游记分享

博客班级 https://edu.cnblogs.com/campus/zjcsxy/SE2020
作业要求 https://edu.cnblogs.com/campus/zjcsxy/SE2020/homework/11334
作业目标 1. 编写一个小程序,可以全新编写,也可以学习别人的小程序进行修改 2. 熟悉git代码管理流程,将源代码上传到到github 3. 在博客园班级中写一篇相应的博文
作业源代码 git@github.com:wfs2018/software-engineering.git
学号 31801131 翁芳胜
院系 浙大城市学院计算分院

项目描述

本项目的灵感来自于小红书和大众点评,年轻人常常在这些平台上发布吃喝玩乐的心得和推荐。假期是时候想出去游玩却难以选择游玩地点。于是想到做一个旅游日记共享平台,可以看他人的游玩经历和心得。从而选择自己喜欢的游玩地点。由于是第一次做小程序,没有相关知识和经验,本项目只完成了首页游记展示,发布,收藏和喜欢的简单前端搭建,后续随着进一步的学习会完善相关功能。

参考:https://github.com/harveyqing/BearDiary.git

项目页面展示







  1. {
  2. "pages": [
  3. "pages/list/list",
  4. "pages/mine/mine",
  5. "pages/new/new",
  6. "pages/entry/entry"
  7. ],
  8. "window": {
  9. "backgroundTextStyle": "light",
  10. "navigationBarBackgroundColor": "#5566aa",
  11. "navigationBarTitleText": "游记分享",
  12. "navigationBarTextStyle": "white",
  13. "backgroundColor": "#eceff4"
  14. },
  15. "tabBar": {
  16. "color": "#858585",
  17. "selectedColor": "#39b5de",
  18. "backgroundColor": "#ffffff",
  19. "borderStyle": "black",
  20. "list": [
  21. {
  22. "pagePath": "pages/list/list",
  23. "iconPath": "images/icons/mark.png",
  24. "selectedIconPath": "images/icons/markHL.png",
  25. "text": "印记"
  26. },
  27. {
  28. "pagePath": "pages/mine/mine",
  29. "iconPath": "images/icons/mine.png",
  30. "selectedIconPath": "images/icons/mineHL.png",
  31. "text": "我的"
  32. }
  33. ]
  34. },
  35. "debug": true,
  36. "sitemapLocation": "sitemap.json"
  37. }

各页面代码

首页

wxml文件

  1. <!-- dairy.wxml -->
  2. <template name="content-item">
  3. <block wx:if="{{content.type == 'TEXT'}}">
  4. <view style="margin-top:30rpx">
  5. <text wx:if="{{content.type == 'TEXT'}}" class="text">{{content.content}}</text>
  6. </view>
  7. </block>
  8. <block wx:if="{{content.type == 'IMAGE'}}">
  9. <image class="media" mode="aspectFill" src="{{content.content}}" bindtap="enterPreviewMode" data-src="{{content.content}}"></image>
  10. <view style="margin-top: 10rpx">{{content.description}}</view>
  11. </block>
  12. <block wx:if="{{content.type == 'VIDEO'}}">
  13. <video class="media" src="{{content.content}}"></video>
  14. <view style="margin-top: 10rpx">{{content.description}}</view>
  15. </block>
  16. <template is="content-footer" data="{{content}}"></template>
  17. </template>
  18. <!-- 正文footer -->
  19. <template name="content-footer">
  20. <view class="footer">
  21. <view class="left">
  22. <image mode="aspectFit" src="../../images/icons/poi.png"></image>
  23. <text style="margin-left:10rpx;">{{content.poi.name}}</text>
  24. </view>
  25. <view class="right">
  26. <image mode="aspectFit" src="../../images/icons/comment.png"></image>
  27. <view>{{content.commentNum}}</view>
  28. </view>
  29. <view class="right">
  30. <image mode="aspectFit" src="../../images/icons/like.png"></image>
  31. <view>{{content.likeNum}}</view>
  32. </view>
  33. </view>
  34. </template>
  35. <view class="container">
  36. <view class="header" style="#ffffff">
  37. <!--顶部固定工具栏-->
  38. <view class="toolbar">
  39. <image class="item" mode="aspectFit" wx:for="{{toolbar}}" src="{{item}}"></image>
  40. </view>
  41. <!--meta信息区-->
  42. <view class="title">
  43. <image class="avatar" mode="aspectFit" src="{{diary.meta.avatar}}"> </image>
  44. <view class="desc">
  45. <view class="item">{{diary.meta.title}}</view>
  46. <view class="item">{{diary.meta.meta}}</view>
  47. </view>
  48. </view>
  49. </view>
  50. <!--正文-->
  51. <view wx:for="{{diary.list}}" wx:for-item="content" class="content">
  52. <template is="content-item" data="{{content}}"></template>
  53. </view>
  54. <view id="footer">
  55. <view class="container">
  56. <view class="item" style="font-size:50rpx;">
  57. <view style="display:inline-block">游记</view>
  58. <view style="display:inline-block;margin-left:10rpx;color:#2EA1CA;">分享</view>
  59. </view>
  60. <view class="item" style="font-size:24rpx;color:gray">分享旅程,分享心情</view>
  61. </view>
  62. </view>
  63. </view>
  64. <!-- 预览模式 -->
  65. <swiper class="swiper-container" duration="400" current="{{previewIndex}}" bindtap="leavePreviewMode" style="display:{{previewMode ? 'block' : 'none'}};">
  66. <block wx:for="{{mediaList}}" wx:for-item="media">
  67. <swiper-item>
  68. <image src="{{media.content}}" mode="aspectFit"></image>
  69. </swiper-item>
  70. </block>
  71. </swiper>

Js文件

  1. // entry.js
  2. const toolbar = [
  3. '../../images/nav/download.png', '../../images/nav/fav.png',
  4. '../../images/nav/share.png', '../../images/nav/comment.png',
  5. ];
  6. const app = getApp();
  7. Page({
  8. data: {
  9. // 当前日志
  10. diary: undefined,
  11. // 右上角工具栏
  12. toolbar: toolbar,
  13. // 图片预览
  14. previewMode: false,
  15. // 当前预览
  16. previewIndex: 0,
  17. // 内容列表
  18. mediaList: [],
  19. },
  20. // 加载日记
  21. getDiary(params) {
  22. console.log("Loading diary data...", params);
  23. var id = params["id"], diary;
  24. app.getDiaryList(list => {
  25. if (typeof id === 'undefined') {
  26. diary = list[0];
  27. } else {
  28. diary = list[id];
  29. }
  30. });
  31. this.setData({
  32. diary: diary,
  33. });
  34. },
  35. // 过滤出预览图片列表
  36. getMediaList() {
  37. if (typeof this.data.diary !== 'undefined' &&
  38. this.data.diary.list.length) {
  39. this.setData({
  40. mediaList: this.data.diary.list.filter(
  41. content => content.type === 'IMAGE'),
  42. })
  43. }
  44. },
  45. // 进入预览
  46. enterPreviewMode(event) {
  47. let url = event.target.dataset.src;
  48. let urls = this.data.mediaList.map(media => media.content);
  49. let previewIndex = urls.indexOf(url);
  50. this.setData({previewMode: true, previewIndex});
  51. },
  52. // 退出预览
  53. leavePreviewMode() {
  54. this.setData({previewMode: false, previewIndex: 0});
  55. },
  56. onLoad: function(params) {
  57. this.getDiary(params);
  58. this.getMediaList();
  59. },
  60. onHide: function() {
  61. },
  62. })

我的页面

Wxml文件

  1. <!--mine.wxml-->
  2. <template name="tab1">
  3. <view>
  4. </view>
  5. </template>
  6. <template name="tab2">
  7. <view>
  8. </view>
  9. </template>
  10. <template name="tab3">
  11. <view>
  12. </view>
  13. </template>
  14. <template name="tab4">
  15. <view>
  16. </view>
  17. </template>
  18. <view>
  19. <!--全屏对话框-->
  20. <view class="modal" style="{{modalShowStyle}}">
  21. <view class="dialog">
  22. <view class="modal-item" style="display:flex;justify-content:center;align-items:center;">
  23. 请输入日记标题
  24. </view>
  25. <view class="modal-item" style="margin:0 auto;width:90%;">
  26. <input type="text" bindinput="titleInput" style="background-color:white;border-radius:2px;" value="{{diaryTitle}}" placeholder="请输入日记标题"></input>
  27. </view>
  28. <view class="modal-button" style="width:100%">
  29. <view style="color:green;border-right:1px solid #E5E7ED;" bindtap="touchAddNew">确定</view>
  30. <view bindtap="touchCancel">取消</view>
  31. </view>
  32. </view>
  33. </view>
  34. <view class="header">
  35. <view class="profile">
  36. <image class="avatar" mode="aspectFit" src="{{userInfo.avatar}}"></image>
  37. <view class="description">
  38. <view class="item">
  39. <view style="margin-right:5px">{{userInfo.nickname}}</view>
  40. <view>{{userInfo.sex}}</view>
  41. </view>
  42. <view class="item">{{userInfo.meta}}</view>
  43. </view>
  44. <image class="add" mode="aspectFill" src="../../images/icons/add.png" bindtap="touchAdd"></image>
  45. </view>
  46. <view class="tablist">
  47. <view wx:for="{{tabs}}" wx:for-index="idx" class="tab" bindtap="touchTab" style="{{item.extraStyle}}" id="{{idx}}">
  48. <view class="content" style="color:{{highLightIndex == idx ? '#54BFE2' : ''}};">
  49. <image class="image" mode="aspectFit" src="{{highLightIndex == idx ? item.iconActive : item.icon}}"></image>
  50. <view style="margin-top:2px;">{{item.title}}</view>
  51. </view>
  52. </view>
  53. </view>
  54. </view>
  55. <template is="{{currentTab}}"></template>
  56. </view>

Js

  1. // mine.js
  2. var iconPath = "../../images/icons/"
  3. var tabs = [
  4. {
  5. "icon": iconPath + "mark.png",
  6. "iconActive": iconPath + "markHL.png",
  7. "title": "日记",
  8. "extraStyle": "",
  9. },
  10. {
  11. "icon": iconPath + "collect.png",
  12. "iconActive": iconPath + "collectHL.png",
  13. "title": "收藏",
  14. "extraStyle": "",
  15. },
  16. {
  17. "icon": iconPath + "like.png",
  18. "iconActive": iconPath + "likeHL.png",
  19. "title": "喜欢",
  20. "extraStyle": "",
  21. },
  22. {
  23. "icon": iconPath + "more.png",
  24. "iconActive": iconPath + "moreHL.png",
  25. "title": "更多",
  26. "extraStyle": "border:none;",
  27. },
  28. ]
  29. var userInfo = {
  30. avatar: "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3049066004,1582117064&fm=26&gp=0.jpg",
  31. nickname: "wfs",
  32. sex: "♂", // 0, male; 1, female
  33. meta: '10篇日记',
  34. }
  35. Page({
  36. // data
  37. data: {
  38. // 展示的tab标签
  39. tabs: tabs,
  40. // 当前选中的标签
  41. currentTab: "tab1",
  42. // 高亮的标签索引
  43. highLightIndex: "0",
  44. // 模态对话框样式
  45. modalShowStyle: "",
  46. // 待新建的日记标题
  47. diaryTitle: "",
  48. // TODO 用户信息
  49. userInfo: userInfo,
  50. },
  51. // 隐藏模态框
  52. hideModal() {
  53. this.setData({modalShowStyle: ""});
  54. },
  55. // 清除日记标题
  56. clearTitle() {
  57. this.setData({diaryTitle: ""});
  58. },
  59. onShow: function() {
  60. this.hideModal();
  61. this.clearTitle();
  62. },
  63. // 点击tab项事件
  64. touchTab: function(event){
  65. var tabIndex = parseInt(event.currentTarget.id);
  66. var template = "tab" + (tabIndex + 1).toString();
  67. this.setData({
  68. currentTab: template,
  69. highLightIndex: tabIndex.toString()
  70. }
  71. );
  72. },
  73. // 新建日记事件
  74. touchAdd: function (event) {
  75. this.setData({
  76. modalShowStyle: "opacity:1;pointer-events:auto;"
  77. })
  78. },
  79. // 新建日记
  80. touchAddNew: function(event) {
  81. this.hideModal();
  82. wx.navigateTo({
  83. url: "../new/new?title=" + this.data.diaryTitle,
  84. });
  85. },
  86. // 取消标题输入
  87. touchCancel: function(event) {
  88. this.hideModal();
  89. this.clearTitle();
  90. },
  91. // 标题输入事件
  92. titleInput: function(event) {
  93. this.setData({
  94. diaryTitle: event.detail.value,
  95. })
  96. }
  97. })

新建日记页面

  1. <!--new.wxml-->
  2. <template name="common">
  3. <scroll-view class="container" scroll-y="true">
  4. <view class="common-container">
  5. <view class="item-group" wx:for="{{layoutList}}" wx:for-item="group">
  6. <block wx:for="{{group}}" wx:for-item="item">
  7. <block wx:if="{{item.type == 'TEXT'}}">
  8. <view class="album-item content-text">
  9. <view>{{item.content}}</view>
  10. </view>
  11. </block>
  12. <block wx:elif="{{item.type == 'IMAGE'}}">
  13. <image src="{{item.content}}" class="album-item" mode="aspectFill"></image>
  14. </block>
  15. <block wx:elif="{{item.type == 'VIDEO'}}">
  16. <video class="album-item" src="{{item.content}}"></video>
  17. </block>
  18. </block>
  19. </view>
  20. </view>
  21. </scroll-view>
  22. <view class="tabbar" style="display:{{showTab ? 'flex' : 'none'}};">
  23. <view class="item" bindtap="inputTouch">
  24. <image class="icon" mode="aspectFit" src="../../images/tabbar/text.png"></image>
  25. </view>
  26. <view class="item" bindtap="mediaTouch">
  27. <image class="icon" mode="aspectFit" src="../../images/tabbar/image.png"></image>
  28. </view>
  29. <view class="item">
  30. <image class="icon" mode="aspectFit" src="../../images/tabbar/more.png"></image>
  31. </view>
  32. </view>
  33. <action-sheet hidden="{{mediaActionSheetHidden}}" bindchange="mediaActionSheetChange">
  34. <block wx:for-items="{{mediaActionSheetItems}}" wx:for-index="id">
  35. <action-sheet-item class="action-item" bindtap="{{mediaActionSheetBinds[id]}}">
  36. {{item}}
  37. </action-sheet-item>
  38. </block>
  39. <action-sheet-cancel class='action-cacel'>取消</action-sheet-cancel>
  40. </action-sheet>
  41. </template>
  42. <template name="inputText">
  43. <view class="input-container">
  44. <view style="height:47rpx" wx:for="{{inputStatus.lines}}" wx:for-index="idx">
  45. <input type="text" data-index="{{idx}}" placeholder="" bindinput="textInput" bindchange="textInputChange" value="{{item}}" auto-focus="{{idx == inputStatus.row ? true : false}}" bindfocus="focusInput"/>
  46. </view>
  47. </view>
  48. <view class="tabbar">
  49. <view class="item" style="width:50%" bindtap="inputCancel">
  50. <image class="icon" mode="aspectFit" src="../../images/tabbar/cancel.png"></image>
  51. </view>
  52. <view class="item" style="width:50%" bindtap="inputDone">
  53. <image class="icon" mode="aspectFit" src="../../images/tabbar/ok.png"></image>
  54. </view>
  55. </view>
  56. </template>
  57. <view style="width:100%;height:100%">
  58. <block wx:if="{{showMode == 'common'}}">
  59. <template is="{{showMode}}" data="{{showTab: showTab, mediaActionSheetHidden: mediaActionSheetHidden, mediaActionSheetItems: mediaActionSheetItems, mediaActionSheetBinds: mediaActionSheetBinds, layoutList: layoutList}}"></template>
  60. </block>
  61. <block wx:if="{{showMode == 'inputText'}}">
  62. <template is="{{showMode}}" data="{{inputStatus}}"></template>
  63. </block>
  64. <loading hidden="{{!showLoading}}" bindchange="hideLoading">
  65. {{loadingMessage}}
  66. </loading>
  67. </view>

Js

  1. // new.js
  2. // TODO 并不是所有非中文字符宽度都为中文字符宽度一半,需特殊处理
  3. // TODO 由于文本框聚焦存在bug,故编辑模式待实现
  4. const input = require('../../utils/input');
  5. const config = require('../../config');
  6. const geo = require('../../services/geo');
  7. const util = require('../../utils/util');
  8. const RESOLUTION = 750; // 微信规定屏幕宽度为750rpx
  9. const MARGIN = 10; // 写字面板左右margin
  10. const ROW_CHARS = Math.floor((RESOLUTION - 2 * MARGIN) / config.input.charWidth);
  11. const MAX_CHAR = 1000; // 最多输1000字符
  12. // 内容布局
  13. const layoutColumnSize = 3;
  14. // 日记内容类型
  15. const TEXT = 'TEXT';
  16. const IMAGE = 'IMAGE';
  17. const VIDEO = 'VIDEO';
  18. const mediaActionSheetItems = ['拍照', '选择照片', '选择视频'];
  19. const mediaActionSheetBinds = ['chooseImage', 'chooseImage', 'chooseVideo'];
  20. var app = getApp();
  21. Page({
  22. data: {
  23. // 日记对象
  24. diary: {
  25. meta: {},
  26. list: [],
  27. },
  28. // 日记内容布局列表(2x2矩阵)
  29. layoutList: [],
  30. // 是否显示loading
  31. showLoading: false,
  32. // loading提示语
  33. loadingMessage: '',
  34. // 页面所处模式
  35. showMode: 'common',
  36. // 输入框状态对象
  37. inputStatus: {
  38. row: 0,
  39. column: 0,
  40. lines: [''],
  41. mode: 'INPUT',
  42. auto: false, // 是否有自动换行
  43. },
  44. // 当前位置信息
  45. poi: null,
  46. // 点击`图片`tab的action-sheet
  47. mediaActionSheetHidden: true,
  48. // 多媒体文件插入action-sheet
  49. mediaActionSheetItems: mediaActionSheetItems,
  50. // 多媒体文件插入项点击事件
  51. mediaActionSheetBinds: mediaActionSheetBinds,
  52. // 是否显示底部tab栏
  53. showTab: true,
  54. },
  55. // 显示底部tab
  56. showTab() {
  57. this.setData({showTab: true});
  58. },
  59. // 隐藏底部tab
  60. hideTab() {
  61. this.setData({showTab: false});
  62. },
  63. // 显示loading提示
  64. showLoading(loadingMessage) {
  65. this.setData({showLoading: true, loadingMessage});
  66. },
  67. // 隐藏loading提示
  68. hideLoading() {
  69. this.setData({showLoading: false, loadingMessage: ''});
  70. },
  71. // 数据初始化
  72. init() {
  73. this.getPoi();
  74. this.setMeta();
  75. },
  76. // 设置日记数据
  77. setDiary(diary) {
  78. let layout = util.listToMatrix(diary.list, layoutColumnSize);
  79. this.setData({diary: diary, layoutList: layout});
  80. this.saveDiary(diary);
  81. },
  82. // 保存日记
  83. // TODO sync to server
  84. saveDiary(diary) {
  85. const key = config.storage.diaryListKey;
  86. app.getLocalDiaries(diaries => {
  87. diaries[diary.meta.title] = diary;
  88. wx.setStorage({key: key, data: diaries});
  89. })
  90. },
  91. // 页面初始化
  92. onLoad: function(options) {
  93. if (options) {
  94. let title = options.title;
  95. if (title) {this.setData({
  96. 'diary.meta.title': title,
  97. 'diary.meta.create_time': util.formatTime(new Date()),
  98. 'diary.meta.cover': ''
  99. });}
  100. }
  101. this.init();
  102. },
  103. // 页面渲染完成
  104. onReady: function(){
  105. wx.setNavigationBarTitle({title: '编辑日记'});
  106. },
  107. onShow:function(){
  108. // 页面显示
  109. },
  110. onHide:function(){
  111. // 页面隐藏
  112. },
  113. onUnload:function(){
  114. // 页面关闭
  115. console.log('页面跳转中...');
  116. },
  117. // 清除正在输入文本
  118. clearInput() {
  119. this.setData({inputStatus: {
  120. row: 0,
  121. common: 0,
  122. lines: [''],
  123. mode: 'INPUT',
  124. auto: false,
  125. }});
  126. },
  127. // 结束文本输入
  128. inputDone() {
  129. let text = this.data.inputStatus.lines.join('\n');
  130. let diary = this.data.diary;
  131. if (text) {
  132. diary.list.push(this.makeContent(TEXT, text, ''));
  133. this.setDiary(diary);
  134. }
  135. this.inputCancel();
  136. },
  137. // 进入文本编辑模式
  138. inputTouch(event) {
  139. this.setData({showMode: 'inputText'});
  140. },
  141. // 取消文本编辑
  142. inputCancel() {
  143. this.setData({showMode: 'common'});
  144. this.clearInput();
  145. },
  146. // 文本输入
  147. textInput(event) {
  148. console.log(event);
  149. let context = event.detail;
  150. // 输入模式
  151. if (this.data.inputStatus.mode === 'INPUT') {
  152. if (context.value.length != context.cursor) {
  153. console.log('用户输入中...');
  154. } else {
  155. let text = context.value;
  156. let len = input.strlen(text);
  157. let lines = this.data.inputStatus.lines;
  158. let row = this.data.inputStatus.row;
  159. let [extra, extra_index] = [[['']], 0];
  160. let hasNewLine = false;
  161. console.log('当前文本长度: ' + len);
  162. // 当前输入长度超过规定长度
  163. if (len >= ROW_CHARS) {
  164. // TODO 此处方案不完善
  165. // 一次输入最好不超过两行
  166. hasNewLine = true;
  167. while (input.strlen(text) > ROW_CHARS) {
  168. let last = text[text.length - 1];
  169. if (input.strlen(extra[extra_index] + last) > ROW_CHARS) {
  170. extra_index += 1;
  171. extra[extra_index] = [''];
  172. }
  173. extra[extra_index].unshift(last);
  174. text = text.slice(0, -1);
  175. }
  176. }
  177. lines[lines.length - 1] = text;
  178. if (hasNewLine) {
  179. extra.reverse().forEach((element, index, array) => {
  180. lines.push(element.join(''));
  181. row += 1;
  182. });
  183. }
  184. let inputStatus = {
  185. lines: lines,
  186. row: row,
  187. mode: 'INPUT',
  188. auto: true, // // 自动换行的则处于输入模式
  189. };
  190. 列表
  191. wxml
  192. <scroll-view scroll-y="true">
  193. <view wx:for="{{diaries}}" wx:for-index="idx" class="item-container" bindtap="showDetail" id="{{idx}}">
  194. <image mode="aspectFit" src="{{item.meta.cover}}" class="cover"></image>
  195. <view class="desc">
  196. <view class="left">
  197. <view style="font-size:32rpx;margin:10rpx 0;">{{item.meta.title}}</view>
  198. <view style="font-size:24rpx;color:darkgray">{{item.meta.meta}}</view>
  199. </view>
  200. <view class="right">
  201. <image mode="aspectFit" src="{{item.meta.avatar}}"></image>
  202. <text style="font-size:24rpx;margin-top:10rpx;color:darkgray">{{item.meta.nickName}}</text>
  203. </view>
  204. </view>
  205. </view>
  206. </scroll-view>

JS

  1. const config = require("../../config");
  2. var app = getApp();
  3. Page({
  4. data: {
  5. // 日记列表
  6. // TODO 从server端拉取
  7. diaries: null,
  8. // 是否显示loading
  9. showLoading: false,
  10. // loading提示语
  11. loadingMessage: '',
  12. },
  13. /**
  14. * 生命周期函数--监听页面加载
  15. */
  16. onLoad() {
  17. this.getDiaries();
  18. },
  19. /**
  20. * 获取日记列表
  21. */
  22. getDiaries() {
  23. var that = this;
  24. app.getDiaryList(list => {
  25. that.setData({diaries: list});
  26. })
  27. },
  28. // 查看详情
  29. showDetail(event) {
  30. wx.navigateTo({
  31. url: '../entry/entry?id=' + event.currentTarget.id,
  32. });
  33. }
  34. })

总结

这是第一次编写小程序,刚刚听到作业的时候很震惊一周要做一个小程序。从头开始学习html,css知识的同时,去参考完整的demo。一句一句的理解,调试。几天下来对小程序的结构有了了解。在做小程序的时候,也遇到了一些困难,在搜素引擎和同学们的帮助下也都解决了。虽然最后做的很粗糙,但是在这个过程中,基本上完成了小程序的入门,也知道了怎么去解决遇到的问题。这次的作业也让我明白,在开发方面还有很多需要学习的知识。需要更加努力

微信小程序-游记分享(无后台)的更多相关文章

  1. mpvue开发微信小程序,分享按钮报错:`Cannot read property 'apply' of null`

    用mpvue开发微信小程序,分享按钮报错:Cannot read property 'apply' of null onShareAppMessage 是于微信小程序Pages的生命周期钩子,顾这个方 ...

  2. 微信小程序绘制分享图

    微信小程序绘制分享图例子: demo下载地址:https://gitee.com/v-Xie/wxCanvasShar 大致代码会再以下说明 实际开发项目: 基础知识点: 了解canvas基础知识 w ...

  3. (一)校园信息通微信小程序从前端到后台整和笔记

    前段时间接触了微信小程序,现在回过头来做一些笔记. 先上效果图 后台数据管理界面(PHP) 校园信息通微信小程序前端界面 下面先简单的说一下怎样部署一个微信小程序 首先是前端 微信小程序有它专门的开发 ...

  4. 微信小程序-实现分享(带参数)

    微信小程序分享功能的实现方法有两种: 第一种 在page.js中实现onShareAppMessage,便可在小程序右上角选择分享该页面 onShareAppMessage: function () ...

  5. (一)微信小程序之模拟调用后台接口踩过的坑

    如下图标记的三个点 在调试过程中出现问题,特此记录. 1. 之前在浏览器测试接口习惯省略 http:// ,是因为浏览器默认有一个检测,在你输入的网址前面加http://,如果有就不加. 然而在微信小 ...

  6. 微信小程序,请求php后台返回json数据多出隐藏字符问题

    这几天在做一个微信小程序注册登录页面的时候碰到一个问题,就是使用wx.request api的时候success中返回的JSON数据前面会多出空白字符,后面网上查了一下是说php bom头问题(详细介 ...

  7. 微信小程序商城 带java后台源码

    微信小程序商城(Java版) 演示地址 账号:admin 密码:admin 小程序体验码: 技术选型 1 后端使用技术 1.1 springframework4.3.7.RELEASE 1.2 myb ...

  8. 微信小程序全局设置分享内容

    微信小程序每个页面都可以在onShareAppMessage中设置分享内容,如果想要全局设置成一样的分享内容如何设置呢? 在app.js中新增以下方法: //重写分享方法 overShare: fun ...

  9. 微信小程序之分享功能

    说到分享 大家都会想到手机右上角点击不就分享了么?对的没错,那样是分享转发的是小程序  而不是指定的某个页面,所以自己动手丰衣足食,自己写一个转发功能被, 其实也没那么可怕,主要参考的是微信小程序AP ...

随机推荐

  1. Python-变量、变量作用域、垃圾回收机制原理-global nonlocal

    变量实现原理决定了Python使用的垃圾回收机制为变量引用计数,当这个对象引用计数为0时候,则会自动执行__del__函数回收资源, del方法只是把变量指向的对象引用计数减一而已并删除这个变量 表达 ...

  2. spring-boot-route(二)读取配置文件的几种方式

    Spring Boot提供了两种格式的配置文件,分别是properties 和 yml.Spring Boot最大的特点就是自动化配置,如果我们想修改自动化配置的默认值,就可以通过配置文件来指定自己服 ...

  3. CF538B Quasi Binary 思维题

    题目描述 给出一个数 \(n\),你需要将 \(n\) 写成若干个数的和,其中每个数的十进制表示中仅包含\(0\)和\(1\). 问最少需要多少个数 输入输出格式 输入格式: 一行 一个数 \(n(1 ...

  4. 在 Visual Studio 中创建一个简单的 C# 控制台应用程序

    转载:https://blog.csdn.net/qq_43994242/article/details/87260824 快速入门:使用 Visual Studio 创建第一个 C# 控制台应用 h ...

  5. Python 中 pip 工具的安装与使用

    pip 是 Python 包管理工具,该工具提供了对Python 包的查找.下载.安装.卸载的功能. 目前如果你在 python.org 下载最新版本的安装包,则是已经自带了该工具. Python 2 ...

  6. 多测师讲解自动化 _rf自动化需要总结的问题(2)_高级讲师肖sir

    1.口述整个自动化环境搭建的过程.以及环境搭建需要哪些工具包以及对应的工具包的作用?2.RF框架的原理?常见的功能?3.公司自动化测试的流程?1.自动化需求的评审2.自动化场景的选择3.自动化工具的选 ...

  7. Rust之路(4)——所有权

    [未经书面同意,严禁转载] -- 2020-10-14 -- 所有权是Rust的重中之重(这口气咋像高中数学老师 WTF......). 所有权是指的对内存实际存储的数据的访问权(包括读取和修改),在 ...

  8. 三门峡6378.7939(薇)xiaojie:三门峡哪里有xiaomei

    三门峡哪里有小姐服务大保健[微信:6378.7939倩儿小妹[三门峡叫小姐服务√o服务微信:6378.7939倩儿小妹[三门峡叫小姐服务][十微信:6378.7939倩儿小妹][三门峡叫小姐包夜服务] ...

  9. Android HandlerThread 详解

    概述 HandlerThread 相信大家都比较熟悉了,从名字上看是一个带有 Handler 消息循环机制的一个线程,比一般的线程多了消息循环的机制,可以说是Handler + Thread 的结合, ...

  10. xuexi

    1.内存的编址方法就是内存地址与内存单元格一一对应且永久绑定.计算机的cpu只认识内存地址,不关心内存单元格的位置和内容.通过硬件的设计来达到通过内存地址找到内存单元格. 2.内存的编址是以字节为单位 ...