当前位置:   article > 正文

UNIAPP&小程序从入门到精通_observers lifetimes uniapp

observers lifetimes uniapp

第一章=>
1、如何创建项目               
2、项目的基本结构             
3、页面组成(wxss可以不用)     
4、组件的使用                         
5、协同开发与发布

第二章=>
6、WXML页面结构渲染     
7、style样式美化               
8、app.json全局配置                   
9、page.json页面个性化         
10、发起网络请求

第三章=>
11、本地生活案例             
12、页面间导航跳转           
13、下拉刷新                               
14、上拉加载                           
15、生命周期函数           
16、本地生活案例扩展

第四章=>
17、自定义组件                 
18、behaviors作用           
19、vant-weapp组件库               
20、MobX实现全局数据共享     
21、API实现Promise化 

第五章=>
22、分包                           
23、自定义tabBar             
​​​​​​​24、小程序大项目(uni-app)

****************************************************************************************************************************************************************************

  1. 1、如何创建项目(重新认识下小程序:结构化学习)
  2. 1】概述
  3. 运行环境不同:浏览器 VS 微信环境
  4. ************************************************************************************
  5. API不同:DOM DOM API VS 地理定位+扫码+支付
  6. ************************************************************************************
  7. 开发者模式不同:浏览器+代码编辑器 VS 小程序账号+小程序开发工具+配置项目
  8. 2】第一个小程序
  9. 我的账号已经有了,扫码即可!!!!
  10. ************************************************************************************
  11. https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
  12. 下载与安装开发工具(推荐稳定版)
  13. ************************************************************************************
  14. https://mp.weixin.qq.com/wxamp/devprofile/get_profile?token=692889462&lang=zh_CN
  15. 登录获取AppID,在管理后台-开发管理-开发设置里
  16. ************************************************************************************
  17. 扫码登录微信小程序即可
  18. ************************************************************************************
  19. 设置-外观设置-可以设置颜色 字号18 行距12号。
  20. @代理设置为不使用任何代理
  21. ************************************************************************************
  22. 新建程序页面,注意几个细节点:
  23. 目录指定:放到E 项目 WXL/LittlePro
  24. 不使用云服务,语言使用JS(别搞错了!!!!!!!!!)
  25. ************************************************************************************
  26. 查看项目效果:可以点击编译按钮(刷到最新,模拟器展示:用的最多)
  27. 手机上看:项目上的预览按钮,弹出二维码扫下就行了,真机预览
  28. ************************************************************************************
  29. 帮助!!!!!!!!!!!!!的使用 (P403 10分钟)
  30. 区域功能概述(使用iPhone 6 7 8
  31. ************************************************************************************
  32. 代码编辑器、调试功能区域、主要使用Console控制台打印看内容!!!

****************************************************************************************************************************************************************************

  1. 2、项目的基本结构
  2. 1】代码构成
  3. pages用来存放所有小程序的页面
  4. ************************************************************************************
  5. utils用于存放工具类的
  6. ************************************************************************************
  7. app.js(入口) / app.json(全局配置) / app.wxss(全局样式文件)
  8. ************************************************************************************
  9. project.config.json项目配置文件
  10. ************************************************************************************
  11. sitemap.json用来配置小程序及其页面是否允许被微信索引
  12. ************************************************************************************
  13. @小程序页面重点概述
  14. indexindex.js函数 index.json配置 index.wxml页面结构 index.wxss页面样式 】
  15. index.wxss可以用style代替的!!!!!!!!!!!!!!
  16. ************************************************************************************
  17. json配置文件的作用:app.json(全局配置) project.config.json sitemap.json
  18. 每个页面xxx.json
  19. ************************************************************************************
  20. app.json:全局配置。
  21. {
  22. "pages":[ // 有几个页面
  23. "pages/index/index",
  24. "pages/logs/logs"
  25. ],
  26. "window":{ // 窗口颜色
  27. "backgroundTextStyle":"light",
  28. "navigationBarBackgroundColor": "#fff",
  29. "navigationBarTitleText": "Weixin",
  30. "navigationBarTextStyle":"black"
  31. },
  32. "style": "v2", // 全局定义小程序所有页面背景色、文字颜色 可以删除或保留
  33. "sitemapLocation": "sitemap.json"
  34. }
  35. ************************************************************************************
  36. project.config.json:项目配置
  37. {
  38. "description": "项目配置文件",
  39. "packOptions": {
  40. "ignore": [],
  41. "include": []
  42. },
  43. "setting": { // 开发者工具的配置记录 在开发工具里可以配置
  44. "bundle": false,
  45. "userConfirmedBundleSwitch": false,
  46. "urlCheck": true,
  47. "scopeDataCheck": false,
  48. "coverView": true,
  49. "es6": true,
  50. "postcss": true,
  51. "compileHotReLoad": false,
  52. "lazyloadPlaceholderEnable": false,
  53. "preloadBackgroundData": false,
  54. "minified": true,
  55. "autoAudits": false,
  56. "newFeature": false,
  57. "uglifyFileName": false,
  58. "uploadWithSourceMap": true,
  59. "useIsolateContext": true,
  60. "nodeModules": false,
  61. "enhance": true,
  62. "useMultiFrameRuntime": true,
  63. "useApiHook": true,
  64. "useApiHostProcess": true,
  65. "showShadowRootInWxmlPanel": true,
  66. "packNpmManually": false,
  67. "enableEngineNative": false,
  68. "packNpmRelationList": [],
  69. "minifyWXSS": true,
  70. "showES6CompileOption": false,
  71. "minifyWXML": true,
  72. "babelSetting": {
  73. "ignore": [],
  74. "disablePlugins": [],
  75. "outputPath": ""
  76. }
  77. },
  78. "compileType": "miniprogram",
  79. "libVersion": "2.19.4",
  80. "appid": "wx775c2214e34aa966", // 小程序的appid 可以修改
  81. "projectname": "miniprogram-92", // 这个项目不等于小程序名称!!!!!
  82. "condition": {},
  83. "editorSetting": {
  84. "tabIndent": "insertSpaces",
  85. "tabSize": 2
  86. }
  87. }
  88. ************************************************************************************
  89. sitemap.json
  90. 小程序内搜索,效果类似于PC网页的SEO。
  91. {
  92. "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
  93. "rules": [{
  94. "action": "allow", // 允许被微信索引 disallow 是不允许被索引
  95. "page": "*" // 所有页面
  96. }]
  97. }
  98. ************************************************************************************
  99. 页面的.json配置文件(个性化配置会覆盖全局json配置)
  100. {
  101. "pages":[
  102. "pages/index/index",
  103. "pages/logs/logs"
  104. ],
  105. "window":{
  106. "backgroundTextStyle":"light",
  107. "navigationBarBackgroundColor": "#fff", // 全局是白色
  108. "navigationBarTitleText": "Weixin",
  109. "navigationBarTextStyle":"black"
  110. },
  111. "style": "v2",
  112. "sitemapLocation": "sitemap.json"
  113. }
  114. ****************
  115. {
  116. "usingComponents": {},
  117. "navigationBarBackgroundColor":"#00B26A" // 局部是绿色,最终显示是绿色
  118. }

****************************************************************************************************************************************************************************

  1. 3、页面组成(wxss可以不用)
  2. 1】如何新建小程序页面
  3. {
  4. "pages":[
  5. "pages/index/index",
  6. "pages/list/list", // !!!!!!!!!!!!!!操作这个即可
  7. "pages/logs/logs"
  8. ],
  9. "window":{
  10. "backgroundTextStyle":"light",
  11. "navigationBarBackgroundColor": "#fff",
  12. "navigationBarTitleText": "Weixin",
  13. "navigationBarTextStyle":"black"
  14. },
  15. "style": "v2",
  16. "sitemapLocation": "sitemap.json"
  17. }
  18. ************************************************************************************
  19. 修改项目首页:
  20. "pages":[
  21. "pages/list/list", // 这里
  22. "pages/index/index",
  23. "pages/logs/logs"
  24. ],
  25. 2】WXML和HTML区别:
  26. 标签名称不同、属性节点不同、提供了类似于VUE中的模板语法!!!!!
  27. HTML( div span img a)
  28. WXML(view text image navigator)
  29. ************************************************************************************
  30. 属性节点不同
  31. <a herf="#">百度</a>
  32. <navigator url="/pages/index/index">主页</navigator>
  33. ************************************************************************************
  34. 提供数据绑定、列表渲染、条件渲染和VUE一样!!!!!!!!!!!!
  35. ************************************************************************************
  36. WXSS与CSS
  37. 区别:新增了rpx尺寸单位、提供全局样式和局部样式、wxss仅支持部分css选择器
  38. ************************************************************************************
  39. app.wxss全局样式表。xx页面.wxss局部样式
  40. ************************************************************************************
  41. wxss仅支持部分css选择器:比如id选择器,类选择器,元素选择器
  42. 3】具体文件配置
  43. .js文件:点击、获取用户位置
  44. app.js 整个小程序的入口文件,通过App()函数来启动整个小程序。
  45. xx页面.js通过调用Page()函数来创建并运行页面。
  46. 普通的.js文件,用来封装工具类或者公共属性供项目使用。
  47. 4】宿主环境
  48. 小程序运行所必须依赖的环境。就是手机微信!!!!!没有微信,就没有小程序
  49. ************************************************************************************
  50. 小程序宿主环境提供的支持:通行模型、运行机制、组件、API
  51. ************************************************************************************
  52. 通信的主体:渲染层WXML WXSS、逻辑层JS。
  53. ************************************************************************************
  54. 通信模型:渲染层WXML与逻辑层JS通信(微信客户端)。逻辑层JS与三方服务API器之间的通信(微信客户端)。
  55. ************************************************************************************
  56. 运行机制:
  57. 小程序启动过程:小程序代码包下载到本地--->解析app.json全局配置文件--->执行app.js入口文件调用App()
  58. --->渲染首页、小程序启动完成。
  59. 页面渲染过程:.json--->wxml/wxss---->.js调用Page()函数--->页面渲染完成。

****************************************************************************************************************************************************************************

  1. 4、组件的使用
  2. 1】组件的分类:
  3. 视图容器(view scroll-view swiper swiper-item)、基础内容、表单组件、导航组件!!!!
  4. +媒体组件、map地图组件、canvas画布组件、开放能力、无障碍方向。
  5. 2】view的使用
  6. <!-- 分割线,这是下面的内容... 我先都用style写,快速上手目的是-->
  7. <view style="display: flex;justify-content: space-around;">
  8. <view style="width: 100px;height: 100px;text-align: center;line-height: 100px;background-color: lightgreen;">1</view>
  9. <view style="width: 100px;height: 100px;text-align: center;line-height: 100px;background-color: lightskyblue;">2</view>
  10. <view style="width: 100px;height: 100px;text-align: center;line-height: 100px;background-color: lightcoral;">3</view>
  11. </view>
  12. 3】scroll-view的使用:height: 120px;" scroll-y
  13. <!-- 分割线,这是下面的内容... -->
  14. <scroll-view style="display: flex;justify-content: space-around;height: 120px;" scroll-y>
  15. <view style="width: 100px;height: 100px;text-align: center;line-height: 100px;background-color: lightgreen;">1</view>
  16. <view style="width: 100px;height: 100px;text-align: center;line-height: 100px;background-color: lightskyblue;">2</view>
  17. <view style="width: 100px;height: 100px;text-align: center;line-height: 100px;background-color: lightcoral;">3</view>
  18. </scroll-view>
  19. 【4】轮播图样式实现:swiper和swiper-item组件的基本使用。用style真是真清晰,上手块,牛批呀
  20. <!-- 分割线,这是下面的内容... -->
  21. <swiper style="height: 150px;" indicator-dots>
  22. <swiper-item>
  23. <view style="height:100%;line-height: 150px;text-align: center;background-color: green;">A</view>
  24. </swiper-item>
  25. <swiper-item>
  26. <view style="height:100%;line-height: 150px;text-align: center;background-color: yellow;">B</view>
  27. </swiper-item>
  28. <swiper-item>
  29. <view style="height: 100%;line-height: 150px;text-align: center;background-color: blue;">C</view>
  30. </swiper-item>
  31. </swiper>
  32. 【5】其他自定义属性:
  33. indicator-dots是否展示小圆点
  34. <swiper style="height: 150px;" indicator-dots indicator-color="white" indicator-active-color="red"
  35. autoplay interval="2000" circular>
  36. ************************************************************************************
  37. 基础内容组件text 、rich-text
  38. text支持长按选中
  39. <view>
  40. 长按选中
  41. <text selectable> // !!!!!!!!!!!!!!!!!!
  42. 1592129198
  43. </text>
  44. </view>
  45. ************************************************************************************
  46. rich-text,感觉用的不多吧!!!!!!!!!!!!!!!!!!!!!
  47. <view>
  48. <rich-text nodes="<h1 style='color:red'>示例</h1>">
  49. </rich-text>
  50. </view>
  51. 【6】其他常用组件
  52. button
  53. <!-- 分割线,这是下面的内容...和VUE好像 -->
  54. <button>默认按钮</button>
  55. <button type="primary">主要按钮</button>
  56. <button type="warn">主要按钮</button>
  57. <button type="primary" size="mini">主要小按钮</button>
  58. <button type="primary" plain="true">主要镂空按钮</button>
  59. ************************************************************************************
  60. image使用(同时优化了自己的服务器,作为图片上传与预览的功能,牛批)
  61. <!-- 分割线,这是下面的内容...和VUE好像 -->
  62. <image src="https://wdfgdzx.top/document/pre_see/f75ffca9d133429c97622a5093ff6a80.jpg"></image>
  63. <image src="https://wdfgdzx.top/document/pre_see/f75ffca9d133429c97622a5093ff6a80.jpg" mode="aspectFit"></image>
  64. <image src="https://wdfgdzx.top/document/pre_see/f75ffca9d133429c97622a5093ff6a80.jpg" mode="aspectFill"></image>
  65. <image src="https://wdfgdzx.top/document/pre_see/f75ffca9d133429c97622a5093ff6a80.jpg" mode="widthFix"></image>
  66. <image src="https://wdfgdzx.top/document/pre_see/f75ffca9d133429c97622a5093ff6a80.jpg" mode="heightFix"></image>
  67. ************************************************************************************
  68. 【7】小程序的宿主环境API:事件监听类API、同步API、异步API
  69. 事件监听类API:以on开头,wx.onWindowResize
  70. 同步API:Sync结尾的API wx.setStorageSync("key","value")
  71. 异步API:需要通过success、fail、complete来接收结果的。wx.request()发起网络请求,通过success接收

****************************************************************************************************************************************************************************

  1. 5、协同开发与发布
  2. 1】权限管理需求
  3. 项目权限:管理、产品、设计、开发、测试
  4. 2】成员管理
  5. https://mp.weixin.qq.com/wxamp/user/manage?action=index&use_role=1&token=1582776250&lang=zh_CN
  6. 3】可惜了了,我是全栈,我就是管理员,我什么都需要。哈哈哈
  7. 项目成员、体验成员
  8. 4】小程序成员管理
  9. 开发者权限:对小程序功能进行开发。
  10. 体验者权限:体验小程序
  11. 登录权限:登录小程序后台,无需管理员确认
  12. 开发设置。
  13. 腾讯云管理。
  14. 5】成员的添加
  15. 主要在成员管理操作!!!!!!!!!!!!!!!!!!!
  16. 6】小程序的版本
  17. 开发版本--->体验版本--->审核中的版本--->发布正式版
  18. **************************************************************************************
  19. 上传按钮进行上传。
  20. https://mp.weixin.qq.com/wxamp/wacodepage/getcodepage?token=1582776250&lang=zh_CN
  21. 这里找到开发版本后进行审核!!!!!!!!!!!!!
  22. 7】基于小程序码的推广
  23. https://mp.weixin.qq.com/wxamp/basicprofile/index?token=1582776250&lang=zh_CN
  24. 可以下载对应的小程序码
  25. **************************************************************************************
  26. 查看运营数据:
  27. https://wedata.weixin.qq.com/mp2/basic-data/realtime-data
  28. 点击移动端查看数据--->可以扫描二维码,查看相关数据

****************************************************************************************************************************************************************************

  1. 6、WXML页面结构渲染
  2. 1】数据绑定
  3. data中定义、wxml中使用
  4. ***************************************************************************************
  5. data: {
  6. list: {
  7. name: "默认名称"
  8. }
  9. },
  10. ***************************************************************************************
  11. <text>数据详情:{{list.name}}</text> // 胡子语法
  12. 2】胡子语法使用:内容绑定、绑定属性、三元运算
  13. 绑定属性:和VUE有点不同了
  14. data: {
  15. list: {
  16. name: "默认名称",
  17. src: "https://wdfgdzx.top/document/pre_see/fe78f50f0dee49569735e9c4ab608708.jpg"
  18. }
  19. },
  20. ***************************************************************************************
  21. <image src="{{list.src}}"></image>// 成功调用
  22. <image src="{{list.src}}" mode="widthFix"></image>
  23. ***************************************************************************************
  24. 三元运算:
  25. data: {
  26. list: {
  27. name: "默认名称",
  28. src: "https://wdfgdzx.top/document/pre_see/fe78f50f0dee49569735e9c4ab608708.jpg",
  29. randomNum1: Math.random() * 10
  30. }
  31. },
  32. ***************************************************************************************
  33. <!-- 分割线,这是下面的内容...和VUE好像 -->
  34. <text>数据详情:{{list.name}}{{list.randomNum1}}</text>
  35. <image src="{{list.src}}" mode="widthFix"></image>
  36. <text>\n{{list.randomNum1>=5?'大于等于5':'小于5'}}</text>
  37. 3】算术运算
  38. data: {
  39. list: {
  40. name: "默认名称",
  41. src: "https://wdfgdzx.top/document/pre_see/fe78f50f0dee49569735e9c4ab608708.jpg",
  42. randomNum1: Math.random().toFixed(2) // 生成一个随机的两位小数
  43. }
  44. },
  45. ***************************************************************************************
  46. <text>数据详情:{{list.randomNum1}}----{{list.randomNum1*100}}</text>
  47. 4】事件绑定:tap input change
  48. event:type事件类型、target触发事件的组件、detail额外的信息
  49. ***************************************************************************************
  50. target和currentTarget的区别:
  51. target是触发事件的源头组件,而currentTarget是当前事件所绑定的组件
  52. show() {
  53. wx.showToast({
  54. title: '点击了按钮',
  55. })
  56. },
  57. ***************************************************************************************
  58. <view bindtap="show" style="background-color: aquamarine;"> //currentTarget
  59. <button type="primary">按钮</button> // target
  60. </view>
  61. 5】bindtap的语法格式
  62. <button type="primary" bindtap="show">点击我能响应</button>
  63. ***************************************************************************************
  64. show(e) {
  65. console.log(e)
  66. console.log(e.target)
  67. wx.showToast({
  68. title: '点击了按钮',
  69. })
  70. },
  71. 6】为data中数据赋新值
  72. giveNewVal(e) {
  73. this.setData({
  74. list: {
  75. name: '新值'
  76. }
  77. })
  78. },
  79. ***************************************************************************************
  80. <!-- 分割线,这是下面的内容...和VUE好像 -->
  81. <text>{{list.name}}</text>
  82. <button type="primary" bindtap="giveNewVal">重新赋值</button>
  83. ***************************************************************************************
  84. giveNewVal(e) {
  85. this.setData({
  86. list: {
  87. count: this.data.list.count + 1 // 主要是这里!!!!!!!!!!!!!!!!!!
  88. }
  89. })
  90. },
  91. ***************************************************************************************
  92. <text>{{list.count}}</text>
  93. <button type="primary" bindtap="giveNewVal">重新赋值</button>
  94. 7】事件传参
  95. <button type="primary" bindtap="showVal" data-info="{{'大家好'}}">传参调用</button>
  96. ***************************************************************************************
  97. showVal(e) { // 说明小程序中e很重要的,都能通过它传参了,卧槽 日你大爷
  98. //console.log(e.target.dataset.info)
  99. wx.showToast({
  100. title: e.target.dataset.info,
  101. })
  102. },
  103. ***************************************************************************************
  104. <button type="primary" bindtap="showVal" data-info="{{2}}">传参调用</button>// 传的是数值
  105. <button type="primary" bindtap="showVal" data-info="{{'2'}}">传参调用</button> // 传的是字符串
  106. ***************************************************************************************
  107. 注意:小程序不能直接在括号里传参,日尼玛反人类!!!!!!!!!!!!!!!!
  108. 8】bindinput的语法格式
  109. showVal(e) {
  110. console.log(e.detail.value) // 这里拿到的方式注意!!!!!!!!!
  111. },
  112. ***************************************************************************************
  113. <input bindinput="showVal" style="background-color: aquamarine;border: 1px solid gray;"></input>
  114. 9】实现文本框和data之间的数据同步,太简单了
  115. showVal(e) {
  116. console.log(e.detail.value)
  117. this.setData({
  118. list: {
  119. name: e.detail.value
  120. }
  121. })
  122. },
  123. ***************************************************************************************
  124. <input bindinput="showVal" style="background-color: aquamarine;border: 1px solid gray;"></input>
  125. {{list.name}}
  126. ***************************************************************************************
  127. 不管wxss确实省事很多了,集中精力放在重点的事情上,后面自己一统江山就靠这个了,起飞!!!
  128. 10】条件渲染
  129. data: {
  130. list: {
  131. name: '默认值',
  132. flag: false
  133. }
  134. },
  135. ***************************************************************************************
  136. <text wx:if="{{list.flag}}">true</text>
  137. <text wx:else>false</text>
  138. ***************************************************************************************
  139. 结合<block>使用wx:if,实现整体的显示切换,能够避免在页面渲染不必要的元素。
  140. <block wx:if="{{list.flag}}">
  141. <text>true</text>
  142. <text>\ntrue显示2</text>
  143. </block>
  144. <block wx:else>
  145. <text>false</text>
  146. <text>\nfalse显示2</text>
  147. </block>
  148. 11】hidden的使用
  149. <view hidden="{{list.flag}}">false</view>
  150. <view hidden="{{!list.flag}}">true</view>
  151. 12】wx:if与hidden的比对
  152. wx:if是创建和移出、hidden是加样式。和VUE好像呀!!!!!频繁切换用hidden.....
  153. 13】列表渲染wx:for
  154. data: {
  155. test: {
  156. list: ['陈翔', '球球', '蘑菇头', '米线儿', '闰土']
  157. }
  158. },
  159. ***************************************************************************************
  160. <view wx:for="{{test.list}}">
  161. 索引是:{{index}} 当前项:{{item}}
  162. </view>
  163. ***************************************************************************************
  164. wx:key的使用,可以提高渲染效率
  165. <view wx:for="{{test.list}}" wx:key="index">
  166. 索引是:{{index}} 当前项:{{item}}
  167. </view>
  168. ***************************************************************************************
  169. data: {
  170. test: {
  171. list: [
  172. {id:1,name:'陈翔'},
  173. {id:2,name:'球球'},
  174. {id:3,name:'米线儿'},
  175. ]
  176. }
  177. },
  178. ***************************************************************************************
  179. <view wx:for="{{test.list}}" wx:key="id"> // 数据库查询的基本都有id
  180. 索引是:{{index}} 当前项:{{item.name}}
  181. </view>

****************************************************************************************************************************************************************************

  1. 7、style样式美化
  2. 1】wxss和css的关系
  3. wxss具有大部分css属性,扩展了rpx @import样式导入
  4. *****************************************************************************************
  5. 行了初期,我只用style="xxxx",哈哈哈哈哈!!!!!!!!!!
  6. 2】rpx概述
  7. 屏幕总宽度为750份,小程序会自动把rpx换算成像素单位渲染,从而实现屏幕适配
  8. *****************************************************************************************
  9. rpx与px换算。750rpx=375px=750物理像素,不同的设备还不同,了解即可。
  10. iphone6开发比较合适
  11. 3】样式导入@import
  12. .globalColor {
  13. color: red
  14. }
  15. *****************************************************************************************
  16. /* pages/test/test.wxss */
  17. @import "/common/common.wxss";
  18. *****************************************************************************************
  19. <view wx:for="{{test.list}}" wx:key="id" class="globalColor"> // 名字显示就是红色
  20. {{item.name}}
  21. </view>
  22. *****************************************************************************************
  23. 哪有style来的直接呢?哈哈哈
  24. <view wx:for="{{test.list}}" wx:key="id" style="color: green;">
  25. {{item.name}}
  26. </view>
  27. 4】全局样式与局部样式
  28. /**app.wxss**/ 这是全局样式!!!!!!!!!!!!!!!!
  29. *****************************************************************************************
  30. /* pages/test/test.wxss */ 局部样式,他的配置会覆盖全局样式的配置
  31. *****************************************************************************************
  32. 有这个功夫不如,用style 卧槽,搞的这么复杂。

****************************************************************************************************************************************************************************

  1. 8、app.json全局配置
  2. 1】app.json就是全局配置文件!!!!!!!!!!!!!!!!!!
  3. **********************************************************************************************
  4. @pages 记录当前小程序所有页面的存放路径
  5. @window 全局设置小程序窗口的外观
  6. @设置小程序底部的tabBar效果
  7. @style 是否启用新版组件样式
  8. 2】window常用配置
  9. navigationBar开头的都是配置导航栏效果的
  10. backgroundColor开头的都是配置窗口背景的
  11. 下拉刷新页面效果的选项
  12. **********************************************************************************************
  13. "navigationBarTitleText": "物品回收", 配置标题文本的
  14. **********************************************************************************************
  15. 设置导航栏的背景色
  16. "navigationBarBackgroundColor": "#2b4b6b",
  17. "navigationBarBackgroundColor":"#00B26A"
  18. **********************************************************************************************
  19. 设置标题文字颜色
  20. "navigationBarTextStyle": "white"
  21. **********************************************************************************************
  22. 全局开启下拉刷新功能
  23. "window": {
  24. "backgroundTextStyle": "light",
  25. "navigationBarBackgroundColor": "#2b4b6b",
  26. "navigationBarTitleText": "物品回收",
  27. "navigationBarTextStyle": "white",
  28. "enablePullDownRefresh": true //!!!!!!!!!!!!!!!!!!!这个点!!!!!!
  29. },
  30. 这个下拉刷新,会作用全局所有页面。
  31. 模拟器并不能100%还原真机,发布的时候还是用真机测试下!!!!!!!!!
  32. **********************************************************************************************
  33. "backgroundColor": "#efefef" 配置下拉刷新区域的颜色值。
  34. **********************************************************************************************
  35. 设置下拉刷新时,loading效果
  36. "window": {
  37. "backgroundTextStyle": "dark", // !!!!!!!!!!!!!!!!!!!!!
  38. "navigationBarBackgroundColor": "#2b4b6b",
  39. "navigationBarTitleText": "物品回收",
  40. "navigationBarTextStyle": "white",
  41. "enablePullDownRefresh": true,
  42. "backgroundColor": "#efefef"
  43. },
  44. **********************************************************************************************
  45. 设置上拉触底的距离:上拉滑动操作,来加载更多数据的问题。
  46. onReachBottomDistance 默认是50px加载下一页,如果希望改变。不建议改,50px即可
  47. "window": {
  48. "backgroundTextStyle": "dark",
  49. "navigationBarBackgroundColor": "#2b4b6b",
  50. "navigationBarTitleText": "物品回收",
  51. "navigationBarTextStyle": "white",
  52. "enablePullDownRefresh": true,
  53. "backgroundColor": "#efefef",
  54. "onReachBottomDistance": 100 // 知识说明下这个知识点
  55. },
  56. 3】tabBar:实现多页面的快速切换,一般是底部tabBar(2-5项标签)
  57. 6个组成部分:backgroundColor tabBar的背景色。
  58. selectedIconPath:选中时图片路径
  59. borderStyle 上边框颜色
  60. iconPath:未选中的图片路径
  61. selectedColor:选中的时候的颜色
  62. color:未选中时候的颜色
  63. **********************************************************************************************
  64. 配置tabBar效果!!!!!!!!!!!!!!!!
  65. {
  66. "pages": [
  67. "pages/index/index",
  68. "pages/test/test",
  69. "pages/logs/logs"
  70. ],
  71. "window": {
  72. "backgroundTextStyle": "dark",
  73. "navigationBarBackgroundColor": "#2b4b6b",
  74. "navigationBarTitleText": "物品回收",
  75. "navigationBarTextStyle": "white",
  76. "enablePullDownRefresh": true,
  77. "backgroundColor": "#efefef"
  78. },
  79. "style": "v2",
  80. "sitemapLocation": "sitemap.json",
  81. "tabBar": { // !!!!!!!!!!!!!!!!
  82. "list": [{
  83. "pagePath": "pages/index/index", // !!!!!!!!!!!!!!!!
  84. "text": "主页"
  85. },
  86. {
  87. "pagePath": "pages/test/test", // !!!!!!!!!!!!!!!!
  88. "text": "测试"
  89. }
  90. ]
  91. }
  92. }
  93. **********************************************************************************************
  94. 有了云服务器真方便,自己的七牛云呀,嘿嘿嘿!!!必须放在本地,emmm 有意思!!!!!
  95. "tabBar": {
  96. "list": [{
  97. "pagePath": "pages/index/index",
  98. "text": "主页",
  99. "iconPath": "/common/主页1.png",
  100. "selectedIconPath": "/common/主页2.png"
  101. },
  102. {
  103. "pagePath": "pages/test/test",
  104. "text": "测试",
  105. "iconPath": "/common/测试1.png",
  106. "selectedIconPath": "/common/测试2.png"
  107. }
  108. ]
  109. }

****************************************************************************************************************************************************************************

  1. 9page.json页面个性化
  2. 1】页面配置文件的作用
  3. 用来配置当前页面的窗口外观、页面效果的。感觉可以但没必要!!!!!
  4. ******************************************************************************************
  5. 页面配置和全局配置的关系。
  6. 如果想覆盖,就把全局配置的内容复制一份,到页面配置重新指定下颜色。
  7. 2】页面配置中常用配置项:和全局的一样 emmm !!!!!!!!!

****************************************************************************************************************************************************************************

  1. 10、发起网络请求
  2. 1】网络数据请求,只能请求https类型的接口
  3. 必须将接口的域名添加到信任列表中,我就信任https://wdfgdzx.top 哈哈
  4. https://mp.weixin.qq.com/wxamp/devprofile/get_profile?token=1582776250&lang=zh_CN
  5. 上述地址添加
  6. **********************************************************************************************
  7. 不能用localhost,而且还必须备案,emmm
  8. 2】发起get请求
  9. getInfo() {
  10. wx.request({
  11. url: 'https://wdfgdzx.top/wx_test', // 请求的地址接口,必须基于https协议
  12. method: 'GET', // 请求的方式
  13. data: { // 发送到服务器的数据
  14. page: 1
  15. },
  16. success: res => {
  17. wx.showToast({
  18. title: res.data,
  19. icon: 'success',
  20. duration: 2000
  21. }); // 请求成功之后的回调函数
  22. }
  23. })
  24. },
  25. **********************************************************************************************
  26. getInfo() {
  27. let thisA = this; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  28. wx.request({
  29. url: 'https://wdfgdzx.top/wx_test', // 请求的地址接口,必须基于https协议
  30. method: 'GET', // 请求的方式
  31. data: { // 发送到服务器的数据
  32. page: 1
  33. },
  34. success: res => {
  35. thisA.setData({ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  36. "test": {
  37. "name": res.data
  38. }
  39. })
  40. }
  41. })
  42. },
  43. 3】发起post请求 P34 16
  44. postInfo() {
  45. let thisA = this;
  46. wx.request({
  47. url: 'https://wdfgdzx.top/wx_post',
  48. method: "post",
  49. data: {
  50. name: "接口必将返回---陈翔六点半"
  51. },
  52. success: (res) => {
  53. thisA.setData({
  54. "test": {
  55. "name": res.data
  56. }
  57. })
  58. }
  59. })
  60. },
  61. **********************************************************************************************
  62. <button type="primary" bindtap="postInfo">发起网络请求</button>
  63. <view>{{test.name}}</view>
  64. 4】页面加载时,请求数据
  65. onLoad(options) {
  66. wx.showToast({
  67. title: '执行了!',
  68. })
  69. this.wx_post()
  70. },
  71. 5】跳过request合法域名校验
  72. 合法域名校验只提供了https
  73. ***************************************************************************************
  74. 但是为了方便开发,可以在:设置-项目设置-不校验合法域名!
  75. 注意只能在开发与调试阶段使用。
  76. ***************************************************************************************
  77. 关于跨域问题,小程序是不存在的,吼吼牛批!!!!!!!!!
  78. ***************************************************************************************
  79. Ajax技术依赖于XMLHttpRequest,小程序的请求是自带的,是叫发起网络请求!

****************************************************************************************************************************************************************************

  1. 11、本地生活案例
  2. 1】步骤
  3. 新建项目--->配置导航栏效果--->配置tabBar效果--->实现轮播图--->九宫格效果--->图片布局
  4. 2】项目备份+项目结构改变
  5. "pages": [
  6. "pages/home/home",
  7. "pages/message/message",
  8. "pages/contact/contact"
  9. ],
  10. 3】配置导航栏的效果
  11. "window": {
  12. "backgroundTextStyle": "dark",
  13. "navigationBarBackgroundColor": "#2b4b6b",
  14. "navigationBarTitleText": "本地生活",
  15. "navigationBarTextStyle": "white",
  16. "enablePullDownRefresh": true,
  17. "backgroundColor": "#efefef"
  18. },
  19. 4】配置tabBar
  20. "tabBar": {
  21. "list": [{
  22. "pagePath": "pages/home/home",
  23. "text": "首页",
  24. "iconPath": "/common/主页2.png",
  25. "selectedIconPath": "/common/主页1.png"
  26. },
  27. {
  28. "pagePath": "pages/message/message",
  29. "text": "消息",
  30. "iconPath": "/common/消息2.png",
  31. "selectedIconPath": "/common/消息1.png"
  32. },
  33. {
  34. "pagePath": "pages/contact/contact",
  35. "text": "联系",
  36. "iconPath": "/common/联系2.png",
  37. "selectedIconPath": "/common/联系1.png"
  38. }
  39. ]
  40. }
  41. 5】实现轮播图
  42. <!-- 轮播图区域 -->
  43. <swiper style="height: 350rpx;" indicator-dots="true" circular="true">
  44. <swiper-item wx:for="{{home.list}}" wx:key="id">
  45. <image src="{{item.preview}}" style="width: 100%;height: 100%;"></image>
  46. </swiper-item>
  47. </swiper>
  48. 6】实现九宫格数据
  49. <!-- 九宫格数据 -->
  50. <view style="display: flex;flex-wrap: wrap;border-left: 1rpx solid #efefef;border-top: 1rpx solid #efefef;">
  51. <view wx:for="{{home.list}}" wx:key="id" style="width: 33.33%;height: 200rpx;display: flex;flex-direction: column;align-items: center;justify-content: center;border-right: 1rpx solid #efefef;border-bottom: 1rpx solid #efefef;box-sizing: border-box;">
  52. <image src="{{item.preview}}" style="width: 60rpx;height: 60rpx;"></image>
  53. <text style="font-size: 24rpx;margin-top: 10rpx;">{{item.name}}</text>
  54. </view>
  55. </view>
  56. 7】底部图片的展示
  57. <!-- 图片区域 -->
  58. <view style="display: flex;padding: 20rpx 10rpx;justify-content: space-around;">
  59. <image src="{{home.list[0].preview}}" mode="widthFix" style="width: 45%;"></image>
  60. <image src="{{home.list[1].preview}}" mode="widthFix" style="width: 45%;"></image>
  61. </view>
  62. ***************************************************************************************************
  63. 发现没?当wxss融入了wxml,逻辑非常清晰,就是样式的调整而已,还不简单吗!!!!哈哈
  64. ***************************************************************************************************
  1. data: {
  2. home: {
  3. list: []
  4. }
  5. },
  1. selectHomeList() {
  2. // let thisA = this;
  3. wx.request({
  4. url: 'https://localhost/document/list_page',
  5. method: 'post',
  6. data: {
  7. currentPage: 1,
  8. pageSize: 9
  9. },
  10. success: (res) => {
  11. // console.log(res.data.object.data)
  12. this.setData({
  13. home: {
  14. list: res.data.object.data
  15. }
  16. })
  17. // console.log(this.data.home.list)
  18. }
  19. })
  20. },

****************************************************************************************************************************************************************************

  1. 12、页面间导航跳转
  2. 1】页面之间的相互跳转
  3. 传统HTML:<a>链接跳转、localtion.href跳转
  4. *********************************************************************************************
  5. 小程序实现跳转的两种方式:
  6. @声明式导航:<navigator>
  7. @编程式导航:调用小程序的导航API,实现页面的跳转
  8. *********************************************************************************************
  9. <navigator url="/pages/contact/contact" open-type="switchTab" style="background-color: aqua;">跳转联系页面</navigator>
  10. open-type="switchTab"这个必须指定,不然不能跳转对应的tabBar页面。
  11. 注意点!!!!!!!!!!!!!!!!!!!!
  12. *********************************************************************************************
  13. 跳转非tabBar页面
  14. <navigator url="/pages/info/info" style="background-color: aqua;">跳转info页面</navigator>
  15. 这个自己前面用了很多了!!!!!!!!!!!!!!!
  16. 2】后退导航
  17. <navigator open-type="navigateBack" delta="1" style="background-color: aqua;">返回上一页</navigator>
  18. open-type="navigateBack" 注意!!!!!!!!!!!!!!!!!!!!
  19. delta="1" 注意!!!!!!!!!!!!!!!!!!!!
  20. 3】编程式导航
  21. 跳转tabBar页面:
  22. <button bindtap="goContact">跳转联系页面</button> 这个就是在js方法里用函数调转了
  23. *********************************************************************************************
  24. goContact() {
  25. wx.switchTab({ // 注意!!!!!!!!!!!!!
  26. url: '/pages/contact/contact',
  27. })
  28. },
  29. *********************************************************************************************
  30. 跳转到非tabBar页面
  31. <button bindtap="goInfo">跳转info页面</button>
  32. goInfo() {
  33. wx.navigateTo({ // 注意!!!!!!!!!!!!!
  34. url: '/pages/info/info',
  35. })
  36. },
  37. *********************************************************************************************
  38. 后退导航:
  39. <button bindtap="goBack">后退</button>
  40. goBack() {
  41. wx.navigateBack()
  42. },
  43. 感觉学会声明式就行了。
  44. 4】声明式导航传参
  45. <navigator url="/pages/info/info?name='陈翔'&age=20">跳转到info页面</navigator>
  46. *********************************************************************************************
  47. goInfo() { // 编程式导航传参
  48. wx.navigateTo({ // 注意!!!!!!!!!!!!!
  49. url: '/pages/info/info?name='陈翔'&age=20',
  50. })
  51. },
  52. *********************************************************************************************
  53. 在onLoad中接收导航参数
  54. data: {
  55. name: '',
  56. age: ''
  57. },
  58. /**
  59. * 生命周期函数--监听页面加载
  60. */
  61. onLoad(options) {
  62. console.log(options) // 这里接收了
  63. this.setData({
  64. "name": options.name,
  65. "age": options.age
  66. })
  67. },
  68. *********************************************************************************************
  69. data: {
  70. query: {} // 老师还是牛批,封装的思想
  71. },
  72. /**
  73. * 生命周期函数--监听页面加载
  74. */
  75. onLoad(options) {
  76. console.log(options)
  77. this.setData({
  78. query: options // 老师还是牛批,封装的思想
  79. })
  80. },

****************************************************************************************************************************************************************************

  1. 13、下拉刷新
  2. 1】概述
  3. 就是下拉开启刷新效果;
  4. "enablePullDownRefresh": true,
  5. **********************************************************************************
  6. 建议在页面的.json配置文件中开启"enablePullDownRefresh": true,
  7. {
  8. "usingComponents": {},
  9. "enablePullDownRefresh": true // 这里!!!!!!!!!!!!!!!
  10. }
  11. **********************************************************************************
  12. 设置样式:我是在app.json中统一配置的!!!!
  13. "navigationBarTextStyle": "white",
  14. "backgroundColor": "#efefef"
  15. 2】监听页面的下拉刷新事件,主要实现下拉后count的值置为0
  16. <view>count的值是:{{count}}</view>
  17. <button bindtap="addCount">自增+1</button>
  18. **********************************************************************************
  19. onPullDownRefresh() {
  20. console.log("触发下拉刷新");
  21. this.setData({
  22. count: 0
  23. })
  24. },
  25. **********************************************************************************
  26. 解决下拉刷新后,没有自动关闭刷新效果的问题:
  27. onPullDownRefresh() {
  28. // console.log("触发下拉刷新");
  29. this.setData({
  30. count: 0
  31. })
  32. wx.stopPullDownRefresh() // !!!!!!!!!!!!!!!!!!这里是重点
  33. },

****************************************************************************************************************************************************************************

  1. 14、上拉加载
  2. 1】上拉触底概念
  3. 这个操作往往是实现分页功能的。
  4. 2】监听上拉触底事件
  5. <view style="height: 2000rpx;background-color: aqua;"></view>
  6. *******************************************************************************************
  7. // 需要做节流处理,访问非法的数据请求
  8. onReachBottom() {
  9. console.log("触发了上拉触底事件")
  10. },
  11. *******************************************************************************************
  12. 配置上拉触底的距离,一般不需要配置
  13. {
  14. "usingComponents": {},
  15. "onReachBottomDistance": 100
  16. }
  17. 3】上拉触底案例介绍
  18. 定义获取随机颜色的方法-在页面加载时获取初始数据-渲染UI结构美化页面效果
  19. -在上拉触底时调用获取随机颜色的方法-添加loading提示效果-对上拉触底节流
  20. *******************************************************************************************
  21. data: {
  22. photoList: []
  23. },
  24. getPhotoList() {
  25. wx.request({
  26. url: 'https://localhost/document/list_page',
  27. method: 'post',
  28. data: {
  29. currentPage: 1,
  30. pageSize: 18
  31. },
  32. success: (res) => {
  33. // console.log(res.data.object.data)
  34. this.setData({
  35. // 新旧数据拼接,得到大数组
  36. photoList: [...this.data.photoList, ...res.data.object.data] // 这里是个关键点
  37. })
  38. // console.log(this.data.home.list)
  39. }
  40. })
  41. },
  42. *******************************************************************************************
  43. 果然什么都要用自己的数据,这样才能知道底层的一些东西,是怎么用的,怎么提供的!!!!
  44. UI结构的渲染:
  45. <view wx:for="{{photoList}}" wx:key="id">
  46. <image src="{{item.preview}}" style="width: 100%;border-radius: 10rpx;"></image>
  47. </view>
  48. *******************************************************************************************
  49. 上拉触底后再次调用getPhotoList()函数
  50. onReachBottom() {
  51. // console.log("执行了")
  52. this.getPhotoList() // 会再次发起wx.request请求
  53. },
  54. *******************************************************************************************
  55. 添加loading效果
  56. getPhotoList() {
  57. wx.showLoading({
  58. title: '数据加载中...', // 本地的网络太好了,效果一闪而过
  59. })
  60. wx.request({
  61. url: 'https://localhost/document/list_page',
  62. method: 'post',
  63. data: {
  64. currentPage: 1,
  65. pageSize: 18
  66. },
  67. complete: (res) => {
  68. wx.hideLoading()
  69. },
  70. *******************************************************************************************
  71. 解决上拉处理节流的问题:!!!!!!!!!!!!!!!!!!!
  72. 定义节流阀--->修改loadingFlag的值--->判断loadingFlag从而实现节流(红绿灯)
  73. getPhotoList() { // VUE的语法也能用呀 哈哈哈哈哈!!!!!!!!!!!!
  74. wx.showLoading({
  75. title: '数据加载中...',
  76. })
  77. this.data.loadingFlag = true
  78. wx.request({
  79. url: 'https://localhost/document/list_page',
  80. method: 'post',
  81. data: {
  82. currentPage: 1,
  83. pageSize: 18
  84. },
  85. complete: (res) => {
  86. wx.hideLoading()
  87. this.data.loadingFlag = false
  88. },
  89. *******************************************************************************************
  90. onReachBottom() {
  91. // console.log("执行了")
  92. if (!this.data.loadingFlag) {
  93. this.getPhotoList()
  94. } else {
  95. return
  96. }
  97. },
  98. 4】自定义编译模式
  99. 在普通编译-添加编译模式-里面来改变,方便直接看当前修改页面的效果!!!!!!!
  100. 提高开发效率是最根本的目的!!!!!!!!!!!!!

****************************************************************************************************************************************************************************

  1. 15、生命周期函数
  2. 1】概述
  3. 生命周期:创建---运行---销毁的整个阶段。强调的是一个时间段。
  4. *****************************************************************************************
  5. 小程序从开始运行,到程序结束关闭的阶段。
  6. 2】分类
  7. 应用生命周期:小程序的启动-运行-销毁的过程
  8. 页面生命周期:页面的加载---渲染---销毁的过程
  9. 应用生命周期>页面生命周期
  10. 小程序启动---页面A的生命周期---页面B的生命周期---...---小程序结束
  11. 3】生命周期函数
  12. 作用:允许程序员在特定的时间点,执行某些特定的操作
  13. onLoad:页面初始化数据
  14. 生命周期函数:强调的是时间点。
  15. 4】生命周期函数分类:
  16. 应用的生命周期函数、页面的生命周期函数
  17. 应用的生命周期函数
  18. *******************************************************************************************
  19. 需要再app.js中声明:
  20. onLaunch、onShow、onHide
  21. console.log("触发了onLaunch...")
  22. *******************************************************************************************
  23. onShow 从手机进入小程序
  24. onHide 从手机退出小程序
  25. 5】页面声明周期函数
  26. onLoad() // 初始化页面 仅调用一次!!!!!!!!!!!!!!!!!
  27. onShow() // 页面展示
  28. onReady() // 初次渲染完毕后,可以修改页面的UI结构了!!!!!!!!
  29. onHide()// 页面被隐藏了
  30. onUnload()// 一个页面调用一次
  31. 6】wxs脚本概述
  32. wxs典型应用场景是”过滤器“
  33. *******************************************************************************************
  34. wxs类似于js,不支持ES6及以上语法、wxs遵循了CommonJS规范
  35. *******************************************************************************************
  36. wxs内嵌使用语法:可以内嵌到wxml中
  37. 可以用于封装方法呀 感觉!!!!!!!!!!!
  38. <!--pages/message/message.wxml-->
  39. <text>pages/message/message.wxml</text>
  40. <view>count的值是:{{count}}</view>
  41. <button bindtap="addCount">自增+1</button>
  42. {{name}}
  43. {{m1.toUpperCase(name)}} // 使用!!!!!!!!!!!!!!!!
  44. <wxs module="m1"> // 定义!!!!!!!!!!!!!!!!!!!
  45. module.exports.toUpperCase = function (str) {
  46. return str.toUpperCase()
  47. }
  48. </wxs>
  49. *******************************************************************************************
  50. 定义外联的wxs脚本!!!!!!!!!!!!!!!!!!!!!!
  51. /* tools.wxs */
  52. function toUpperCase(str) {
  53. return str.toUpperCase()
  54. }
  55. module.exports = {
  56. toUpperCase: toUpperCase // 和VUE不一样,不能使用简写!!!!!!!!!!
  57. }
  58. <!--pages/message/message.wxml-->
  59. <text>pages/message/message.wxml</text>
  60. <view>count的值是:{{count}}</view>
  61. <button bindtap="addCount">自增+1</button>
  62. {{name}}
  63. {{m1.toUpperCase(name)}}
  64. <wxs src="../../utils/tools.wxs" module="m1"></wxs> // !!!!!!!!!!这里是重点
  65. *******************************************************************************************
  66. wxs特点,wxs和js是两种语言。
  67. wxs典型场景就是过滤器,要配合胡子语法使用!!!!!!有很大局限性呀
  68. 隔离性:wxs运行环境和其他js代码是隔离的
  69. wxs不能调用js中定义的函数,也不能调用小程序提供的API
  70. 性能好:iOS上而已,会快2-20倍,在安卓上一样。

****************************************************************************************************************************************************************************

  1. 16、本地生活案例扩展
  2. 1】完成列表页面的开发
  3. 效果:页面导航传参---上拉触底---下拉刷新
  4. ***************************************************************************************
  5. <!-- 九宫格数据 -->
  6. <view style="display: flex;flex-wrap: wrap;border-left: 1rpx solid #efefef;border-top: 1rpx solid #efefef;">
  7. <navigator url="/pages/beauty_list/beauty_list?id={{item.id}}&name={{item.name}}" wx:for="{{home.list}}" wx:key="id" style="width: 33.33%;height: 200rpx;display: flex;flex-direction: column;align-items: center;justify-content: center;border-right: 1rpx solid #efefef;border-bottom: 1rpx solid #efefef;box-sizing: border-box;">
  8. <image src="{{item.preview}}" style="width: 60rpx;height: 60rpx;"></image>
  9. <text style="font-size: 24rpx;margin-top: 10rpx;">{{item.name}}</text>
  10. </navigator>
  11. </view>
  12. 导航+传参navigator url="/pages/beauty_list/beauty_list?id={{item.id}}&name={{item.name}}"
  13. ***************************************************************************************
  14. 动态设置页面的标题
  15. data: {
  16. query: {}
  17. },
  18. ***************************************************************************************
  19. onLoad(options) {
  20. // console.log(options)
  21. this.data.query = options; // 还是我牛批 三步走!!!!!!说明可以用this.data.query来赋值
  22. },
  23. ***************************************************************************************
  24. onReady() {
  25. wx.setNavigationBarTitle({
  26. title: this.data.query.name,
  27. })
  28. },
  29. ***************************************************************************************
  30. query: {}, // 重新定义包装数据类型 // 神经百战才知道结构化和统一性的重要性!!!!!!!!!!!!
  31. // 要不统一改写自己的VUE项目吧,感觉肯定是获益匪浅!!!!!!!!!!!!!!
  32. list: [],
  33. sendData: {
  34. currentPage: 1, // 这里都是和服务器对应的
  35. pageSize: 9
  36. },
  37. sendDataForm: {
  38. total: 0
  39. },
  40. returnData: {}
  41. ***************************************************************************************
  42. 事实证明: 更靠谱点 卧槽 emmm
  43. this.setData({
  44. list: res.data.object.data
  45. })
  46. 可以优化,但是不要玩火!!!!!!!!!!!!
  47. 2】列表页面的开发
  48. list: [...this.data.list, ...res.data.object.data], 这个写法需要注意下!!!!!!!!
  49. ***************************************************************************************
  50. 排查了一圈,感觉自己的后端逻辑代码真牛皮。
  51. <!--pages/beauty_list/beauty_list.wxml-->
  52. <!-- <text>pages/beauty_list/beauty_list.wxml</text> -->
  53. <view wx:for="{{list}}" wx:key="id" style="display: flex;padding: 15rpx;border: 1rpx solid #efefef;margin:15rpx;border-radius: 8rpx;box-shadow: 1rpx 1rpx 15rpx #ddd;">
  54. <view>
  55. <image src="{{item.preview}}" style="width: 250rpx;height:250rpx;display: block;margin-right: 15rpx;"></image>
  56. </view>
  57. <view style="display: flex;flex-direction: column;justify-content: space-around;font-size: 24rpx;">
  58. <text style="font-weight: bold;">名称:{{item.name}}</text>
  59. <text>大小:{{item.size}}</text>
  60. <text>类型:{{item.type}}</text>
  61. <text>MD5:{{item.md5}}</text>
  62. </view>
  63. </view>
  64. ***************************************************************************************550分钟
  65. 实现加载中效果!!!!!!!!!!!!!!!!
  66. wx.showLoading({
  67. title: '数据加载中...',
  68. })
  69. complete: () => {
  70. wx.hideLoading()
  71. },
  72. ***************************************************************************************
  73. 上拉触底的分页加载效果:
  74. onReachBottom() {
  75. // console.log("执行了")
  76. this.data.sendData.currentPage = this.data.sendData.currentPage + 1
  77. console.log(this.data.sendData) // 我搞的好,当超过3也的时候,会不断加载第一页
  78. this.selectList()
  79. },
  80. ***************************************************************************************
  81. 定义节流阀
  82. loadingFlag: false
  83. selectList() {
  84. // let thisA = this;
  85. this.data.loadingFlag = true
  86. wx.showLoading({
  87. title: '数据加载中...',
  88. })
  89. wx.request({
  90. url: 'https://localhost/document/list_page',
  91. method: 'post',
  92. data: this.data.sendData,
  93. complete: () => {
  94. wx.hideLoading()
  95. this.data.loadingFlag = false
  96. },
  97. onReachBottom() {
  98. // console.log("执行了")
  99. if (!this.data.loadingFlag) {
  100. this.data.sendData.currentPage = this.data.sendData.currentPage + 1
  101. console.log(this.data.sendData)
  102. } else {
  103. return false
  104. }
  105. this.selectList()
  106. },
  107. Network下网络改成slow 3G可以模拟出效果
  108. 3】分页问题的处理
  109. 如果只有3页,会发送为第4 5页的请求吗?
  110. 自己虽然牛批,但是还需要处理重复的数据的.....
  111. ***************************************************************************************
  112. 页码值*每页数据>=总页数了,就没有下一页了!!!!牛批!!!哥哥
  113. if (this.data.sendData.currentPage * this.data.sendData.pageSize >= this.data.returnData.total) {
  114. // 证明没有下一页了
  115. return wx.showToast({
  116. title: '数据加载完毕!',
  117. icon: "none"
  118. })
  119. }
  120. ***************************************************************************************
  121. 启动下拉刷新
  122. {
  123. "usingComponents": {},
  124. "enablePullDownRefresh": true // !!!!!!!!!!!!!!!!
  125. }
  126. *****************************************
  127. onPullDownRefresh() {
  128. // 下拉刷新充值关键数据
  129. this.data.sendData.currentPage = 1
  130. this.data.list = []
  131. this.data.returnData.total = 0
  132. // 重新发起请求
  133. console.log(this.data.sendData)
  134. this.selectList()
  135. },
  136. *****************************************
  137. 解决下拉刷新不会自动关闭的问题
  138. complete: () => {
  139. wx.hideLoading()
  140. this.data.loadingFlag = false
  141. wx.stopPullDownRefresh() // 自动关闭下拉刷新的效果
  142. },
  143. 优化下*********************
  144. this.selectList(() => {
  145. wx.stopPullDownRefresh()
  146. })
  147. ********************************************
  148. selectList(cb) {
  149. // let thisA = this;
  150. this.data.loadingFlag = true
  151. wx.showLoading({
  152. title: '数据加载中...',
  153. })
  154. wx.request({
  155. url: 'https://localhost/document/list_page',
  156. method: 'post',
  157. data: this.data.sendData,
  158. complete: () => {
  159. wx.hideLoading()
  160. this.data.loadingFlag = false
  161. // wx.stopPullDownRefresh()
  162. cb && cb()
  163. },
  164. success: (res) => {
  165. // console.log(res)
  166. this.setData({
  167. list: [...this.data.list, ...res.data.object.data],
  168. returnData: {
  169. total: res.data.object.total - 0
  170. }
  171. })
  172. console.log(this.data.list)
  173. }
  174. })
  175. },
  176. 4】wxs店铺手机号的处理:过滤器
  177. /* tools.wxs */
  178. function toUpperCase(str) {
  179. return str.toUpperCase()
  180. }
  181. function shortMd5(str) {
  182. return str.substring(0, 23)
  183. }
  184. module.exports = {
  185. toUpperCase: toUpperCase,
  186. shortMd5: shortMd5
  187. }
  188. *****************************************************************
  189. <view style="display: flex;flex-direction: column;justify-content: space-around;font-size: 24rpx;">
  190. <text style="font-weight: bold;">名称:{{item.name}}</text>
  191. <text>大小:{{item.size}}</text>
  192. <text>类型:{{item.type}}</text>
  193. <text>MD5:{{tools.shortMd5(item.md5)}}</text>
  194. </view>
  195. </view>
  196. <wxs src="../../utils/tools.wxs" module="tools"></wxs>
  197. 真能实现我的md5缩减功能,牛批,过滤手机电话号码,应该是一样的
  198. 5】总结
  199. 导航跳转、下拉刷新、上拉加载更多、知道小程序的生命周期函数

****************************************************************************************************************************************************************************

  1. 17、自定义组件
  2. 1】创建组件
  3. 在componets--->test文件夹--->新建Component
  4. 组件也是对应4个文件:.js、.json、.wxml和.wxss
  5. 每个组件建议存在单独的目录中,如test1组件 test2组件,创建Component选项
  6. 2】组件的应用
  7. 局部引用、全局引用!
  8. {
  9. "usingComponents": {
  10. "test1": "/components/test1/test1"
  11. }
  12. }
  13. ********************************************************************************************
  14. 直接使用即可!!!!!感觉VUE使用还行,小程序有点杀鸡用牛刀的感觉吧
  15. <!-- home.wxml -->
  16. <test1></test1>
  17. 3】全局引用
  18. 在app.json里 和pages平级,增加配置,即可
  19. "usingComponents": {
  20. "test1": "/components/test1/test1"
  21. }
  22. 4】全局引用与局部引用的使用场景!
  23. 如果会在多个页面,建议全局引用。
  24. 如果只在少数页面使用,建议使用局部引用。
  25. 5】组件和页面的区别?
  26. @组件的test1.json中必须有个字段, "component": true,
  27. @组件的test1.js中,调用的是Component函数
  28. @组件的函数,需要定义到methods节点中,和VUE一样了!!!!!
  29. 6】组件的样式隔离 630分钟(数据记录 三方管理继续修改)

****************************************************************************************************************************************************************************

  1. 17、自定义组件
  2. 1】创建组件
  3. 在componets--->test文件夹--->新建Component
  4. 组件也是对应4个文件:.js、.json、.wxml和.wxss
  5. 每个组件建议存在单独的目录中,如test1组件 test2组件,创建Component选项
  6. 2】组件的应用
  7. 局部引用、全局引用!
  8. {
  9. "usingComponents": {
  10. "test1": "/components/test1/test1"
  11. }
  12. }
  13. ********************************************************************************************
  14. 直接使用即可!!!!!感觉VUE使用还行,小程序有点杀鸡用牛刀的感觉吧
  15. <!-- home.wxml -->
  16. <test1></test1>
  17. 3】全局引用
  18. 在app.json里 和pages平级,增加配置,即可
  19. "usingComponents": {
  20. "test1": "/components/test1/test1"
  21. }
  22. 4】全局引用与局部引用的使用场景!
  23. 如果会在多个页面,建议全局引用。
  24. 如果只在少数页面使用,建议使用局部引用。
  25. 5】组件和页面的区别?
  26. @组件的test1.json中必须有个字段, "component": true,
  27. @组件的test1.js中,调用的是Component函数
  28. @组件的函数,需要定义到methods节点中,和VUE一样了!!!!!
  29. 6】组件的样式隔离 630分钟(数据记录 三方管理继续修改)
  30. 组件样式有隔离的特性:页面不会影响组件,组件不会影响页面
  31. ***************************************************************************************
  32. 组件样式隔离的注意点:全局样式声明的样式表对组件是无效的。(仅是类选择器)
  33. .g_red_text {
  34. color: red;
  35. }
  36. <text class="g_red_text">components/test1/test1.wxml</text>
  37. ***************************************************************************************
  38. 只有这样才有效
  39. <text style="color: green;">components/test1/test1.wxml</text>
  40. ***************************************************************************************
  41. 所以使用的使用建议使用类选择器,这样能样式隔离,我更懒,我就用style,嘿嘿嘿...
  42. ***************************************************************************************
  43. 修改组件的样式隔离选项:
  44. Component({
  45. options: {
  46. styleIsolation: 'apply-shared' // isolated默认 apply-shared页面影响组件 shared 双向影响
  47. },
  48. 这时候页面就影响组件了:
  49. <text class="allRed">components/test1/test1.wxml</text>
  50. 就是样式的额变化,没有必要这么玩,都搞迷糊了,卧槽!!!!!!!!!!!!!!!
  51. 7】自定义组件-数据方法和属性
  52. data: {
  53. name: '组件'
  54. },
  55. ***************************************************************************************
  56. _myShowToast() {
  57. wx.showToast({
  58. title: 'name的值:' + this.data.name,
  59. icon: 'none'
  60. })
  61. }
  62. 只要是自己定义的函数都以_开头。
  63. methods: {
  64. addPoint() {
  65. this.setData({
  66. name: this.data.name + '.'
  67. })
  68. this._myShowToast()
  69. },
  70. _myShowToast() {
  71. wx.showToast({
  72. title: 'name的值:' + this.data.name,
  73. icon: 'none'
  74. })
  75. }
  76. }
  77. ***************************************************************************************
  78. <!--components/test1/test1.wxml-->
  79. <text>components/test1/test1.wxml</text>
  80. <view>
  81. name的值是:{{name}}
  82. </view>
  83. <button bindtap="addPoint">给name加.</button>
  84. ***************************************************************************************
  85. 就是VUE的prop卧槽,现在才明白!!!!!!!!!!!!!!!!!!!!
  86. properties: {
  87. max: {
  88. type: Number,
  89. value: 10 // 默认值
  90. },
  91. min: Number // 简化形式
  92. },
  93. ***************************************************************************************
  94. <!--components/test1/test1.wxml-->
  95. <text>components/test1/test1.wxml</text>
  96. <view>
  97. name的值是:{{name}}
  98. </view>
  99. <button bindtap="addPoint">给name加.</button>
  100. 我的prop是:{{max}} {{min}} !!!!!!!!!!!!!!!
  101. ***************************************************************************************
  102. <!-- home.wxml -->
  103. <test1 max="5" min='2'></test1>
  104. ***************************************************************************************
  105. 展示的是我的prop是: 5 2 ,懂了吧!!!!!!!!!!!!!!!!!!!
  106. methods: {
  107. addPoint() {
  108. if (this.data.count >= this.properties.max) { //控制自增最大值!!!!!!!!!!!!
  109. return false
  110. }
  111. this.setData({
  112. count: this.data.count + 1
  113. })
  114. this._myShowToast()
  115. },
  116. _myShowToast() {
  117. wx.showToast({
  118. title: 'count的值:' + this.data.count,
  119. icon: 'none'
  120. })
  121. }
  122. }
  123. ***************************************************************************************
  124. data和properties的区别:小程序里都差不多。
  125. data存储私有数据,properties是外界传过来的数据,两者都是可读可写的。
  126. this.data.xxx
  127. this.properties.xxx 注意下使用的区别!!!!!!!!!!!!!!!!
  128. ***************************************************************************************
  129. setData修改properties的值
  130. this.setData({
  131. count: this.data.count + 1,
  132. min: this.properties.min - 1 // !!!!!!!!!!注意是this.properties哦!!!!!
  133. })
  134. 8】自定义组件-数据监听器
  135. 类似VUE里的watch侦听器
  136. observers: {
  137. 'count,min': function name(count, min) {
  138. console.log("count的值发生变化:" + count + "---" + min)
  139. }
  140. }
  141. 说明不仅能监控data,还能监控properties,卧槽 卧槽 好屌呀
  142. ***************************************************************************************
  143. 监听器监听对象属性的变化:
  144. observers: {
  145. 'person.name,person.age': function name(name, age) {
  146. console.log("person属性的值发生变化:" + name + "---" + age)
  147. }
  148. }
  149. ***************************************************************************************
  150. 数据监听器案例:
  151. <!--components/test1/test1.wxml-->
  152. <text>components/test1/test1.wxml</text>
  153. <view style="background-color: rgb({{fullColor}});line-height: 200rpx;font-size: 24rpx;color: white;text-shadow: 0rpx 0rpx 2rpx black;text-align: center;">
  154. 颜色值:{{fullColor}}
  155. </view>
  156. <button size="mini" bindtap="changeR" type="default"></button>
  157. <button size="mini" bindtap="changeG" type="primary"></button>
  158. <button size="mini" bindtap="changeB" type="warn"></button>
  159. ***************************************************************************************
  160. // components/test1/test1.js
  161. Component({
  162. /**
  163. * 组件的初始数据
  164. */
  165. data: {
  166. rgb: {
  167. r: 0,
  168. g: 0,
  169. b: 0
  170. },
  171. fullColor: '0,0,0'
  172. },
  173. /**
  174. * 组件的方法列表
  175. */
  176. methods: {
  177. changeR() {
  178. this.setData({
  179. 'rgb.r': this.data.rgb.r + 5 > 255 ? 255 : this.data.rgb.r + 5 // 看看对象的赋值
  180. })
  181. },
  182. changeG() {
  183. this.setData({
  184. 'rgb.g': this.data.rgb.g + 5 > 255 ? 255 : this.data.rgb.g + 5 // 看看对象的赋值
  185. })
  186. },
  187. changeB() {
  188. this.setData({
  189. 'rgb.b': this.data.rgb.b + 5 > 255 ? 255 : this.data.rgb.b + 5 // 看看对象的赋值
  190. })
  191. },
  192. },
  193. observers: {
  194. 'rgb.r,rgb.g,rgb.b': function name(r, g, b) {
  195. this.setData({
  196. fullColor: `${r},${g},${b}`
  197. })
  198. }
  199. }
  200. })
  201. ***************************************************************************************
  202. 对象监控的优化:!!!!!!!!!!!!!!!!!对象.**
  203. observers: {
  204. 'rgb.**': function name(obj) {
  205. this.setData({
  206. fullColor: `${obj.r},${obj.g},${obj.b}`
  207. })
  208. }
  209. }
  210. 9】自定义组件-纯数据字段
  211. 什么是纯数据字段?那些不用于界面渲染的data字段,比如r g b就是纯数据字段。
  212. ***************************************************************************************
  213. 纯数据字段能够提升页面更新的性能。
  214. ***************************************************************************************
  215. 怎么定义?
  216. options: {
  217. pureDataPattern: /^_/ // 凡是以_开头的都是纯数据字段
  218. },
  219. data: {
  220. _a: true, // 纯数据字段
  221. ***************************************************************************************
  222. 全局改造!!!!!!!!!!!!!!!!!!提升性能!!!!!!!!!!
  223. // components/test1/test1.js
  224. Component({
  225. /**
  226. * 组件的初始数据
  227. */
  228. options: {
  229. pureDataPattern: /^_/ // 凡是以_开头的都是纯数据字段
  230. },
  231. data: {
  232. _rgb: {
  233. r: 0,
  234. g: 0,
  235. b: 0
  236. },
  237. fullColor: '0,0,0'
  238. },
  239. /**
  240. * 组件的方法列表
  241. */
  242. methods: {
  243. changeR() {
  244. this.setData({
  245. '_rgb.r': this.data._rgb.r + 5 > 255 ? 255 : this.data._rgb.r + 5
  246. })
  247. },
  248. changeG() {
  249. this.setData({
  250. '_rgb.g': this.data._rgb.g + 5 > 255 ? 255 : this.data._rgb.g + 5
  251. })
  252. },
  253. changeB() {
  254. this.setData({
  255. '_rgb.b': this.data._rgb.b + 5 > 255 ? 255 : this.data._rgb.b + 5
  256. })
  257. },
  258. },
  259. observers: {
  260. '_rgb.**': function name(obj) {
  261. this.setData({
  262. fullColor: `${obj.r},${obj.g},${obj.b}`
  263. })
  264. }
  265. }
  266. })
  267. 10】组件的生命周期
  268. created:常用
  269. attached:常用
  270. ready
  271. moved
  272. detached:常用
  273. error
  274. ***************************************************************************************
  275. 主要的生命周期函数:
  276. created 组件示例刚创建好的时候,这时候还不能使用setData
  277. attached 这时候setData可以执行,可以进行初始化数据
  278. detached 组件被销毁的时候,适合做一些清理性质的工作
  279. ***************************************************************************************
  280. 如何定义组件的生命周期函数:
  281. lifetimes节点:(新的方式,推荐的)
  282. // components/test1/test1.js
  283. Component({
  284. data: {},
  285. /**
  286. * 组件的方法列表
  287. */
  288. lifetimes: {
  289. created() {
  290. console.log('created 执行')
  291. },
  292. attached() {
  293. console.log('attached 执行')
  294. }
  295. },
  296. methods: {},
  297. })
  298. 11】自定义组件-组件所在!!!“页面”!!!的生命周期函数
  299. 例如:每当触发页面show生命周期函数时,希望生成一个随机的RGB颜色值
  300. ***************************************************************************************
  301. 组件所在页面的声明周期函数有3个:show hide resize
  302. ***************************************************************************************
  303. pageLifetimes节点:
  304. // components/test1/test1.js
  305. Component({
  306. data: {},
  307. /**
  308. * 组件的方法列表
  309. */
  310. pageLifetimes: { // 所在页面的生命周期函数
  311. show() {
  312. console.log("show 执行")
  313. },
  314. hide() {
  315. console.log("hide 执行")
  316. },
  317. resize() {
  318. console.log("resize 执行")
  319. }
  320. },
  321. methods: {},
  322. })
  323. ***************************************************************************************
  324. // components/test1/test1.js 这个是我自己实现的呦!!!!!!!!!!!!!!!
  325. Component({
  326. data: {
  327. _rgb: {
  328. r: 0,
  329. g: 0,
  330. b: 0
  331. },
  332. fullColor: '0,0,0'
  333. },
  334. /**
  335. * 组件的方法列表
  336. */
  337. pageLifetimes: { // 所在页面的生命周期函数
  338. show() {
  339. console.log("show 执行")
  340. this._randomColor()
  341. },
  342. hide() {
  343. console.log("hide 执行")
  344. },
  345. resize() {
  346. console.log("resize 执行")
  347. }
  348. },
  349. methods: {
  350. _randomColor() {
  351. this.setData({
  352. _rgb: {
  353. r: Math.floor(Math.random() * 256),
  354. g: Math.floor(Math.random() * 256),
  355. b: Math.floor(Math.random() * 256),
  356. },
  357. })
  358. this.setData({
  359. fullColor: this.data._rgb.r + ',' + this.data._rgb.g + ',' + this.data._rgb.b
  360. })
  361. // console.log(this.data.fullColor)
  362. }
  363. },
  364. })
  365. 12】自定义组件-插槽
  366. 什么是插槽?用于承载!!!!组件使用者!!!提供的wxml结构。
  367. <slot></slot>
  368. 好像VUE也没怎么用过,鸡肋
  369. ***************************************************************************************
  370. 单个插槽:
  371. <!--components/test1/test1.wxml-->
  372. <view>
  373. <view>这是组件的内部节点</view>
  374. <slot></slot>
  375. </view>
  376. ***************************************************************************************
  377. <test1>
  378. <view style="color: red;">这里是插入到slot中的content</view>
  379. </test1>
  380. ***************************************************************************************
  381. 启用多个插槽
  382. options: {
  383. multipleSlots: true // 启用多个插槽
  384. },
  385. ***************************************************************************************
  386. 多个要给slot 加name属性加以区分
  387. <!--components/test1/test1.wxml-->
  388. <view>
  389. <slot name="one"></slot>
  390. <view>这是组件的内部节点</view>
  391. <slot name="two"></slot>
  392. </view>
  393. ***************************************************************************************
  394. <test1>
  395. <view style="color: red;" slot="one">这里是插入到slot one中的content</view>
  396. <view style="color: red;" slot="two">这里是插入到slot two中的content</view>
  397. </test1>
  398. 13】父子组件之间的通信
  399. 三种方式:属性绑定(父-子) 事件绑定(子-父) 获取组件实例
  400. ***************************************************************************************
  401. 属性绑定!!!!!!!!!!!:home首页是父组件 test1是子组件!!!!!!!!!!!
  402. <!-- home.wxml -->
  403. <view>父组件中count的值:{{count}}</view>
  404. <!-- 组件 -->
  405. <test1 count="{{count}}">子组件:</test1>
  406. *****************************************
  407. data: { // 父组件
  408. count: 0
  409. },
  410. ***************************************************************************************
  411. 子组件接收:使用
  412. properties: {
  413. count: Number
  414. },
  415. *****************************************
  416. <!--components/test1/test1.wxml-->
  417. <view>
  418. 我是子组件~~~~~~~~count的值是:{{count}}
  419. </view>
  420. *****************************************
  421. 子组件自增+1
  422. addCount() {
  423. this.setData({
  424. fff_son_count: this.properties.fff_son_count + 1
  425. })
  426. }
  427. *****************************************
  428. 发现子组件是变化了,但是父组件没变化,所以要实现子组件向父组件传值:事件绑定!!!!!
  429. ***************************************************************************************
  430. 事件绑定!!!!!!!!!!!!!!!!!!!!!!!!!!!!!子传父
  431. 父组件js定义函数
  432. // 供子组件调用的函数
  433. son_fff_count() {
  434. console.log("son_fff_count")
  435. },
  436. *****************************************
  437. <test1 fff_son_count="{{count}}" bind:son_fff_count="son_fff_count">子组件:</test1>
  438. *****************************************
  439. this.triggerEvent("son_fff_count")
  440. *****************************************
  441. this.triggerEvent("son_fff_count", {
  442. value: this.properties.fff_son_count // 传递的值
  443. })
  444. *****************************************
  445. // 供子组件调用的函数
  446. son_fff_count(e) {
  447. console.log("son_fff_count " + e.detail.value)
  448. this.setData({
  449. count: e.detail.value
  450. })
  451. },
  452. ***************************************************************************************
  453. 至此就实现了父传子、子传父了,牛批!!!!!!!!!!!!!!!
  454. ***************************************************************************************
  455. 获取组件实例实现父子组件的通信!!!!!!!!!!
  456. 建议使用id选择器:
  457. <test1 fff_son_count="{{count}}" bind:son_fff_count="son_fff_count" id="sonTest1">子组件:</test1>
  458. <!-- 通过获取实例 -->
  459. <button bindtap="getSon">获取子组件实例</button>
  460. ***************************************************************************************
  461. getSon() {
  462. const test1 = this.selectComponent("#sonTest1")
  463. console.log(test1)
  464. test1.setData({ // 直接操作子组件
  465. fff_son_count: test1.properties.fff_son_count + 1
  466. })
  467. },

****************************************************************************************************************************************************************************

  1. 18、behaviors作用
  2. 1】概念
  3. 用于实现组件间代码共享的特性,类似vue.js中的mixins,类java的静态变量呀。
  4. ***********************************************************************************
  5. 每一个组件可以引用多个behavior,behavior也可以引用其他behavior
  6. 2】behavior的创建
  7. module.exports = Behavior({
  8. data: {
  9. name: '陈翔'
  10. },
  11. properties: {
  12. },
  13. methods: {
  14. }
  15. })
  16. 3】导入并使用behavior
  17. // components/test1/test1.js
  18. const my_behavior = require('../../behaviors/my_behavior.js')
  19. Component({
  20. behaviors: [my_behavior],
  21. ***********************************************************************************
  22. 使用:
  23. <view>
  24. 在behavior中定义的用户名是:{{name}}
  25. </view>
  26. 4】behavior中所有可用的节点
  27. properties、data、methods、behaviors(引入其他behavior的作用)
  28. ***********************************************************************************
  29. 同名字段的覆盖和组合规则。这也太low了
  30. 5】组件-总结
  31. 创建并引用组件 usingComponents
  32. ***********************************************************************************
  33. 修改组件的样式隔离选项
  34. ***********************************************************************************
  35. 如何定义和使用数据监听器
  36. ***********************************************************************************
  37. 能够知道如何定义和使用纯数据字段
  38. ***********************************************************************************
  39. 知道实现组件父子通信有哪3中方式
  40. ***********************************************************************************
  41. 知道定义和使用behaviors

****************************************************************************************************************************************************************************

  1. 19、vant-weapp组件库
  2. 1】小程序对npm的支持与限制
  3. 不支持依赖Node.js内置库的包...
  4. 不支持依赖浏览器内置对象的包...
  5. 不支持依赖C++插件的包...
  6. 2】使用npm安装Vant Weapp的包
  7. 是有赞前端团队开源的UI组件库,类似于ElementUI。是MIT协议
  8. ***************************************************************************************
  9. 安装Vant组件库
  10. 在目录结构空白处-右击-在外部窗口中打开!!!!!!!!!!!!!!!
  11. npm i @vant/weapp@1.3.3 -S --production
  12. 工具---构建npm
  13. 修改app.json "style": "v2", 去掉
  14. ***************************************************************************************
  15. 使用Vant组件
  16. app.json配置
  17. "usingComponents": {
  18. "vant_button": "@vant/weapp/button/index"
  19. },
  20. -------------------------------------------------------------------
  21. <vant_button type="primary">vant按钮</vant_button>
  22. <vant_button type="info">vant按钮</vant_button>
  23. <vant_button type="warning">vant按钮</vant_button>
  24. <vant_button type="danger">vant按钮</vant_button>
  25. 3】vant weapp定制全局主题样式
  26. /**app.wxss**/
  27. page {
  28. --button-danger-background-color: #C00000;
  29. --button-danger-border-color: #D60000;
  30. }
  31. 这就可以了!!!!!!!!!!!!!!!!!!

****************************************************************************************************************************************************************************

  1. 20、MobX实现全局数据共享
  2. 1】什么是全局数据共享?
  3. Vuex Redx Mobx 更强大的组件间的数据传递
  4. ***************************************************************************************
  5. mobx-miniprogram来创建save示例对象
  6. mobx-miniprogram-bindings 把save中的共享数据或方法,绑定到组件或页面中使用
  7. ***************************************************************************************
  8. npm i --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1
  9. -------------------------------------------------------------------------------------
  10. 删除miniprogram_npm,然后执行工具---npm构建
  11. 2】创建Mbox save实例
  12. // 在这里js中专门创建save实例对象
  13. import {
  14. observable
  15. } from 'mobx-miniprogram'
  16. export const save = observable({
  17. saveName: '陈翔',
  18. saveAge: 26
  19. })
  20. ***************************************************************************************
  21. // 在这里js中专门创建store实例对象
  22. import {
  23. action,
  24. observable
  25. } from 'mobx-miniprogram'
  26. export const store = observable({
  27. storeName: '陈翔',
  28. storeAge: 26,
  29. // 定义计算属性
  30. get add() { // add就是计算属性的名字
  31. return this.storeAge + 1
  32. },
  33. // 定义全局方法修改save里的数据
  34. updateStoreAge: action(function (step) {
  35. this.storeAge = this.storeAge + step
  36. })
  37. })
  38. 3】如何将save里的成员绑定到页面中?
  39. // pages/message/message.js
  40. import {
  41. createStoreBindings
  42. } from 'mobx-miniprogram-bindings'
  43. import {
  44. store
  45. } from '../../store/store'
  46. -------------------------------------------------------------------------------------
  47. onLoad(options) {
  48. this.saveBindings = createStoreBindings(this, {
  49. save,
  50. fields: ['saveName', 'saveAge'],
  51. actions: ['updateSaveAge']
  52. })
  53. },
  54. onUnload() {
  55. this.saveBindings.destroyStoreBindings()
  56. },
  57. 4】在页面上使用save里的成员
  58. <view>
  59. {{storeName}} {{storeAge}}
  60. </view>
  61. <vant_button type="primary" bindtap="saveAgeAdd">storeAge+1</vant_button>
  62. <vant_button type="danger" bindtap="saveAgeReduce" data-step="{{-2}}">storeAge-2</vant_button>
  63. -------------------------------------------------------------------------------------
  64. saveAgeAdd() {
  65. // console.log("saveAgeAdd")
  66. this.updateStoreAge(1)
  67. },
  68. saveAgeReduce(e) {
  69. // console.log(e)
  70. this.updateStoreAge(e.target.dataset.step)
  71. },
  72. 5】将store中的成员绑定到组件中
  73. app.json:
  74. "usingComponents": {
  75. "vant_button": "@vant/weapp/button/index",
  76. "test_component": "components/test_component"
  77. },
  78. -------------------------------------------------------------------------------------
  79. // components/test_component.js
  80. import {
  81. storeBindingsBehavior
  82. } from 'mobx-miniprogram-bindings'
  83. import {
  84. store
  85. } from '../store/store'
  86. // 使用
  87. Component({
  88. behaviors: [storeBindingsBehavior],
  89. storeBindings: {
  90. store,
  91. fields: {
  92. storeName: () => store.storeName, // 第一种
  93. storeAge: (store) => store.storeAge, // 第二种
  94. add: 'add' // 绑定字段的第三种方式
  95. },
  96. actions: {
  97. updateStoreAge: 'updateStoreAge'
  98. }
  99. },
  100. properties: {},
  101. data: {},
  102. methods: {
  103. saveAgeAdd() {
  104. // console.log("saveAgeAdd")
  105. this.updateStoreAge(1)
  106. },
  107. saveAgeReduce(e) {
  108. // console.log(e)
  109. this.updateStoreAge(e.target.dataset.step)
  110. },
  111. }
  112. })
  113. -------------------------------------------------------------------------------------
  114. <!--components/test_component.wxml-->
  115. <text>components/test_component.wxml</text>
  116. <view>~~~~~~~~~~~~~~~~~~~~~分割</view>
  117. <view>
  118. {{storeName}} {{storeAge}}
  119. </view>
  120. <vant_button type="primary" bindtap="saveAgeAdd">storeAge+1</vant_button>
  121. <vant_button type="danger" bindtap="saveAgeReduce" data-step="{{-2}}">storeAge-2</vant_button>

****************************************************************************************************************************************************************************

  1. 21、API实现Promise化
  2. 1】什么是API Promise化?
  3. 通过额外的配置,升级改造为Promise API,提高代码可读性
  4. 2】具体配置与使用
  5. npm i --save miniprogram-api-promise@1.0.4
  6. ----------------------------------------------------------------------------------------
  7. 工具-npm构建 这一步不要忘记了!!!!!!!!!!!!!!
  8. 可以先删除miniprogram_npm,然后再构建,避免构建出现问题。
  9. ****************************************************************************************
  10. 使用:
  11. // app.js
  12. import { promisifyAll } from 'miniprogram-api-promise'
  13. const wxp = wx.p = { }
  14. promisifyAll(wx, wxp)
  15. ----------------------------------------------------------------------------------------
  16. async selectList() {
  17. const {data:res} = await wx.p.request({
  18. method: 'post',
  19. url: 'https://localhost/document/list_page',
  20. data: this.data.sendData,
  21. })
  22. console.log(res)
  23. },
  24. ----------------------------------------------------------------------------------------
  25. 不好意思,用不习惯,emmmm

****************************************************************************************************************************************************************************

  1. 22、分包
  2. 1】概念
  3. 分包是把一个完整的小程序,划分为不同的子包,在构建时打包成不同的分包,让用户在使用的时候
  4. 可以按需加载。
  5. ***********************************************************************************************
  6. 优点:优化小程序首次启动的下载时间,在多人共同开发的时候更高效、解耦写作
  7. 2】分包前项目的构成
  8. 分包前项目过大:所有页面+公共资源
  9. ***********************************************************************************************
  10. 分包后:
  11. 主包:项目启动页面或TabBar页面,以及分包都需要的一些公共资源
  12. 分包:只包含当前分包有关的页面和私有资源 N个分包
  13. 3】分包的加载规则
  14. tabBar肯定放在主包...
  15. -----------------------------------------------------------------------------------------------
  16. 非tabBar页面可以按照功能的不同,划分为不同的包,进行按需下载
  17. 4】分包的体积限制
  18. 整个小程序主包+分包不能超过16M
  19. -----------------------------------------------------------------------------------------------
  20. 单个分包/主包不能超过2M
  21. 5】配置使用分包
  22. 在app.json里的subpackage节点中声明分包的结构
  23. ***********************************************************************************************
  24. "subpackages": [{
  25. "root": "pkgA",
  26. "pages": [
  27. "pages/cat/cat",
  28. "pages/dog/dog"
  29. ]
  30. }, {
  31. "root": "pkgB",
  32. "pages": [
  33. "pages/apple/apple",
  34. "pages/orange/orange"
  35. ]
  36. }],
  37. ***********************************************************************************************
  38. 起别名:!!!!!!!!!!!!!!!!!!!
  39. "subpackages": [{
  40. "root": "pkgA",
  41. "name": "p1",
  42. "pages": [
  43. "pages/cat/cat",
  44. "pages/dog/dog"
  45. ]
  46. }, {
  47. "root": "pkgB",
  48. "name": "p2",
  49. "pages": [
  50. "pages/apple/apple",
  51. "pages/orange/orange"
  52. ]
  53. }],
  54. ***********************************************************************************************
  55. 在详情-基本信息-本地代码-可以看到每个包的大小
  56. ***********************************************************************************************
  57. 分包的打包原则:
  58. @ subpackages分包之外的,都会被打包的主包里面!!!!!!!!!!!!!!
  59. @ 主包也有自己的pages
  60. @ tabBar页面必须在主包内
  61. @ 分包之间不能互相嵌套
  62. ***********************************************************************************************
  63. 分包的引用原则:
  64. @ 主包无法引用分包内的私有资源
  65. @ 分包之间不能相互引用私有资源
  66. @ 分包可以引用主包内的公共资源!!!!!!!!!!!!!!!!!!!!!!!!!!!
  67. 6】独立分包
  68. 可以独立于主包和分包独立运行!!!!
  69. 感觉像是另一个入口,emmmm
  70. @ 特点就是是否需要依赖主包才能运行
  71. ***********************************************************************************************
  72. 独立分包的应用场景:
  73. @ 独立分包不依赖主包即可运行,提升分包页面的启动速度。
  74. 注意: 一个小程序可以有多个独立分包
  75. ***********************************************************************************************
  76. 独立分包的配置方法:
  77. , {
  78. "root": "pkgC",
  79. "name": "p3",
  80. "pages": [
  81. "pages/beauty/beauty",
  82. "pages/girl/girl"
  83. ],
  84. "independent": true // !!!!!!!!!!!!!!!!主要是这里
  85. }
  86. ***********************************************************************************************
  87. 独立分包的引用原则:
  88. @ 主包无法引用独立分包资源
  89. @ 独立分包之间无法相互引用资源
  90. @ 独立分包和普通分包也无法引用资源
  91. @ 独立分包也不能应用主包的公共资源!!!!!!!!!!!!
  92. 7】分包预下载
  93. 在进入小程序某个页面时,框架自动预下载可能需要的分包,从而提升用户对页面的访问速度。
  94. ***********************************************************************************************
  95. 配置分包的预下载
  96. "preloadRule": { // !!!!!!!!!!!!这里这里这里
  97. "pages/contact/contact": {
  98. "packages": ["p1"],
  99. "network": "all" // 所有网络都会下载
  100. }
  101. },
  102. "subpackages": [{
  103. "root": "pkgA",
  104. "name": "p1",
  105. -----------------------------------------------------------------------------------------------
  106. 点击联系的时候,控制台会自动打印:
  107. preloadSubpackages: p1
  108. preloadSubpackages: success
  109. ***********************************************************************************************
  110. 分包预下载的限制:
  111. 同一个主包页面,享有的所有的预下载大小限额2M(总体预下载分包不能超过2M)

****************************************************************************************************************************************************************************

  1. 23、自定义tabBar 89
  2. 1】自定义tabBar的实现步骤
  3. @ 配置信息
  4. @ 添加tabBar代码文件
  5. @ 编写tabBar代码
  6. "tabBar": {
  7. "custom": true, // !!!!!!!!!!!!!!!!!!!
  8. "list": [{
  9. "pagePath": "pages/home/home",
  10. "text": "首页",
  11. "iconPath": "/common/主页2.png",
  12. "selectedIconPath": "/common/主页1.png"
  13. },
  14. {
  15. "pagePath": "pages/message/message",
  16. "text": "消息",
  17. "iconPath": "/common/消息2.png",
  18. "selectedIconPath": "/common/消息1.png"
  19. },
  20. {
  21. "pagePath": "pages/contact/contact",
  22. "text": "联系",
  23. "iconPath": "/common/联系2.png",
  24. "selectedIconPath": "/common/联系1.png"
  25. }
  26. ]
  27. }
  28. 2】初步实现自定义tabBar效果
  29. custom-tab-bar在pages同级,然后新建index组件Component,记录哦 这个很重要!!!!!!!
  30. ******************************************************************************************
  31. 紧接着底部就出现了custom-tab-bar/index.wxml
  32. ******************************************************************************************
  33. "usingComponents": {
  34. "vant_button": "@vant/weapp/button/index",
  35. "test_component": "components/test_component",
  36. "van-tabbar": "@vant/weapp/tabbar/index",
  37. "van-tabbar-item": "@vant/weapp/tabbar-item/index"
  38. },
  39. ---------------------------------------------------------------------------------------------
  40. <!--custom-tab-bar/index.wxml-->
  41. <!-- <text>这是自定义tabBar</text> -->
  42. <van-tabbar active="{{ active }}" bind:change="onChange">
  43. <van-tabbar-item icon="home-o">标签</van-tabbar-item>
  44. <van-tabbar-item icon="search">标签</van-tabbar-item>
  45. <van-tabbar-item icon="friends-o">标签</van-tabbar-item>
  46. <van-tabbar-item icon="setting-o">标签</van-tabbar-item>
  47. </van-tabbar>
  48. ---------------------------------------------------------------------------------------------
  49. // custom-tab-bar/index.js
  50. // 使用
  51. Component({
  52. properties: {},
  53. data: {
  54. active: 0
  55. },
  56. methods: {
  57. onChange(event) { // event.detail 的值为当前选中项的索引
  58. this.setData({
  59. active: event.detail
  60. });
  61. },
  62. }
  63. })
  64. ******************************************************************************************
  65. 自定义徽标:感觉没有组件给的好看,哈哈哈哈
  66. <!--custom-tab-bar/index.wxml-->
  67. <!-- <text>这是自定义tabBar</text> -->
  68. <van-tabbar active="{{ active }}" bind:change="onChange">
  69. <van-tabbar-item info="3">
  70. <image slot="icon" src="/common/主页2.png" mode="aspectFit" style="width: 30px; height: 18px;" />
  71. <image slot="icon-active" src="/common/主页1.png" mode="aspectFit" style="width: 30px; height: 18px;" />
  72. 首页
  73. </van-tabbar-item>
  74. <van-tabbar-item icon="home-o">标签</van-tabbar-item>
  75. <van-tabbar-item icon="search">标签</van-tabbar-item>
  76. <van-tabbar-item icon="friends-o">标签</van-tabbar-item>
  77. <van-tabbar-item icon="setting-o">标签</van-tabbar-item>
  78. </van-tabbar>
  79. ---------------------------------------------------------------------------------------------
  80. data: {
  81. active: 0,
  82. "list": [{
  83. "pagePath": "pages/home/home",
  84. "text": "首页",
  85. "iconPath": "/common/主页2.png",
  86. "selectedIconPath": "/common/主页1.png"
  87. },
  88. {
  89. "pagePath": "pages/message/message",
  90. "text": "消息",
  91. "iconPath": "/common/消息2.png",
  92. "selectedIconPath": "/common/消息1.png"
  93. },
  94. {
  95. "pagePath": "pages/contact/contact",
  96. "text": "联系",
  97. "iconPath": "/common/联系2.png",
  98. "selectedIconPath": "/common/联系1.png"
  99. }
  100. ]
  101. },
  102. ---------------------------------------------------------------------------------------------
  103. <!--custom-tab-bar/index.wxml-->
  104. <!-- <text>这是自定义tabBar</text> -->
  105. <van-tabbar active="{{ active }}" bind:change="onChange">
  106. <van-tabbar-item wx:for="{{list}}" wx:key="index">
  107. <image slot="icon" src="{{item.iconPath}}" mode="aspectFit" style="width: 25px; height: 25px;" />
  108. <image slot="icon-active" src="{{item.selectedIconPath}}" mode="aspectFit" style="width: 25px; height: 25px;" />
  109. {{item.text}}
  110. </van-tabbar-item>
  111. </van-tabbar>
  112. 3】如何渲染出徽标
  113. info="2"
  114. ******************************************************************************************
  115. 处理徽标超出tabBar边界的问题:
  116. // custom-tab-bar/index.js
  117. // 使用
  118. Component({
  119. options: {
  120. styleIsolation: "shared" // 不开启不会生效的哈
  121. },
  122. ---------------------------------------------------------------------------------------------
  123. /* custom-tab-bar/index.wxss */
  124. .van-tabbar-item {
  125. --tabbar-item-margin-bottom: 0
  126. }
  127. ---------------------------------------------------------------------------------------------
  128. 按需渲染徽标
  129. {
  130. "pagePath": "pages/message/message",
  131. "text": "消息",
  132. "iconPath": "/common/消息2.png",
  133. "selectedIconPath": "/common/消息1.png",
  134. info: 2
  135. },
  136. ---------------------------------------------------------------------------------------------
  137. <!--custom-tab-bar/index.wxml-->
  138. <!-- <text>这是自定义tabBar</text> -->
  139. <van-tabbar active="{{ active }}" bind:change="onChange">
  140. <van-tabbar-item wx:for="{{list}}" wx:key="index" info="{{item.info?item.info:''}}">
  141. <image slot="icon" src="{{item.iconPath}}" mode="aspectFit" style="width: 25px; height: 25px;" />
  142. <image slot="icon-active" src="{{item.selectedIconPath}}" mode="aspectFit" style="width: 25px; height: 25px;" />
  143. {{item.text}}
  144. </van-tabbar-item>
  145. </van-tabbar>
  146. ******************************************************************************************
  147. 如何把徽标动态化? // 用store.js全局引用和修改,牛批!!!!!!!!!!!
  148. // custom-tab-bar/index.js
  149. // 使用
  150. import {
  151. storeBindingsBehavior
  152. } from 'mobx-miniprogram-bindings'
  153. import {
  154. store
  155. } from '../store/store'
  156. Component({
  157. behaviors: [storeBindingsBehavior],
  158. options: {
  159. styleIsolation: "shared"
  160. },
  161. properties: {},
  162. storeBindings: {
  163. store,
  164. fields: {
  165. changeInfo: 'changeInfo' // 全局存储的字段
  166. }
  167. },
  168. observers: {
  169. 'changeInfo': function (newVal) {
  170. // console.log(newVal)
  171. this.setData({
  172. 'list[1].info': newVal // 把changeInfo的最新值给到list.info
  173. })
  174. }
  175. },
  176. data: {
  177. active: 0,
  178. "list": [{
  179. "pagePath": "pages/home/home",
  180. "text": "首页",
  181. "iconPath": "/common/主页2.png",
  182. "selectedIconPath": "/common/主页1.png"
  183. },
  184. {
  185. "pagePath": "pages/message/message",
  186. "text": "消息",
  187. "iconPath": "/common/消息2.png",
  188. "selectedIconPath": "/common/消息1.png",
  189. info: 2
  190. },
  191. {
  192. "pagePath": "pages/contact/contact",
  193. "text": "联系",
  194. "iconPath": "/common/联系2.png",
  195. "selectedIconPath": "/common/联系1.png"
  196. }
  197. ]
  198. },
  199. methods: {
  200. onChange(event) { // event.detail 的值为当前选中项的索引
  201. this.setData({
  202. active: event.detail
  203. });
  204. },
  205. }
  206. })
  207. 4】如何实现tabBar页面的切换
  208. onChange(event) { // event.detail 的值为当前选中项的索引
  209. this.setData({
  210. active: event.detail
  211. });
  212. wx.switchTab({
  213. url: '/' + this.data.list[event.detail].pagePath, // 调用切换!!!!!!!!!!!!!
  214. })
  215. },
  216. ******************************************************************************************
  217. // 在这里js中专门创建save实例对象
  218. import {
  219. action,
  220. observable
  221. } from 'mobx-miniprogram'
  222. export const store = observable({
  223. storeName: '陈翔',
  224. storeAge: 26,
  225. changeInfo: 2,
  226. active: 0,
  227. // 修改active下标的函数
  228. updateActive: action(function (index) {
  229. this.active = index
  230. }),
  231. // 定义计算属性
  232. get add() { // add就是计算属性的名字
  233. return this.storeAge + 1
  234. },
  235. // 定义全局方法修改save里的数据
  236. updateStoreAge: action(function (step) {
  237. this.storeAge = this.storeAge + step
  238. this.changeInfo = this.changeInfo + step
  239. })
  240. })
  241. ---------------------------------------------------------------------------------------------
  242. 处理索引标记的问题
  243. // custom-tab-bar/index.js
  244. // 使用
  245. import {
  246. storeBindingsBehavior
  247. } from 'mobx-miniprogram-bindings'
  248. import {
  249. store
  250. } from '../store/store'
  251. Component({
  252. behaviors: [storeBindingsBehavior],
  253. options: {
  254. styleIsolation: "shared"
  255. },
  256. properties: {},
  257. storeBindings: {
  258. store,
  259. fields: {
  260. changeInfo: 'changeInfo', // 全局存储的字段
  261. active: 'active'
  262. },
  263. actions: {
  264. updateActive: 'updateActive'
  265. }
  266. },
  267. observers: {
  268. 'changeInfo': function (newVal) {
  269. // console.log(newVal)
  270. this.setData({
  271. 'list[1].info': newVal // 把changeInfo的最新值给到list.info
  272. })
  273. }
  274. },
  275. data: {
  276. "list": [{
  277. "pagePath": "pages/home/home",
  278. "text": "首页",
  279. "iconPath": "/common/主页2.png",
  280. "selectedIconPath": "/common/主页1.png"
  281. },
  282. {
  283. "pagePath": "pages/message/message",
  284. "text": "消息",
  285. "iconPath": "/common/消息2.png",
  286. "selectedIconPath": "/common/消息1.png",
  287. info: 2
  288. },
  289. {
  290. "pagePath": "pages/contact/contact",
  291. "text": "联系",
  292. "iconPath": "/common/联系2.png",
  293. "selectedIconPath": "/common/联系1.png"
  294. }
  295. ]
  296. },
  297. methods: {
  298. onChange(event) { // event.detail 的值为当前选中项的索引
  299. /* this.setData({
  300. active: event.detail
  301. }); */
  302. this.updateActive(event.detail)
  303. wx.switchTab({
  304. url: '/' + this.data.list[event.detail].pagePath,
  305. })
  306. },
  307. }
  308. })
  309. 5】修改选中项文本的颜色
  310. <van-tabbar active="{{ active }}" bind:change="onChange" active-color="red">
  311. active-color="red"!!!!!!!!!!!!默认的也挺好的,噗嗤
  312. 6】总结:
  313. @ vant-weapp组件库配置使用
  314. @ Mbox 就是store.js的使用
  315. @ 小程序的API promise化
  316. @ 实现自定义tabBar效果!!!!!!!!!!!!!!!!!!

****************************************************************************************************************************************************************************

  1. 24、小程序大项目(uni-app)
  2. 1】项目概述:
  3. 4个tabBar
  4. ***********************************************************************************
  5. @ 商品分类
  6. @ 分类的布局,商品列表页面
  7. @ 加入购物车
  8. @ 收货地址
  9. @ 一键登录
  10. @ 我的页面 收货客服
  11. @ 支付
  12. 2】uni-app概述与开放环境
  13. uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到
  14. iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ
  15. /快手/钉钉/淘宝)、快应用等多个平台。卧槽 这么屌吗!!!!!!!!!!!!!!!
  16. ---------------------------------------------------------------------------------------------
  17. 基于vue.js语法的uni-app模板项目,好牛皮,可以发布小程序项目、H5、Android、iOS、etc等等....
  18. ***********************************************************************************
  19. 下载和配置uniapp开发工具:HBuilderX
  20. https://www.dcloud.io/hbuilderx.html
  21. ---------------------------------------------------------------------------------------------
  22. 下载后解压即可
  23. ---------------------------------------------------------------------------------------------
  24. 安装scss/sass编译插件
  25. https://ext.dcloud.net.cn/plugin?id=2046
  26. ---------------------------------------------------------------------------------------------
  27. 个性化配置:工具-自定义快捷键
  28. 2】新建uniapp项目
  29. 文件---新建项目---所在位置+文件名---选择uni-ui项目
  30. ***********************************************************************************
  31. 组成结构:
  32. pages:所有小程序页面
  33. ---------------------------------------------------------------------------------------------
  34. static:静态资源
  35. ---------------------------------------------------------------------------------------------
  36. main.js vue的初始化入口
  37. ---------------------------------------------------------------------------------------------
  38. App.vue 配置小程序的全局样式
  39. ---------------------------------------------------------------------------------------------
  40. manifest.json
  41. ---------------------------------------------------------------------------------------------
  42. pages.json
  43. ---------------------------------------------------------------------------------------------
  44. uni.scss
  45. ***********************************************************************************
  46. 如何把uniapp项目运行到微信小程序里
  47. 填写微信小程序APPID---manifest.json---微信小程序配置---粘贴小程序appid
  48. ---------------------------------------------------------------------------------------------
  49. 工具-设置-运行配置---小程序运行配置---微信开发者工具路径:C:\Program Files (x86)\Tencent\微信web开发者工具
  50. ---------------------------------------------------------------------------------------------
  51. 微信-开发者工具-设置-安全-服务端口打开
  52. ---------------------------------------------------------------------------------------------
  53. 通过Hbuilder运行-运行到小程序模拟器---即可打开微信小程序开效果,我日尼玛!!!
  54. ***********************************************************************************
  55. 使用Git管理项目
  56. 根节点新建:.gitignore文件
  57. /node_modules
  58. /uppackage/dist
  59. .gitkeep
  60. ***********************************************************************************
  61. 把本地项目托管到码云
  62. F:\A计算机\IT01项目\4.UNIAPP\uni-shop-2\static
  63. cmd
  64. 然后执行如下命令:
  65. git init
  66. git status
  67. git add .
  68. git commit -m "init project"
  69. git config --global user.email "wdfgdzx@163.com"
  70. git config --global user.name "wdfgdzx"
  71. git config --global user.password "s19911009!"
  72. 再执行git commit -m "init project"即可!
  73. ---------------------------------------------------------------------------------------------
  74. git remote add origin https://gitee.com/wdfgdzx/uniapp.git
  75. git push -u origin "master"
  76. 推到码云:::::!!!!!!!!!!毕老师讲的简单过了 我日尼玛!!!
  77. ***********************************************************************************
  78. 配置tabBar效果
  79. git checkout -b tabbar 创建分支
  80. git branch 查看分支
  81. 在pages下面右击新建页面
  82. ***********************************************************************************
  83. {
  84. "tabBar": {
  85. "list": [{
  86. "pagePath": "pages/home/home",
  87. "text": "首页",
  88. "iconPath": "static/tab_icons/home.png",
  89. "selectedIconPath": "static/tab_icons/home-active.png"
  90. }, {
  91. "pagePath": "pages/cate/cate",
  92. "text": "分类",
  93. "iconPath": "static/tab_icons/cate.png",
  94. "selectedIconPath": "static/tab_icons/cate-active.png"
  95. }, {
  96. "pagePath": "pages/cart/cart",
  97. "text": "购物车",
  98. "iconPath": "static/tab_icons/cart.png",
  99. "selectedIconPath": "static/tab_icons/cart-active.png"
  100. }, {
  101. "pagePath": "pages/my/my",
  102. "text": "我的",
  103. "iconPath": "static/tab_icons/my.png",
  104. "selectedIconPath": "static/tab_icons/my-active.png"
  105. }]
  106. },
  107. "pages": [{
  108. "path": "pages/home/home",
  109. "style": {
  110. "navigationBarTitleText": "",
  111. "enablePullDownRefresh": false
  112. }
  113. }, {
  114. "path": "pages/cate/cate",
  115. "style": {
  116. "navigationBarTitleText": "",
  117. "enablePullDownRefresh": false
  118. }
  119. }, {
  120. "path": "pages/cart/cart",
  121. "style": {
  122. "navigationBarTitleText": "",
  123. "enablePullDownRefresh": false
  124. }
  125. }, {
  126. "path": "pages/my/my",
  127. "style": {
  128. "navigationBarTitleText": "",
  129. "enablePullDownRefresh": false
  130. }
  131. }],
  132. "globalStyle": {
  133. "navigationBarTextStyle": "black",
  134. "navigationBarTitleText": "uni-app",
  135. "navigationBarBackgroundColor": "#F8F8F8",
  136. "backgroundColor": "#F8F8F8",
  137. "app-plus": {
  138. "background": "#efeff4"
  139. }
  140. }
  141. }
  142. ***********************************************************************************
  143. "selectedColor": "#C00000",
  144. ***********************************************************************************
  145. pages下面是重点,如果看不到记得删除index也就是首页,牛批呀 我的哥哥
  146. ***********************************************************************************
  147. 提交与合并
  148. git add .
  149. git status
  150. git commit -m "完成tabBar"
  151. git push -u origin "tabbar"
  152. git checkout master
  153. git merge tabbar
  154. git push
  155. git branch
  156. git branch -d tabbar 删除本地分支
  157. 3】实现首页相关的功能!!!!!!!!!!!!!!轮播图
  158. 不搞分支了,真JB麻烦
  159. ***********************************************************************************
  160. npm init -y
  161. npm i @escook/request-miniprogram
  162. ---------------------------------------------------------------------------------------------
  163. // 导入网络请求包
  164. import {
  165. $http
  166. } from '@escook/request-miniprogram'
  167. uni.$http = $http
  168. // 请求拦截器
  169. $http.beforeRequest = function(options) {
  170. uni.showLoading({
  171. title: '数据加载中...'
  172. })
  173. }
  174. // 响应拦截器
  175. $http.afterRequest=function(){
  176. uni.hideLoading()
  177. }
  178. ***********************************************************************************
  179. 请求轮播图数据
  180. 原来是我的服务没有设置跨域导致的,我天 卧槽 沃日!!!!!!!!!!!
  181. ***********************************************************************************
  182. 我也不知道怎么折腾的,反正更新跨域后就解决了,哈哈哈哈!!!!
  183. onLoad() {
  184. // 加载的时候就调用方法
  185. this.selectList()
  186. },
  187. methods: {
  188. selectList() {
  189. uni.$http.post("/document/list_page", this.sendData).then(res => {
  190. console.log(res)
  191. })
  192. }
  193. }
  194. 至此,就实现了VUE类似的开发,但是可以运行N+个平台,卧槽 牛批!!!!!!!!!!!!!
  195. ***********************************************************************************
  196. selectList() {
  197. uni.$http.post("/document/list_page", this.sendData).then(res => {
  198. // console.log(res)
  199. if (res.data.code === "200") {
  200. this.list = res.data.object.data
  201. } else {
  202. return uni.showToast({
  203. title: '数据请求失败',
  204. duration: 1500,
  205. icon: 'none'
  206. })
  207. }
  208. })
  209. }
  210. h5 app 小程序 浏览器 皆可以
  211. ***********************************************************************************
  212. usw可以快速生成轮播图:
  213. <template>
  214. <view>
  215. <swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true"
  216. style="height: 330rpx;">
  217. <!-- 循环渲染item项目 -->
  218. <swiper-item v-for="item in list" :key="item.id">
  219. <view style="width: 100%;height: 100%;">
  220. <image :src="item.url" style="width: 100%;height: 100%;"></image>
  221. </view>
  222. </swiper-item>
  223. </swiper>
  224. </view>
  225. </template>
  226. <script>
  227. export default {
  228. data() {
  229. return {
  230. // list集合
  231. list: [],
  232. sendData: {
  233. currentPage: 1,
  234. pageSize: 10,
  235. total: 10
  236. }
  237. };
  238. },
  239. onLoad() {
  240. // 加载的时候就调用方法
  241. this.selectList()
  242. },
  243. methods: {
  244. selectList() {
  245. uni.$http.post("/document/list_page", this.sendData).then(res => {
  246. // console.log(res)
  247. if (res.data.code === "200") {
  248. this.list = res.data.object.data
  249. } else {
  250. return uni.showToast({
  251. title: '数据请求失败',
  252. duration: 1500,
  253. icon: 'none'
  254. })
  255. }
  256. })
  257. }
  258. }
  259. }
  260. </script>
  261. <style lang="scss">
  262. </style>
  263. 4】配置小程序分包,万众则归一!!!!!!!!!!!!!!!!!!
  264. 先建立subpkg目录
  265. 然后再pages.json里配置下
  266. "subPackages": [{
  267. "root": "subpkg",
  268. "pages": [{
  269. "path": "goods_detail/goods_detail",
  270. "style": {}
  271. }]
  272. }],
  273. ---------------------------------------------------------------------------------------------
  274. 然后手动到subpkg下新建页面就行了,弹出的页面中注意选择分包名称,完成OVER
  275. 5】点击轮播图,跳转商品详情页的功能
  276. <template>
  277. <view>
  278. <swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true"
  279. style="height: 330rpx;">
  280. <!-- 循环渲染item项目 -->
  281. <swiper-item v-for="item in list" :key="item.id">
  282. <navigator style="width: 100%;height: 100%;" :url="'/subpkg/goods_detail/goods_detail?id='+item.id">
  283. <image :src="item.url" style="width: 100%;height: 100%;"></image>
  284. </navigator>
  285. </swiper-item>
  286. </swiper>
  287. </view>
  288. </template>
  289. ---------------------------------------------------------------------------------------------
  290. 这就完事了,到详情页,有id参数值
  291. 6】封装uni.$showMsg(0方法
  292. 因为当调用失败的时候,每次都要写uni.showToast方法,非常麻烦,所以要封装!!!!
  293. ---------------------------------------------------------------------------------------------
  294. // 封装一个报错的方法
  295. uni.$message = function(title = "数据请求失败!", duration = 1500) {
  296. uni.showToast({
  297. title,
  298. duration,
  299. icon: 'none'
  300. })
  301. }
  302. ---------------------------------------------------------------------------------------------
  303. selectList() {
  304. uni.$http.post("/document/list_page", this.sendData).then(res => {
  305. // console.log(res)
  306. if (res.data.code === "200") {
  307. this.list = res.data.object.data
  308. return uni.$message("数据请求成功")
  309. } else {
  310. return uni.$message()
  311. }
  312. })
  313. }
  314. 7】实现分类导航区域
  315. selectNavList() { // 请求分类图
  316. uni.$http.post("/kind/list_page", this.sendData).then(res => {
  317. console.log(res)
  318. if (res.data.code === "200") {
  319. this.navList = res.data.object.data // 注意是navList的赋值了
  320. return uni.$message("数据请求成功!")
  321. } else {
  322. return uni.$message()
  323. }
  324. })
  325. }
  326. ---------------------------------------------------------------------------------------------
  327. <!-- 分类导航区域 -->
  328. <view style="display: flex;justify-content: space-around;margin: 15px 0;">
  329. <view v-for="item in navList" :key="item.id" @click="navClick(item)">
  330. <image :src="item.urlIcon" style="width: 128rpx;height: 140rpx;"></image>
  331. <view style="font-size: 24rpx;margin-left: 24rpx;">{{item.type}}</view>
  332. </view>
  333. </view>
  334. ---------------------------------------------------------------------------------------------
  335. 点击第一项,实现分类页面:
  336. navClick(item) {
  337. // console.log(item)
  338. if (item.type === "点分类") {
  339. uni.switchTab({ // !!!!!!!!!!!!!这是重点
  340. url: '/pages/cate/cate'
  341. })
  342. }
  343. },
  344. 8】获取楼层数据并渲染楼层的标题
  345. <view style="">
  346. <view v-for="(item,index) in floorList" :key="index">
  347. <!-- 楼层标题 -->
  348. <view style="height: 60rpx;width: 100%;display: flex;color: crimson;font-size: 36rpx;">
  349. {{item.floor_title}}
  350. </view>
  351. </view>
  352. </view>
  353. 9】渲染楼层里面的图片
  354. <!-- 左侧大图 mode="widthFix" 如果图片本身合规的话-->
  355. <view>
  356. <image :src="item.product_list[0].url" style="width: 232rpx;"></image>
  357. </view>
  358. ---------------------------------------------------------------------------------------------
  359. <!-- 楼层数据 -->
  360. <view style="">
  361. <view v-for="(item,index) in floorList" :key="index">
  362. <!-- 楼层标题 -->
  363. <view
  364. style="height: 60rpx;width: 100%;display: flex;color: crimson;font-size: 36rpx;padding-left: 10rpx;">
  365. {{item.floor_title}}
  366. </view>
  367. <!-- 楼层的图片区域 -->
  368. <view style="display: flex;padding-left: 10rpx;">
  369. <!-- 左侧大图 mode="widthFix" 如果图片本身合规的话-->
  370. <view>
  371. <image :src="item.product_list[0].url" style="width: 232rpx;"></image>
  372. </view>
  373. <!-- 右侧4小图 -->
  374. <view style="display: flex;flex-wrap: wrap;justify-content: space-around;">
  375. <view v-for="(subItem,subIndex) in item.product_list" :key="subIndex" v-if="subIndex!==0">
  376. <image :src="subItem.url" style="width: 232rpx;height: 236rpx;"></image>
  377. </view>
  378. </view>
  379. </view>
  380. </view>
  381. </view>
  382. 10】点击楼层图片跳转到商品列表页
  383. 在分包里新建goods_list页面,感觉用了uniapp好清晰呀,就一个vue文件,哈哈哈哈!!!!!!
  384. res.data.object.data.forEach(item => { // 挂载上页面属性
  385. item.navUrl = "/subpkg/goods_list/goods_list?query=" + item.kind
  386. })
  387. ---------------------------------------------------------------------------------------------
  388. <navigator :url="item.product_list[0].navUrl">
  389. <image :src="item.product_list[0].url" style="width: 232rpx;"></image>
  390. </navigator>
  391. ---------------------------------------------------------------------------------------------
  392. <view style="display: flex;flex-wrap: wrap;justify-content: space-around;">
  393. <navigator v-for="(subItem,subIndex) in item.product_list" :key="subIndex" v-if="subIndex!==0"
  394. :url="subItem.navUrl">
  395. <image :src="subItem.url" style="width: 232rpx;height: 236rpx;"></image>
  396. </navigator>
  397. </view>
  398. 11】分支的合并与提交
  399. 对于我来说就是规整下项目,存下百度网盘!!!!!!!!!!!!!!
  1. 12108集 创建cate分支以及分类页面的编译模式
  2. 微信小程序里点击小程序模式,新建模式,选择cate页面,这样方便开发!!!!
  3. 13109集初始化分类区域的页面布局
  4. 滑动区域
  5. ***************************************************************************************
  6. 主要是通过scroll-view scroll-y="true" style="height: 300px;width: 120px;"
  7. 加样式实现:
  8. ***************************************************************************************
  9. 占满整个屏幕的高度:
  10. 自带的方法拿到屏幕高度...
  11. ---------------------------------------------------------------------------------------
  12. windowHeight
  13. ---------------------------------------------------------------------------------------
  14. onLoad() {
  15. const sysInfo = uni.getSystemInfoSync();
  16. // console.log(sysInfo)
  17. this.windowsHeight = sysInfo.windowHeight
  18. }
  19. ---------------------------------------------------------------------------------------
  20. :style="{height:windowsHeight+'px',width:'120px'}" // 动态属性绑定
  21. ---------------------------------------------------------------------------------------
  22. .leftView {
  23. background-color: #F7F7F7;
  24. line-height: 60px;
  25. text-align: center;
  26. font-size: 12px;
  27. &.active {
  28. background-color: #FFFFFF;
  29. position: relative;
  30. &::before {
  31. content: ' ';
  32. display: block;
  33. width: 3px;
  34. height: 30px;
  35. background-color: #C00000;
  36. position: absolute;
  37. top: 50%;
  38. left: 0%;
  39. transform: translateY(-50%)
  40. }
  41. }
  42. }
  43. ---------------------------------------------------------------------------------------
  44. 有时候不得不用css,哎
  45. 14】获取并渲染一级分类列表数据
  46. 实操的时候,一级分类需要从mysql group by 下。然后分类肯定有很多吗....
  47. 15】渲染二级和三级分类类表:
  48. <!-- 右侧滑动区域 -->
  49. <scroll-view scroll-y="true" :style="{height:windowsHeight+'px'}">
  50. <view style="font-size: 12px;font-weight: bold;text-align: center;padding: 15px 0;">
  51. <!-- 按道理二级分类应该是动态的 -->
  52. / 爆款服装-2/
  53. </view>
  54. <view style="display: flex;flex-wrap: wrap;">
  55. <view v-for="item in cateListLevel2" :key="item.id"
  56. style="width: 33.33%;display: flex;flex-direction: column;justify-content: center;align-items: center;margin-bottom: 10px;">
  57. <!-- 图片 -->
  58. <image :src="item.url" style="width: 60px;height: 60px;"></image>
  59. <!-- 文本 -->
  60. <text style="font-size: 12px;">{{item.name}}</text>
  61. </view>
  62. </view>
  63. </scroll-view>
  64. 16】切换的时候滚动条的位置没有从顶部开始
  65. 解决bug:
  66. :scroll-top="scrollTop"
  67. this.scrollTop = this.scrollTop === 0 ? 0.01 : 0 // 因为不能赋值一样的
  68. ***************************************************************************************
  69. 点击图片跳转到商品类表页面:
  70. <view v-for="item in cateListLevel2" :key="item.id"
  71. style="width: 33.33%;display: flex;flex-direction: column;justify-content: center;align-items: center;margin-bottom: 10px;"
  72. @click="goGoodsList(item)">
  73. ---------------------------------------------------------------------------------------
  74. goGoodsList(item) { // 跳转到商品列表页面
  75. uni.navigateTo({
  76. url: '/subpkg/goods_list/goods_list?kind=' + item.kind // 传递分类
  77. })
  78. },
  79. 17】搜索相关的功能:自定义搜索组件、搜索建议、搜索历史
  80. 创建自定义搜索组件:
  81. ***************************************************************************************
  82. 新建components目录,新建my-search组件
  83. ---------------------------------------------------------------------------------------
  84. <template>
  85. <view>
  86. 这是自定义搜索组件
  87. </view>
  88. </template>
  89. <script>
  90. export default {
  91. name: "my-search",
  92. data() {
  93. return {
  94. };
  95. }
  96. }
  97. </script>
  98. <style lang="scss">
  99. </style>
  100. ---------------------------------------------------------------------------------------
  101. <!-- 使用自定义组件 -->
  102. <my-search></my-search>
  103. ---------------------------------------------------------------------------------------
  104. 优化组件布局
  105. <template>
  106. <view style="height: 50px;background-color: #C00000;display: flex;align-items: center;padding: 0 10px;">
  107. <view
  108. style="height: 36px;background-color: #FFFFFF;border-radius: 18px;width: 100%;display: flex;justify-content: center;align-items: center;">
  109. <!-- icon组件 -->
  110. <uni-icons type="search" size="17"></uni-icons>
  111. <text style="font-size: 15px;margin-left: 5px;">搜索</text>
  112. </view>
  113. </view>
  114. </template>
  115. <script>
  116. export default {
  117. name: "my-search",
  118. data() {
  119. return {
  120. };
  121. }
  122. }
  123. </script>
  124. <style lang="scss">
  125. </style>
  126. ---------------------------------------------------------------------------------------
  127. 解决添加搜索区域后滚动显示不全的问题:
  128. this.windowsHeight = sysInfo.windowHeight - 50
  129. ***************************************************************************************
  130. 自定义组件的形式,增加通用性:
  131. 没必要这么人性化,都能自定义,你要知道你的代码谁去用...!!!!!!!!!!!!!
  132. 用props绑定属性
  133. 动态绑定style :style="{a:'1',b:'2'}"
  134. ***************************************************************************************
  135. 为自定义组件封装click事件:
  136. <view style="height: 50px;background-color: #C00000;display: flex;align-items: center;padding: 0 10px;"
  137. @click="searchHandler">
  138. ---------------------------------------------------------------------------------------
  139. searchHandler() {
  140. console.log("-----!!!!!")
  141. this.$emit('click') // 注意这个名字和引用组件页面的@ click是一样的
  142. }
  143. ---------------------------------------------------------------------------------------
  144. <my-search @click="goSearch"></my-search>
  145. ---------------------------------------------------------------------------------------
  146. goSearch() { // 跳转搜索页
  147. console.log("外界调用")
  148. },
  149. 18】导航跳转与吸顶效果
  150. goSearch() { // 跳转搜索页 // 这才是真正有用的!!!!!!!!!!!!!!!
  151. // console.log("外界调用")
  152. uni.navigateTo({
  153. url: '/subpkg/search/search'
  154. })
  155. },
  156. ***************************************************************************************
  157. <!-- 搜索组件 -->
  158. <view style="position:sticky;top:0;z-index:999">
  159. <my-search @click="goSearch"></my-search>
  160. </view>
  161. 19】搜索建议
  162. <template>
  163. <view>
  164. <view style="background-color: #C00000;position:sticky;top:0;z-index:999">
  165. <uni-search-bar @input="input" :radius="100" cancelButton="none" placeholder="请输入搜索内容">
  166. </uni-search-bar>
  167. </view>
  168. </view>
  169. </template>
  170. <script>
  171. export default {
  172. data() {
  173. return {
  174. };
  175. },
  176. methods: {
  177. input(e) {
  178. console.log(e)
  179. }
  180. }
  181. }
  182. </script>
  183. <style lang="scss">
  184. </style>
  185. ***************************************************************************************
  186. 搜索框自动获取焦点:
  187. uni_modules----uni-search-bar---componets---uni-search-bar.vue
  188. 修改里面的data
  189. data() {
  190. return {
  191. show: true,
  192. showSync: true, // !!!!!!!!!!!!!!这里
  193. searchVal: ''
  194. }
  195. },
  196. ***************************************************************************************
  197. 处理下搜索框的防抖,防止无效的请求
  198. <script>
  199. export default {
  200. data() {
  201. return {
  202. timer: null, //延时器
  203. keyWord: ''
  204. };
  205. },
  206. methods: {
  207. input(e) {
  208. // console.log(e)
  209. clearTimeout(this.timer)
  210. this.timer = setTimeout(() => {
  211. // console.log(e)
  212. this.keyWord = e // 赋值关键词
  213. }, 500)
  214. }
  215. }
  216. }
  217. </script>
  1. 20】关键词查询建议列表118集合
  2. selectSearchList() {
  3. // 搜索关键词是否为空
  4. if (this.keyWord.length === 0) {
  5. this.searchResultList = []
  6. return false
  7. }
  8. this.sendData.kind = this.keyWord
  9. uni.$http.post("/document/list_page", this.sendData).then(res => {
  10. console.log(res)
  11. if (res.data.code === "200") {
  12. this.searchResultList = res.data.object.data
  13. } else {
  14. return uni.$message()
  15. }
  16. })
  17. }
  18. *******************************************************************************************
  19. 21】点击跳转详情页
  20. goDetail(item) { // 跳转详情
  21. uni.navigateTo({
  22. url: "/subpkg/goods_detail/goods_detail?id=" + item.id
  23. })
  24. },
  25. *******************************************************************************************
  26. 22】渲染搜索历史
  27. <view style="padding: 0 5px;">
  28. <!-- 标题区域 -->
  29. <view
  30. style="display: flex;justify-content: space-between;height: 40px;align-items: center;font-size: 13px;border-bottom: 1px solid lightgray;">
  31. <text>搜索历史</text>
  32. <uni-icons type="trash" size="17"></uni-icons>
  33. </view>
  34. <!-- 列表区域 -->
  35. <view style="display: flex;flex-wrap: wrap;">
  36. <uni-tag v-for="(item,index) in historyList" :key="index" :text="item"
  37. style="margin-top: 5px;margin-right: 5px;"></uni-tag>
  38. </view>
  39. </view>
  40. *******************************************************************************************
  41. 按需展示!!!!!!!!!!!!!!!!!
  42. <!-- 搜索建议列表 -->
  43. <view style="padding: 0 5px;" v-if="searchResultList.length!==0">
  44. <view v-for="item in searchResultList" :key="item.id" @click="goDetail(item)"
  45. style="display: flex;align-items: center;justify-content: space-between;font-size: 12px;padding: 13px 0;border-bottom: 1px solid lightgray;">
  46. <view style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;margin-right: 3px;">
  47. {{item.kind}}+{{item.name}}
  48. </view>
  49. <uni-icons type="arrowright" size="16"></uni-icons>
  50. </view>
  51. </view>
  52. <!-- 搜索历史 -->
  53. <view style="padding: 0 5px;" v-else>
  54. <!-- 标题区域 -->
  55. <view
  56. style="display: flex;justify-content: space-between;height: 40px;align-items: center;font-size: 13px;border-bottom: 1px solid lightgray;">
  57. <text>搜索历史</text>
  58. <uni-icons type="trash" size="17"></uni-icons>
  59. </view>
  60. <!-- 列表区域 -->
  61. <view style="display: flex;flex-wrap: wrap;">
  62. <uni-tag v-for="(item,index) in historyList" :key="index" :text="item"
  63. style="margin-top: 5px;margin-right: 5px;"></uni-tag>
  64. </view>
  65. </view>
  66. 23】处理搜索关键词
  67. saveHistory() { // 保存搜索历史记录
  68. this.historyList.push(this.keyWord)
  69. },
  70. *******************************************************************************************
  71. 但是存在排序与重复的问题:解决bug
  72. computed: {
  73. betterHistoryList() {
  74. return [...this.historyList].reverse()
  75. }
  76. },
  77. *******************************************************************************************
  78. <view style="display: flex;flex-wrap: wrap;">
  79. <uni-tag v-for="(item,index) in betterHistoryList" :key="index" :text="item"
  80. style="margin-top: 5px;margin-right: 5px;"></uni-tag>
  81. </view>
  82. *******************************************************************************************
  83. 解决搜索关键词重复问题
  84. saveHistory() { // 保存搜索历史记录
  85. const set = new Set(this.historyList)
  86. set.delete(this.keyWord) // 先移出历史
  87. set.add(this.keyWord) // 再追加新的
  88. this.historyList = Array.from(set)
  89. },
  90. *******************************************************************************************
  91. 搜索历史记录持久存储到本地
  92. onLoad() {
  93. this.historyList = JSON.parse(uni.getStorageSync('keyWord') || '[]')
  94. },
  95. methods: {
  96. saveHistory() { // 保存搜索历史记录
  97. const set = new Set(this.historyList)
  98. set.delete(this.keyWord) // 先移出历史
  99. set.add(this.keyWord) // 再追加新的
  100. this.historyList = Array.from(set)
  101. uni.setStorageSync("keyWord", JSON.stringify(this.historyList))
  102. },
  103. 24】清空历史搜索记录
  104. cleanHistory() { // 清空历史记录
  105. this.historyList = []
  106. uni.setStorageSync("keyWord", '[]')
  107. },
  108. 25】点击搜索历史,跳转商品列表页面
  109. <!-- 列表区域 -->
  110. <view style="display: flex;flex-wrap: wrap;">
  111. <uni-tag v-for="(item,index) in betterHistoryList" :key="index" :text="item" @click="goGoodsList(item)"
  112. style="margin-top: 5px;margin-right: 5px;"></uni-tag>
  113. </view>
  114. *******************************************************************************************
  115. goGoodsList(keyWord) {
  116. uni.navigateTo({
  117. url: "/subpkg/goods_list/goods_list?kind=" + keyWord
  118. })
  119. },
  120. 25125集商品列表页面的开发
  121. <template>
  122. <view>
  123. <!-- 外层容器 -->
  124. <view>
  125. <!-- item项 -->
  126. <block v-for="item in list" :key="item.id">
  127. <view style="display: flex;padding: 10px 5px;border-bottom: 1px solid lightgray;">
  128. <!-- 左侧盒子 -->
  129. <view style="margin-right: 5px;">
  130. <image :src="item.url || defaultImage" style="width: 100px;height: 100px;display: block;">
  131. </image>
  132. </view>
  133. <!-- 右侧盒子 -->
  134. <view style="display: flex;flex-direction: column;justify-content: space-between;">
  135. <!-- 商品名称 -->
  136. <view style="font-size: 13px;">{{item.name}}</view>
  137. <!-- 商品价格 -->
  138. <view style="color: #C00000;font-size: 16px;">¥ {{item.price}}</view>
  139. </view>
  140. </view>
  141. </block>
  142. </view>
  143. </view>
  144. </template>
  145. <script>
  146. export default {
  147. data() {
  148. return {
  149. list: [],
  150. defaultImage: 'http://wdfgdzx.top:8000/document/a5dd6d1d1c5c45dd98c6017b1821acb8.jpg', // 默认图片地址
  151. sendData: {
  152. currentPage: 1,
  153. pageSize: 10,
  154. total: 10
  155. }
  156. };
  157. }, // 从上个页面获取参数,获取不到默认是空
  158. onLoad(options) {
  159. // console.log(options)
  160. this.sendData.kind = options.kind || '' // 从上个页面获取参数,获取不到默认是空
  161. this.selectList()
  162. },
  163. methods: {
  164. selectList() {
  165. uni.$http.post("/document/list_page", this.sendData).then(res => {
  166. // console.log(res)
  167. if (res.data.code = "200") {
  168. this.list = res.data.object.data
  169. this.sendData.total = res.data.object.total
  170. } else {
  171. return uni.$message()
  172. }
  173. })
  174. }
  175. }
  176. }
  177. </script>
  178. <style lang="scss">
  179. </style>
  180. 26】把商品item项分装成自定义组件
  181. 在components中创建my-goods组件:
  182. <view>
  183. <!-- item项 -->
  184. <block v-for="item in list" :key="item.id">
  185. <my-goods :item="item"></my-goods> <!-- 注意:item和接受页面名字是一样的 -->
  186. </block>
  187. </view>
  188. *******************************************************************************************
  189. <template>
  190. <!-- 外层容器 -->
  191. <view>
  192. <view style="display: flex;padding: 10px 5px;border-bottom: 1px solid lightgray;">
  193. <!-- 左侧盒子 -->
  194. <view style="margin-right: 5px;">
  195. <image :src="item.url || defaultImage" style="width: 100px;height: 100px;display: block;">
  196. </image>
  197. </view>
  198. <!-- 右侧盒子 -->
  199. <view style="display: flex;flex-direction: column;justify-content: space-between;">
  200. <!-- 商品名称 -->
  201. <view style="font-size: 13px;">{{item.name}}</view>
  202. <!-- 商品价格 -->
  203. <view style="color: #C00000;font-size: 16px;">¥ {{item.price}}</view>
  204. </view>
  205. </view>
  206. </view>
  207. </template>
  208. <script>
  209. export default {
  210. name: "my-goods",
  211. props: {
  212. item: { // 这个名字和页面里使用的名字是一致的,注意!!!!!!!!!!!!
  213. type: Object,
  214. default: {}
  215. }
  216. },
  217. data() {
  218. return {
  219. defaultImage: 'http://wdfgdzx.top:8000/document/a5dd6d1d1c5c45dd98c6017b1821acb8.jpg', // 默认图片地址
  220. };
  221. }
  222. }
  223. </script>
  224. <style lang="scss">
  225. </style>
  226. 27】使用过滤器处理商品价格
  227. <template>
  228. <!-- 外层容器 -->
  229. <view>
  230. <view style="display: flex;padding: 10px 5px;border-bottom: 1px solid lightgray;">
  231. <!-- 左侧盒子 -->
  232. <view style="margin-right: 5px;">
  233. <image :src="item.url || defaultImage" style="width: 100px;height: 100px;display: block;">
  234. </image>
  235. </view>
  236. <!-- 右侧盒子 -->
  237. <view style="display: flex;flex-direction: column;justify-content: space-between;">
  238. <!-- 商品名称 -->
  239. <view style="font-size: 13px;">{{item.name}}</view>
  240. <!-- 商品价格 -->
  241. <view style="color: #C00000;font-size: 16px;">¥ {{item.price | toFixed}}</view>
  242. </view>
  243. </view>
  244. </view>
  245. </template>
  246. <script>
  247. export default {
  248. name: "my-goods",
  249. props: {
  250. item: { // 这个名字和页面里使用的名字是一致的,注意!!!!!!!!!!!!
  251. type: Object,
  252. default: {}
  253. }
  254. },
  255. data() {
  256. return {
  257. defaultImage: 'http://wdfgdzx.top:8000/document/a5dd6d1d1c5c45dd98c6017b1821acb8.jpg', // 默认图片地址
  258. };
  259. },
  260. filters: {
  261. toFixed(num) {
  262. return Number(num).toFixed(2)
  263. }
  264. }
  265. }
  266. </script>
  267. <style lang="scss">
  268. </style>
  269. 28】实现下拉加载更多
  270. {
  271. "path": "goods_list/goods_list",
  272. "style": {
  273. "onReachBottomDistance": 150
  274. }
  275. },
  276. *******************************************************************************************
  277. onReachBottom() {
  278. this.sendData.currentPage = this.sendData.currentPage + 1 // 页面+1后 调用selectList方法
  279. this.selectList()
  280. },
  281. methods: {
  282. selectList() {
  283. uni.$http.post("/document/list_page", this.sendData).then(res => {
  284. // console.log(res)
  285. if (res.data.code = "200") {
  286. this.list = [...this.list, ...res.data.object.data] // 新旧数据拼接
  287. this.sendData.total = res.data.object.total
  288. } else {
  289. return uni.$message()
  290. }
  291. })
  292. }
  293. }
  294. *******************************************************************************************
  295. 节流阀的实现
  296. *******************************************************************************************
  297. 数据是否加载完毕实现
  298. if (this.sendData.currentPage * this.sendData.pageSize >= this.sendData.total) {
  299. return uni.$message("数据加载完毕...")
  300. }
  301. 29】实现下拉刷新
  302. {
  303. "path": "goods_list/goods_list",
  304. "style": {
  305. "onReachBottomDistance": 150,
  306. "enablePullDownRefresh": true,
  307. "backgroundColor": "#f8f8f8"
  308. }
  309. },
  310. *******************************************************************************************
  311. onPullDownRefresh() {
  312. this.sendData.currentPage = 1
  313. this.sendData.total = 0
  314. this.loadingFlag = false
  315. this.list = []
  316. this.selectList(() => uni.stopPullDownRefresh())
  317. },
  318. *******************************************************************************************
  319. selectList(cb) {
  320. this.loadingFlag = true // 打开节流阀
  321. uni.$http.post("/document/list_page", this.sendData).then(res => {
  322. // console.log(res)
  323. this.loadingFlag = false // 关闭节流阀
  324. cb && cb()
  325. if (res.data.code = "200") {
  326. this.list = [...this.list, ...res.data.object.data] // 新旧数据拼接
  327. this.sendData.total = res.data.object.total
  328. } else {
  329. return uni.$message()
  330. }
  331. })
  332. }
  333. *******************************************************************************************
  334. UPDATE document SET preview=REPLACE(preview,'localhost','wdfgdzx.top');
  335. UPDATE document SET url=REPLACE(url,'localhost','wdfgdzx.top');
  336. *******************************************************************************************
  337. 30】点击商品item跳转到商品详情页
  338. <!-- item项 -->
  339. <view v-for="item in list" :key="item.id" @click="goDetail(item)">
  340. <my-goods :item="item"></my-goods> <!-- 注意:item和接受页面名字是一样的 -->
  341. </view>
  342. *******************************************************************************************
  343. goDetail(item) { // 去详情页面
  344. uni.navigateTo({
  345. url: "/subpkg/goods_detail/goods_detail?id=" + item.id
  346. })
  347. },
  348. 31】商品详情页的开发
  349. <script>
  350. export default {
  351. data() {
  352. return {
  353. goodsInfo: {}
  354. };
  355. },
  356. onLoad(options) {
  357. const id = options.id
  358. this.selectGoods(id)
  359. },
  360. methods: {
  361. selectGoods(id) {
  362. uni.$http.post("/document/select_id/" + id).then(res => {
  363. // console.log(res)
  364. if (res.data.code = "200") {
  365. this.goodsInfo = res.data.object
  366. } else {
  367. return uni.$message()
  368. }
  369. })
  370. }
  371. }
  372. }
  373. </script>
  374. *******************************************************************************************
  375. 商品详情页的UI结构
  376. <view>
  377. <!-- 商品详情页 -->
  378. <swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true"
  379. style="height: 750rpx;">
  380. <swiper-item v-for="(item,index) in goodsInfo.imageList" :key="index">
  381. <image :src="item" style="width: 100%;height: 100%;"></image>
  382. </swiper-item>
  383. </swiper>
  384. </view>
  385. *******************************************************************************************
  386. 轮播图预览效果!!!!!!!!!!!!!!!!!!!!!!!!
  387. <template>
  388. <view>
  389. <!-- 商品详情页 -->
  390. <swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true"
  391. style="height: 750rpx;">
  392. <swiper-item v-for="(item,index) in goodsInfo.imageList" :key="index">
  393. <image :src="item" style="width: 100%;height: 100%;" @click="preview(index)"></image>
  394. </swiper-item>
  395. </swiper>
  396. </view>
  397. </template>
  398. <script>
  399. export default {
  400. data() {
  401. return {
  402. goodsInfo: {
  403. imageList: []
  404. }
  405. };
  406. },
  407. onLoad(options) {
  408. const id = options.id
  409. this.selectGoods(id)
  410. },
  411. methods: {
  412. preview(index) { // 预览
  413. uni.previewImage({
  414. current: index,
  415. urls: this.goodsInfo.imageList.map(v => v)
  416. })
  417. },
  418. selectGoods(id) {
  419. uni.$http.post("/document/select_id/" + id).then(res => {
  420. // console.log(res)
  421. if (res.data.code = "200") {
  422. this.goodsInfo = res.data.object
  423. this.goodsInfo.imageList = res.data.object.imageList.split("&&&")
  424. // console.log(this.goodsInfo.imageList)
  425. } else {
  426. return uni.$message()
  427. }
  428. })
  429. }
  430. }
  431. }
  432. </script>
  433. <style lang="scss">
  434. </style>
  1. 32】渲染美化商品信息区域 136
  2. <view>
  3. <!-- 商品价格 -->
  4. <view>
  5. {{goodsInfo.price}}
  6. </view>
  7. <!-- 信息主题区域 -->
  8. <view>
  9. <!-- 商品名称 -->
  10. <view>
  11. {{goodsInfo.name}}
  12. </view>
  13. <!-- 收藏 -->
  14. <view>
  15. <uni-icons type="star" size="18" color="gray"></uni-icons>
  16. <text>收藏</text>
  17. </view>
  18. </view>
  19. <!-- 运费区域 -->
  20. <view>
  21. 快递:免运费
  22. </view>
  23. </view>
  24. *************************************************************************************************
  25. 美化:
  26. <!-- 商品信息区域 -->
  27. <view style="padding: 10px;padding-right: 0;">
  28. <!-- 商品价格 -->
  29. <view style="color: #C00000;font-size: 18px;margin: 10px 0;">
  30. ¥ {{goodsInfo.price}}
  31. </view>
  32. <!-- 信息主题区域 -->
  33. <view style="display: flex;justify-content: space-between;">
  34. <!-- 商品名称 -->
  35. <view style="font-size: 13px;margin-right: 10px">
  36. {{goodsInfo.name}}
  37. </view>
  38. <!-- 收藏 -->
  39. <view style="width: 120px;font-size: 12px;display: flex;flex-direction: column;align-items: center;
  40. justify-content: center;border-left: 1px solid lightgray;color: gray;">
  41. <uni-icons type="star" size="18" color="gray"></uni-icons>
  42. <text>收藏</text>
  43. </view>
  44. </view>
  45. <!-- 运费区域 -->
  46. <view style="font-size: 12px;color: gray;margin: 10px 0;">
  47. 快递:免运费
  48. </view>
  49. </view>
  50. 33】渲染商品详情数据
  51. <!-- 商品详情图片区域 -->
  52. <view style="display: flex;justify-content: center;">
  53. <image src='https://wdfgdzx.top/document/pre_see/00f3be647229489887b4fa6a9f35459b.jpg' style="width: 100%;">
  54. </image>
  55. </view>
  56. *************************************************************************************************
  57. .webp替换为jpg即可在iOS上显示
  58. *************************************************************************************************
  59. 解决商品价格显示闪烁问题:
  60. <view v-if="goodsInfo.name">
  61. 34】渲染商品底部的导航区域
  62. <!-- 底部导航区域 -->
  63. <view style="position: fixed;bottom: 0;left:0;width: 100%;">
  64. <uni-goods-nav :fill="true" :options="options" :buttonGroup="buttonGroup" @click="onClick"></uni-goods-nav>
  65. </view>
  66. *************************************************************************************************
  67. options: [{
  68. icon: 'headphones',
  69. text: '客户'
  70. }, {
  71. icon: 'shop',
  72. text: '店铺',
  73. info: 2,
  74. backgroundColor: '#007aff',
  75. color: 'red'
  76. }, {
  77. icon: 'cart',
  78. text: '购物车',
  79. info: 2
  80. }],
  81. buttonGroup: [{
  82. text: '加入购物车',
  83. backgroundColor: '#ff0000',
  84. color: '#fff'
  85. }, {
  86. text: '立即购买',
  87. backgroundColor: '#ffa200',
  88. color: '#fff'
  89. }]
  90. *************************************************************************************************
  91. 除了说一句:帅!!!!!!!!!!!!!!!!!!!!还能说什么
  92. *************************************************************************************************
  93. 点击购物车,跳转到购物车页面
  94. onClick(e) { //点击
  95. // console.log(e)
  96. if (e.content.text === "购物车") {
  97. uni.switchTab({
  98. url: "/pages/cart/cart"
  99. })
  100. }
  101. },
  102. 35140集加入购物车store.js,初始化vuex
  103. import Vue from 'vue'
  104. import Vuex from 'vuex'
  105. Vue.use(Vuex)
  106. const store = new Vuex.Store({
  107. modules: {
  108. }
  109. })
  110. export default store
  111. *************************************************************************************************
  112. // #ifndef VUE3
  113. import Vue from 'vue'
  114. import App from './App'
  115. import store from '@/store/store.js'
  116. // 导入网络请求包
  117. import {
  118. $http
  119. } from '@escook/request-miniprogram'
  120. uni.$http = $http
  121. // 请求的根路径
  122. $http.baseUrl = "https://localhost"
  123. //$http.baseUrl = "https://wdfgdzx.top"
  124. // 请求开始之前做一些事情
  125. $http.beforeRequest = function(options) {
  126. uni.showLoading({
  127. title: "数据加载中..."
  128. })
  129. }
  130. // 请求完成之后做一些事情
  131. $http.afterRequest = function() {
  132. uni.hideLoading()
  133. }
  134. // 封装一个报错的方法
  135. uni.$message = function(title = "数据请求失败!", duration = 1500) {
  136. uni.showToast({
  137. title,
  138. duration,
  139. icon: 'none'
  140. })
  141. }
  142. Vue.config.productionTip = false
  143. App.mpType = 'app'
  144. const app = new Vue({
  145. ...App,
  146. store
  147. })
  148. app.$mount()
  149. // #endif
  150. // #ifdef VUE3
  151. import {
  152. createSSRApp
  153. } from 'vue'
  154. import App from './App.vue'
  155. export function createApp() {
  156. const app = createSSRApp(App)
  157. return {
  158. app
  159. }
  160. }
  161. // #endif
  162. *************************************************************************************************
  163. 购物车数据全局存储
  164. export default {
  165. namespaced: true,
  166. state: () => ({
  167. // 包含6个属性 id name price count image state
  168. cart: []
  169. }),
  170. mutations: {},
  171. getters: {}
  172. }
  173. ------------------------------------------------------------------------------------------------
  174. import Vue from 'vue'
  175. import Vuex from 'vuex'
  176. import moduleCart from '@/store/cart.js'
  177. Vue.use(Vuex)
  178. const store = new Vuex.Store({
  179. modules: {
  180. 'm_cart': moduleCart // 关联购物车示例
  181. }
  182. })
  183. export default store
  184. 36】实现加入购物车功能
  185. 辅助函数:
  186. import {
  187. mapState
  188. } from 'vuex'
  189. export default {
  190. computed: {
  191. ...mapState('m_cart', [])
  192. },
  193. *************************************************************************************************
  194. ...mapMutations('m_cart', ['addCart']), // 使用全局存储方法
  195. buttonClick(e) {
  196. // console.log(e)
  197. if (e.content.text === "加入购物车") {
  198. const goods = {
  199. id: this.goodsInfo.id,
  200. name: this.goodsInfo.name,
  201. price: this.goodsInfo.price,
  202. count: 1,
  203. image: this.goodsInfo.image,
  204. state: true // 默认是勾选的
  205. }
  206. this.addCart(goods)
  207. }
  208. },
  209. *************************************************************************************************
  210. <template>
  211. <view v-if="goodsInfo.name" style="padding-bottom: 50px;">
  212. <!-- 商品详情页 -->
  213. <!-- 轮播图区域 -->
  214. <swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true"
  215. style="height: 750rpx;">
  216. <swiper-item v-for="(item,index) in goodsInfo.imageList" :key="index">
  217. <image :src="item" style="width: 100%;height: 100%;" @click="preview(index)"></image>
  218. </swiper-item>
  219. </swiper>
  220. <!-- 商品信息区域 -->
  221. <view style="padding: 10px;padding-right: 0;">
  222. <!-- 商品价格 -->
  223. <view style="color: #C00000;font-size: 18px;margin: 10px 0;">
  224. ¥ {{goodsInfo.price}}
  225. </view>
  226. <!-- 信息主题区域 -->
  227. <view style="display: flex;justify-content: space-between;">
  228. <!-- 商品名称 -->
  229. <view style="font-size: 13px;margin-right: 10px">
  230. {{goodsInfo.name}}
  231. </view>
  232. <!-- 收藏 -->
  233. <view style="width: 120px;font-size: 12px;display: flex;flex-direction: column;align-items: center;
  234. justify-content: center;border-left: 1px solid lightgray;color: gray;">
  235. <uni-icons type="star" size="18" color="gray"></uni-icons>
  236. <text>收藏</text>
  237. </view>
  238. </view>
  239. <!-- 运费区域 -->
  240. <view style="font-size: 12px;color: gray;margin: 10px 0;">
  241. 快递:免运费
  242. </view>
  243. </view>
  244. <!-- 商品详情图片区域 按道理应该是另一个list集合,不和轮播图的问题-->
  245. <view>
  246. <view v-for="(item,index) in goodsInfo.imageList" :key="index"
  247. style="display: flex;justify-content: center;flex-wrap: wrap;">
  248. <image :src="item" style="width: 100%;">
  249. </image>
  250. </view>
  251. </view>
  252. <!-- 底部导航区域 -->
  253. <view style="position: fixed;bottom: 0;left:0;width: 100%;">
  254. <uni-goods-nav :fill="true" :options="options" :buttonGroup="buttonGroup" @click="onClick"
  255. @buttonClick="buttonClick"></uni-goods-nav>
  256. </view>
  257. </view>
  258. </template>
  259. <script>
  260. import {
  261. mapState,
  262. mapMutations
  263. } from 'vuex'
  264. export default {
  265. computed: {
  266. ...mapState('m_cart', [])
  267. },
  268. data() {
  269. return {
  270. goodsInfo: {
  271. imageList: []
  272. },
  273. options: [
  274. // {
  275. // icon: 'headphones',
  276. // text: '客服'
  277. // },
  278. {
  279. icon: 'shop',
  280. text: '店铺',
  281. // info: 2,
  282. backgroundColor: '#007aff',
  283. color: 'red'
  284. }, {
  285. icon: 'cart',
  286. text: '购物车',
  287. info: 2
  288. }
  289. ],
  290. buttonGroup: [{
  291. text: '加入购物车',
  292. backgroundColor: '#ff0000',
  293. color: '#fff'
  294. }, {
  295. text: '立即购买',
  296. backgroundColor: '#ffa200',
  297. color: '#fff'
  298. }]
  299. };
  300. },
  301. onLoad(options) {
  302. const id = options.id
  303. this.selectGoods(id)
  304. },
  305. methods: {
  306. ...mapMutations('m_cart', ['addCart']), // 使用全局存储方法
  307. buttonClick(e) {
  308. // console.log(e)
  309. if (e.content.text === "加入购物车") {
  310. const goods = {
  311. id: this.goodsInfo.id,
  312. name: this.goodsInfo.name,
  313. price: this.goodsInfo.price,
  314. count: 1,
  315. image: this.goodsInfo.url,
  316. state: true // 默认是勾选的
  317. }
  318. this.addCart(goods) // 调用映射过来的全局存储方法
  319. }
  320. },
  321. onClick(e) { //点击
  322. // console.log(e)
  323. if (e.content.text === "购物车") {
  324. uni.switchTab({
  325. url: "/pages/cart/cart"
  326. })
  327. }
  328. },
  329. preview(index) { // 预览
  330. uni.previewImage({
  331. current: index,
  332. urls: this.goodsInfo.imageList.map(v => v)
  333. })
  334. },
  335. selectGoods(id) {
  336. uni.$http.post("/document/select_id/" + id).then(res => {
  337. // console.log(res)
  338. if (res.data.code = "200") {
  339. this.goodsInfo = res.data.object
  340. this.goodsInfo.imageList = res.data.object.imageList.split("&&&")
  341. // console.log(this.goodsInfo.imageList)
  342. } else {
  343. return uni.$message()
  344. }
  345. })
  346. }
  347. }
  348. }
  349. </script>
  350. <style lang="scss">
  351. </style>
  352. *************************************************************************************************
  353. 此种有真意,欲辨已忘言
  1. 37142集 动态统计购物车中商品的总数量
  2. totalNum(state) {
  3. let c = 0
  4. state.cart.forEach(x => {
  5. c = c + x.count
  6. })
  7. return c // 计算总数
  8. }
  9. *****************************************************************************************
  10. watch: {
  11. totalNum(newVal) {
  12. // console.log(newVal)
  13. const findResult = this.options.find(x => x.text === '购物车')
  14. if (findResult) {
  15. findResult.info = newVal
  16. }
  17. }
  18. },
  19. 38】持久化存储购物车的数据
  20. export default {
  21. namespaced: true,
  22. state: () => ({
  23. // 包含6个属性 id name price count image state
  24. cart: JSON.parse(uni.getStorageSync('cart') || '[]')
  25. }),
  26. mutations: { // 方法在这里定义的
  27. addCart(state, goods) {
  28. const findResult = state.cart.find(x => x.id === goods.id) // 根据id判断是否存在
  29. console.log(findResult)
  30. if (!findResult) {
  31. state.cart.push(goods)
  32. } else {
  33. findResult.count++ // 数量+1
  34. }
  35. // console.log(state.cart)
  36. this.commit('m_cart/saveToStorage')
  37. },
  38. // 持久化存储数据
  39. saveToStorage(state) {
  40. uni.setStorageSync('cart', JSON.stringify(state.cart)) // 存储到本地
  41. }
  42. },
  43. getters: {
  44. totalNum(state) {
  45. let c = 0
  46. state.cart.forEach(x => {
  47. c = c + x.count
  48. })
  49. return c // 计算总数
  50. }
  51. }
  52. }
  53. 39】优化total侦听器
  54. 因为重新编译后还是0.....日尼玛
  55. watch: {
  56. totalNum: {
  57. handler(newVal) {
  58. const findResult = this.options.find(x => x.text === '购物车')
  59. if (findResult) {
  60. findResult.info = newVal
  61. }
  62. },
  63. immediate: true // 这个就可以在加载完毕后立刻调用
  64. }
  65. },
  66. *****************************************************************************************
  67. 主要是通过优化侦听器
  68. 40】动态设置tabBar的数字徽标
  69. <script>
  70. import {
  71. mapGetters
  72. } from 'vuex'
  73. export default {
  74. computed: { // 把全局数据映射到购物车
  75. ...mapGetters('m_cart', ['totalNum'])
  76. },
  77. onShow() {
  78. this.setBadge()
  79. },
  80. data() {
  81. return {
  82. };
  83. },
  84. methods: {
  85. setBadge() {
  86. uni.setTabBarBadge({
  87. index: 2,
  88. text: this.totalNum + ""
  89. })
  90. }
  91. }
  92. }
  93. </script>
  94. *****************************************************************************************
  95. 把设置tabBar徽标的代码抽离为mixins
  96. 因为直接回到首页...等页面,徽标不生效,所以需要抽离!!!!!!!!!!!!!
  97. import {
  98. mapGetters
  99. } from 'vuex'
  100. export default {
  101. computed: { // 把全局数据映射到购物车
  102. ...mapGetters('m_cart', ['totalNum'])
  103. },
  104. onShow() {
  105. this.setBadge()
  106. },
  107. methods: {
  108. setBadge() {
  109. uni.setTabBarBadge({
  110. index: 2,
  111. text: this.totalNum + ""
  112. })
  113. }
  114. }
  115. }
  116. -------------------------------------------------------------------------------------------------
  117. import mix from '@/mixins/tabbar-badge.js'
  118. export default {
  119. mixins: [mix],
  120. 徽标永存
  121. 41】购物车页面-效果演示和编译模式新增
  122. 地址、加减购物、结算----牛批了!!!!!!!!!!!!!
  123. 谢谢黑马的老师!!!!!!!!!!!!!
  124. 在小程序新增一个直接跳转购物车的模式......简单的一批!!!!!!!!!
  125. *****************************************************************************************
  126. <image :src="item.url ||item.image || defaultImage" style="width: 100px;height:
  127. 100px;display: block;"></image>
  128. 我是个人才!!!!!!!!!!!!!!!!!!!!!!!
  129. <!-- 左侧盒子 -->
  130. <view style="margin-right: 5px;display: flex;justify-content: space-between;align-items: center;">
  131. <!-- 选择项 -->
  132. <radio checked="true" color="#C00000"></radio>
  133. <image :src="item.url ||item.image || defaultImage" style="width: 100px;height: 100px;display: block;">
  134. </image>
  135. </view>
  136. *****************************************************************************************
  137. 控制显示与隐藏,因为列表也需要隐藏!!!!!!!!!!!!!!!
  138. props: {
  139. item: { // 这个名字和页面里使用的名字是一致的,注意!!!!!!!!!!!!
  140. type: Object,
  141. default: {}
  142. },
  143. showRadio: {
  144. type: Boolean,
  145. default: false // 默认不展示选择框 即可,需要的话需要传递true
  146. }
  147. },
  148. -------------------------------------------------------------------------------------------------
  149. <radio checked="true" color="#C00000" v-if="showRadio"></radio>
  150. -------------------------------------------------------------------------------------------------
  151. 验证了一句话:万丈高楼平地起!!!!!!!!!!!!!!又见东风来...
  152. :checked="item.state"
  153. 动态绑定选中状态
  154. 42149集 修改购物车商品的勾选状态
  155. <my-goods :item="item" :showRadio="true" @fff_son_radioChange="fff_son_radioChange"></my-goods>
  156. -------------------------------------------------------------------------------------------------
  157. <radio :checked="item.state" color="#C00000" v-if="showRadio" @click="son_fff_radioClick"></radio>
  158. -------------------------------------------------------------------------------------------------
  159. son_fff_radioClick() { // 子触发父亲函数
  160. this.$emit('fff_son_radioChange', {
  161. item_id: this.item.id,
  162. item_state: !this.item.state
  163. })
  164. }
  165. -------------------------------------------------------------------------------------------------
  166. fff_son_radioChange(e) {
  167. console.log(e)
  168. }
  169. *****************************************************************************************
  170. 更新购物车里面的商品勾选状态:
  171. // 更新购物车中商品勾选状态
  172. updateGoodsState(state, goods) {
  173. const findResult = state.cart.find(x => x.id === goods.id) // 根据id判断是否存在
  174. if (findResult) {
  175. findResult.state = goods.state // 更新勾选状态
  176. this.commit('m_cart/saveToStorage') // 更新存储本地
  177. }
  178. }
  179. -------------------------------------------------------------------------------------------------
  180. methods: {
  181. ...mapMutations('m_cart', ['updateGoodsState']),
  182. fff_son_radioChange(e) {
  183. // console.log(e)
  184. this.updateGoodsState(e) // 更新选中状态 e其实是一个对象,传参对象!!!!!!!!!!!!
  185. }
  186. }
  187. 43】商品列表-封装NumberBox
  188. <template>
  189. <!-- 外层容器 -->
  190. <view>
  191. <view style="display: flex;padding: 10px 5px;border-bottom: 1px solid lightgray;">
  192. <!-- 左侧盒子 -->
  193. <view style="margin-right: 5px;display: flex;justify-content: space-between;align-items: center;">
  194. <!-- 选择项 -->
  195. <radio :checked="item.state" color="#C00000" v-if="showRadio" @click="son_fff_radioClick"></radio>
  196. <image :src="item.url ||item.image || defaultImage" style="width: 100px;height: 100px;display: block;">
  197. </image>
  198. </view>
  199. <!-- 右侧盒子 -->
  200. <view style="display: flex;flex-direction: column;justify-content: space-between;flex:1;">
  201. <!-- 商品名称 -->
  202. <view style="font-size: 13px;">{{item.name}}</view>
  203. <!-- 包了一层 -->
  204. <view style="display: flex;justify-content: space-between;align-items: center;">
  205. <!-- 商品价格 -->
  206. <view style="color: #C00000;font-size: 16px;">¥ {{item.price | toFixed}}</view>
  207. <!-- 商品数量 -->
  208. <uni-number-box :min="1" :value="item.count">
  209. </uni-number-box>
  210. </view>
  211. </view>
  212. </view>
  213. </view>
  214. </template>
  215. <script>
  216. export default {
  217. name: "my-goods",
  218. props: {
  219. item: { // 这个名字和页面里使用的名字是一致的,注意!!!!!!!!!!!!
  220. type: Object,
  221. default: {}
  222. },
  223. showRadio: {
  224. type: Boolean,
  225. default: false // 默认不展示选择框 即可,需要的话需要传递true
  226. }
  227. },
  228. data() {
  229. return {
  230. defaultImage: 'http://wdfgdzx.top:8000/document/a5dd6d1d1c5c45dd98c6017b1821acb8.jpg', // 默认图片地址
  231. };
  232. },
  233. filters: {
  234. toFixed(num) {
  235. return Number(num).toFixed(2)
  236. }
  237. },
  238. methods: {
  239. son_fff_radioClick() { // 子触发父亲函数
  240. this.$emit('fff_son_radioChange', {
  241. id: this.item.id,
  242. state: !this.item.state
  243. })
  244. }
  245. }
  246. }
  247. </script>
  248. <style lang="scss">
  249. </style>
  250. *****************************************************************************************
  251. 数量框的按需展示:
  252. 数据库读取最好用线上,不然麻烦不少呀!!!!!!!!!!!!!!!!
  253. 44151集 封装num-change事件,也是父传子,子传父的问题
  254. <template>
  255. <!-- 外层容器 -->
  256. <view>
  257. <view style="display: flex;padding: 10px 5px;border-bottom: 1px solid lightgray;">
  258. <!-- 左侧盒子 -->
  259. <view style="margin-right: 5px;display: flex;justify-content: space-between;align-items: center;">
  260. <!-- 选择项 -->
  261. <radio :checked="item.state" color="#C00000" v-if="showRadio" @click="son_fff_radioClick">
  262. </radio>
  263. <image :src="item.url ||item.image || defaultImage" style="width: 100px;height: 100px;display: block;">
  264. </image>
  265. </view>
  266. <!-- 右侧盒子 -->
  267. <view style="display: flex;flex-direction: column;justify-content: space-between;flex:1;">
  268. <!-- 商品名称 -->
  269. <view style="font-size: 13px;">{{item.name}}</view>
  270. <!-- 包了一层 -->
  271. <view style="display: flex;justify-content: space-between;align-items: center;">
  272. <!-- 商品价格 -->
  273. <view style="color: #C00000;font-size: 16px;">¥ {{item.price | toFixed}}</view>
  274. <!-- 商品数量 -->
  275. <uni-number-box :min="1" :value="item.count" v-if="showNum" @change="son_fff_numChange">
  276. </uni-number-box>
  277. </view>
  278. </view>
  279. </view>
  280. </view>
  281. </template>
  282. <script>
  283. export default {
  284. name: "my-goods",
  285. props: {
  286. item: { // 这个名字和页面里使用的名字是一致的,注意!!!!!!!!!!!!
  287. type: Object,
  288. default: {}
  289. },
  290. showRadio: {
  291. type: Boolean,
  292. default: false // 默认不展示选择框 即可,需要的话需要传递true
  293. },
  294. showNum: {
  295. type: Boolean,
  296. default: false // 默认不展示数量框 即可,需要的话需要传递true
  297. }
  298. },
  299. data() {
  300. return {
  301. defaultImage: 'http://wdfgdzx.top:8000/document/a5dd6d1d1c5c45dd98c6017b1821acb8.jpg', // 默认图片地址
  302. };
  303. },
  304. filters: {
  305. toFixed(num) {
  306. return Number(num).toFixed(2)
  307. }
  308. },
  309. methods: {
  310. son_fff_radioClick() { // 子触发父亲函数
  311. this.$emit('fff_son_radioChange', {
  312. id: this.item.id,
  313. state: !this.item.state
  314. })
  315. },
  316. son_fff_numChange(val) { // 子触发父亲函数
  317. this.$emit('fff_son_numChange', {
  318. id: this.item.id,
  319. count: val - 0 // 这就是最新的数量值
  320. })
  321. }
  322. }
  323. }
  324. </script>
  325. <style lang="scss">
  326. </style>
  1. 45152 优化NumberBox组件
  2. uni-number-box.vue已经默认解决了,最大值是100个,可以修改
  3. *****************************************************************************************
  4. inputValue 小数的处理也是默认帮处理了,果然技术的发展是牛批的,不断更新的!!!!!
  5. *****************************************************************************************
  6. uni-number-box.vue已经自优化了!!!!!!
  7. 46】修改购物车数量持久化存储
  8. 问题:修改数量后,重新编译后还是变回原来的了....
  9. 搞半天,Hbulider没有运行到小程序,搞笑呀!!!!!!!!!!!!!!!!!!!!
  10. // 更新商品的数量并保存到本地
  11. updateCount(state, goods) { // 更新商品数量
  12. const findResult = state.cart.find(x => x.id === goods.id) // 根据id判断是否存在
  13. if (findResult) {
  14. findResult.count = goods.count // 更新数量
  15. // console.log(findResult)
  16. this.commit('m_cart/saveToStorage') // 更新存储本地
  17. }
  18. }
  19. *****************************************************************************************
  20. fff_son_numChange(e) {
  21. // console.log(e)
  22. this.updateCount(e) // 更新选中状态 e其实是一个对象,传参对象!!!!!!!!!!!!
  23. }
  24. 47】滑动删除的UI效果
  25. 之后查看官网示例时发现options是旧版的写法,我使用的是新版,要用right-options代替。
  26. *****************************************************************************************
  27. 坑呀!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  28. *****************************************************************************************
  29. <!-- 渲染购物车中的商品信息 -->
  30. <uni-swipe-action>
  31. <block v-for="(item,index) in cart" :key="index">
  32. <uni-swipe-action-item :right-options="options" @click="">
  33. <my-goods :item="item" :showRadio="true" :showNum="true" @fff_son_radioChange="fff_son_radioChange"
  34. @fff_son_numChange="fff_son_numChange"></my-goods>
  35. </uni-swipe-action-item>
  36. </block>
  37. </uni-swipe-action>
  38. *****************************************************************************************
  39. data() {
  40. return {
  41. options: [{
  42. text: '删除',
  43. style: {
  44. backgroundColor: '#C00000'
  45. }
  46. }]
  47. };
  48. },
  49. *****************************************************************************************
  50. 实现滑动删除的功能
  51. 代码写错,导致state.cart出错,耗费了我不少时间排查
  52. 还得实现保存空,重新保存,没少费劲
  53. removeGoodsById(state, goods) { // 根据id删除商品
  54. state.cart = state.cart.filter(x => x.id !== goods.id)
  55. this.commit('m_cart/saveToStorage') // 更新存储本地
  56. }
  57. *****************************************************************************************
  58. @click="swipeItemClick(item)">
  59. swipeItemClick(item) {
  60. // console.log(item)
  61. this.removeGoodsById(item)
  62. }
  63. 48】收货地址的实现!!!!!!!!!!!!!!!!!!155
  64. <template>
  65. <view>
  66. 收货地址组件
  67. </view>
  68. </template>
  69. <script>
  70. export default {
  71. name: "my-address",
  72. data() {
  73. return {
  74. };
  75. }
  76. }
  77. </script>
  78. <style lang="scss">
  79. </style>
  80. *****************************************************************************************
  81. <template>
  82. <view>
  83. <!-- 选择收货地址的盒子 -->
  84. <view style="height: 90px;display: flex;justify-content: center;align-items: center;">
  85. <button type="primary" size="mini" style="">请选择收货地址+</button>
  86. </view>
  87. <!-- 底部边框 -->
  88. <image src="/static/cart_border@2x.png" style="display: flex;width: 100%;height: 5px;"></image>
  89. </view>
  90. </template>
  91. <script>
  92. export default {
  93. name: "my-address",
  94. data() {
  95. return {
  96. };
  97. }
  98. }
  99. </script>
  100. <style lang="scss">
  101. </style>
  102. *****************************************************************************************
  103. <template>
  104. <view>
  105. <!-- 选择收货地址的盒子 -->
  106. <view style="height: 90px;display: flex;justify-content: center;align-items: center;">
  107. <button type="primary" size="mini" style="">请选择收货地址+</button>
  108. </view>
  109. <!-- 渲染收货信息的盒子 -->
  110. <view
  111. style="font-size: 12px;height: 90px;display: flex;flex-direction: column;justify-content: center;padding: 0 5px;">
  112. <!-- 第一行 -->
  113. <view style="display: flex;justify-content: space-between;">
  114. <!-- 左右布局 -->
  115. <view>收货人:ask</view>
  116. <view style="display: flex;">
  117. <view>电话:183XXXX0000</view>
  118. <uni-icons type="arrowright" size="16"></uni-icons>
  119. </view>
  120. </view>
  121. <!-- 第二行 -->
  122. <view style="display: flex;justify-content: space-between;align-items: center;margin-top: 10px;">
  123. <!-- 左右布局 -->
  124. <view style="white-space: nowrap;">收货地址:</view>
  125. <view>安徽省合肥市蜀山区创新大道2889号苏宁小店安徽省合肥市蜀山区创新大道2889号苏宁小店安徽省合肥市蜀山区创新大道2889号苏宁小店</view>
  126. </view>
  127. </view>
  128. <!-- 底部边框 -->
  129. <image src="/static/cart_border@2x.png" style="display: flex;width: 100%;height: 5px;"></image>
  130. </view>
  131. </template>
  132. <script>
  133. export default {
  134. name: "my-address",
  135. data() {
  136. return {
  137. };
  138. }
  139. }
  140. </script>
  141. <style lang="scss">
  142. </style>
  143. *****************************************************************************************
  144. 按需展示
  145. <view style="height: 90px;display: flex;justify-content: center;align-items: center;"
  146. v-if="JSON.stringify(address)==='{}'">
  147. <button type="primary" size="mini" style="">请选择收货地址+</button>
  148. </view>
  149. <!-- 渲染收货信息的盒子 -->
  150. <view v-else
  151. style="font-size: 12px;height: 90px;display: flex;flex-direction: column;justify-content:
  152. center;padding: 0 5px;">
  153. 49】实现选择收货地址功能
  154. "requiredPrivateInfos": [
  155. "getLocation",
  156. "chooseAddress"
  157. ]
  158. 要使用,先开启
  159. *****************************************************************************************
  160. 然后再配置方法
  161. methods: {
  162. async pickAddress() {
  163. const [err, success] = await uni.chooseAddress().catch(err => err)
  164. // console.log(res)
  165. if (err === null && success.errMsg === 'chooseAddress:ok') {
  166. // console.log(success)
  167. this.address = success
  168. }
  169. }
  170. }
  171. 50】渲染收货人信息
  172. computed: {
  173. addressStr() {
  174. if (!this.address.provinceName) {
  175. return ''
  176. } else {
  177. return this.address.provinceName + this.address.cityName + this.address.countyName + this.address
  178. .detailInfo
  179. }
  180. }
  181. },
  182. 51】将客户选择的地址,存储到VUEX全局存储中
  183. export default {
  184. namespaced: true, // 开启命名空间
  185. // 数据节点
  186. state: () => ({
  187. address: {}
  188. }),
  189. // 方法
  190. mutations: {
  191. updateAddress(state, address) {
  192. state.address = address // 更新收货地址
  193. }
  194. },
  195. // 访问方法
  196. getters: {
  197. }
  198. }
  199. *****************************************************************************************
  200. ...mapState('m_user', ['address']),
  201. *****************************************************************************************
  202. methods: {
  203. ...mapMutations('m_user', ['updateAddress']),
  204. async pickAddress() {
  205. const [err, success] = await uni.chooseAddress().catch(err => err)
  206. // console.log(res)
  207. if (err === null && success.errMsg === 'chooseAddress:ok') {
  208. // console.log(success)
  209. // this.address = success
  210. this.updateAddress(success) // 更新地址
  211. }
  212. }
  213. }
  214. 52】持久化存储到store.js中
  215. updateAddress(state, address) {
  216. state.address = address // 更新收货地址
  217. this.commit('m_user/saveAddressToStorage'); // 调用存储
  218. },
  219. saveAddressToStorage(state) {
  220. uni.setStorageSync('address', JSON.stringify(state.address)) // 存储到本地
  221. }
  222. 53】将addressStr抽离为getters,目的是提高代码的复用性
  223. export default {
  224. namespaced: true, // 开启命名空间
  225. // 数据节点
  226. state: () => ({
  227. address: JSON.parse(uni.getStorageSync('address') || '{}')
  228. }),
  229. // 方法
  230. mutations: {
  231. updateAddress(state, address) {
  232. state.address = address // 更新收货地址
  233. this.commit('m_user/saveAddressToStorage'); // 调用存储
  234. },
  235. saveAddressToStorage(state) {
  236. uni.setStorageSync('address', JSON.stringify(state.address)) // 存储到本地
  237. }
  238. },
  239. // 访问方法
  240. getters: {
  241. addressStr(state) {
  242. if (!state.address.provinceName) {
  243. return ''
  244. } else {
  245. return state.address.provinceName + state.address.cityName + state.address.countyName + state.address
  246. .detailInfo
  247. }
  248. }
  249. }
  250. }
  251. *****************************************************************************************
  252. import {
  253. mapState,
  254. mapMutations,
  255. mapGetters
  256. } from 'vuex'
  257. export default {
  258. name: "my-address",
  259. data() {
  260. return {
  261. // address: {}
  262. };
  263. },
  264. computed: {
  265. ...mapState('m_user', ['address']),
  266. ...mapGetters('m_user', ['addressStr'])
  267. },
  268. methods: {
  269. ...mapMutations('m_user', ['updateAddress']),
  270. 54】重新选择收货地址
  271. <view v-else @click="pickAddress"
  272. style="font-size: 12px;height: 90px;display: flex;flex-direction: column;justify-content:
  273. center;padding: 0 5px;">
  274. *****************************************************************************************
  275. 解决收货地址授权失败的问题!!!!!!!!!!
  276. 我的项目好像没这个问题,牛批 162说解决了这个问题,但是我的不需要解决,哈哈哈
  277. 55】封装结算区域的组件
  278. <template>
  279. <view style="position: fixed; bottom: 0;left: 0;width: 100%;height: 50px;background-color: yellow;">
  280. 结算组件
  281. </view>
  282. </template>
  283. <script>
  284. export default {
  285. name: "my-settle",
  286. data() {
  287. return {
  288. };
  289. }
  290. }
  291. </script>
  292. <style lang="scss">
  293. </style>
  294. *****************************************************************************************
  295. <template>
  296. <view style="position: fixed; bottom: 0;left: 0;width: 100%;height: 50px;background-color: white;display: flex;justify-content: space-between;
  297. align-items: center;font-size: 14px;padding-left: 5px;">
  298. <!-- 全选 -->
  299. <label style="display: flex;align-items: center;">
  300. <radio color="#C00000" :checked="true" />
  301. <text>全选</text>
  302. </label>
  303. <!-- 合计 -->
  304. <view>
  305. 合计:<text style="color: #C00000;font-weight: bold;">¥ 123.06</text>
  306. </view>
  307. <!-- 结算按钮 -->
  308. <view
  309. style="background-color: #C00000;height: 50px;color: white;line-height: 50px;padding: 0 10px;min-width: 100px;text-align: center;">
  310. 结算(0
  311. </view>
  312. </view>
  313. </template>
  314. <script>
  315. export default {
  316. name: "my-settle",
  317. data() {
  318. return {
  319. };
  320. }
  321. }
  322. </script>
  323. <style lang="scss">
  324. </style>
  325. 56】动态渲染已勾选商品的总数量!!!!!!!!!!!!!!!!!!!!!!!
  326. checkedCount(state) {
  327. // console.log(tempList)
  328. let total = 0
  329. state.cart.filter(x => x.state).forEach(item => {
  330. // console.log(item.count)
  331. total = total + item.count
  332. })
  333. return total
  334. }
  335. *****************************************************************************************
  336. 动态渲染全选的状态:
  337. computed: {
  338. ...mapGetters('m_cart', ['checkedCount', 'totalNum']),
  339. fullCheckFlag() {
  340. return this.totalNum === this.checkedCount
  341. }
  342. }
  343. 57】商品的全选和反选功能
  344. updateAllGoodsState(state, newState) { // 更新所有商品的勾选状态
  345. state.cart.forEach(x => x.state = newState)
  346. this.commit('m_cart/saveToStorage') // 更新存储本地
  347. }
  348. *****************************************************************************************
  349. ...mapMutations('m_cart', ['updateAllGoodsState']),
  350. changeAllState() { // 改变所有商品的勾选状态
  351. // console.log("执行了")
  352. this.updateAllGoodsState(!this.fullCheckFlag)
  353. }
  354. *****************************************************************************************
  355. getGoodsCheckedPrice(state) {
  356. let total = 0
  357. state.cart.filter(x => x.state).forEach(item => {
  358. // console.log(item.count)
  359. total = total + item.price * item.count
  360. })
  361. return total.toFixed(2)
  362. }
  363. *****************************************************************************************
  364. ...mapGetters('m_cart', ['checkedCount', 'totalNum', 'getGoodsCheckedPrice']),
  365. *****************************************************************************************
  366. <view>
  367. 合计:<text style="color: #C00000;font-weight: bold;">¥ {{getGoodsCheckedPrice}}</text>
  368. </view>
  369. *****************************************************************************************
  370. 动态计算购物车徽标的数值,就是自己一直关注的tabBar数字不更新问题的处理!!!!
  371. import {
  372. mapGetters
  373. } from 'vuex'
  374. export default {
  375. computed: { // 把全局数据映射到购物车
  376. ...mapGetters('m_cart', ['totalNum'])
  377. },
  378. watch: { // !!!!!!!!!!!!!!!!!!!!!this one
  379. totalNum() {
  380. this.setBadge()
  381. }
  382. },
  383. onShow() {
  384. this.setBadge()
  385. },
  386. methods: {
  387. setBadge() {
  388. uni.setTabBarBadge({
  389. index: 2,
  390. text: this.totalNum + ""
  391. })
  392. }
  393. }
  394. }
  395. 58】购物车细节渲染
  396. <view v-if="cart.length!==0">
  397. <!-- 空购物车 -->
  398. <view v-else style="display: flex;flex-direction: column;align-items: center;padding-top: 150px;">
  399. <image src="/static/cart_empty@2x.png" style="width: 90px;height: 90px;"></image>
  400. <text style="font-size: 12px;color: gray;margin-top: 15px;">购物车空空如也~</text>
  401. </view>
  1. 59170集 登录与支付
  2. settleClick() { // 用户点击了结算按钮
  3. if (!this.checkedCount) {
  4. return uni.$message("请选择要结算的商品")
  5. }
  6. if (!this.addressStr) {
  7. return uni.$message("请选择收货地址")
  8. }
  9. if (!this.token) {
  10. return uni.$message("请您先登录账户")
  11. }
  12. }
  13. 60】登录页面UI的初步渲染
  14. 创建下我的页面的编译模式
  15. ********************************************************************************************
  16. 登录和登录后判断条件展示
  17. <!-- 登录组件 -->
  18. <my-login v-if="!token"></my-login>
  19. <!-- 登录后组件 -->
  20. <my-user-info v-else></my-user-info>
  21. ********************************************************************************************
  22. <template>
  23. <view>
  24. <uni-icons type="contact-filled" size="100" color="#AFAFAF"></uni-icons>
  25. <button type="primary" style="">一键登录</button>
  26. <text style="">登录后进行更多权益</text>
  27. </view>
  28. </template>
  29. <script>
  30. export default {
  31. name: "my-login",
  32. data() {
  33. return {
  34. };
  35. }
  36. }
  37. </script>
  38. <style lang="scss">
  39. </style>
  40. ********************************************************************************************
  41. <template>
  42. <view
  43. style="height: 750rpx;background-color: #F8F8F8;display: flex;flex-direction: column;justify-content: center;align-items: center;">
  44. <uni-icons type="contact-filled" size="100" color="#AFAFAF"></uni-icons>
  45. <button type="primary"
  46. style="width: 90%;border-radius: 100px;margin: 15px 0;background-color: #C00000;">一键登录</button>
  47. <text style="font-size: 12px;color: gray">登录后进行更多权益</text>
  48. </view>
  49. </template>
  50. <script>
  51. export default {
  52. name: "my-login",
  53. data() {
  54. return {
  55. };
  56. }
  57. }
  58. </script>
  59. <style lang="scss">
  60. </style>
  61. ********************************************************************************************
  62. <template>
  63. <view class="login-container" style="height: 750rpx;background-color: lightgray;display: flex;
  64. flex-direction: column;justify-content: center;align-items: center;position: relative;overflow: hidden;">
  65. <uni-icons type="contact-filled" size="100" color="#AFAFAF"></uni-icons>
  66. <button type="primary"
  67. style="width: 90%;border-radius: 100px;margin: 15px 0;background-color: #C00000;">一键登录</button>
  68. <text style="font-size: 12px;color: gray">登录后进行更多权益</text>
  69. </view>
  70. </template>
  71. <script>
  72. export default {
  73. name: "my-login",
  74. data() {
  75. return {
  76. };
  77. }
  78. }
  79. </script>
  80. <style lang="scss">
  81. .login-container {
  82. &::after {
  83. content: '';
  84. display: block;
  85. width: 100%;
  86. height: 40px;
  87. background-color: #F5F5F5;
  88. position: absolute;
  89. bottom: 0;
  90. left: 0;
  91. border-radius: 100%;
  92. transform: translateY(50%);
  93. }
  94. }
  95. </style>
  96. 61】点击按钮实现登录 172
  97. open-type="getUserInfo" @getuserinfo="getUserInfo"
  98. 前面的那个更重要!!!!!!!!!!!!!!!!!!
  99. 62】将用户的基本信息存储到本地
  100. updateUserInfo(state, userInfo) {
  101. state.userInfo = userInfo
  102. this.commit('m_user/saveUserInfoToStorage'); // 调用存储
  103. },
  104. saveUserInfoToStorage(state) {
  105. uni.setStorageSync('userInfo', JSON.stringify(state.userInfo))
  106. }
  107. ********************************************************************************************
  108. ...mapMutations('m_user', ['updateUserInfo']),
  109. getUserInfo(e) {
  110. if (e.detail.errMsg === 'getUserInfo:fail auth deny') {
  111. return uni.$message("您取消了登录授权")
  112. }
  113. this.updateUserInfo(e.detail.userInfo)
  114. // console.log(e)
  115. }
  116. 63】调动uni.login获取用户登录凭证
  117. async getToken(info) { // 获取code的值
  118. // 获取code对应的值
  119. const [err, res] = await uni.login().catch(err => err)
  120. // console.log(res)
  121. if (err || res.errMsg !== 'login:ok') {
  122. return uni.$message('登录失败')
  123. }
  124. console.log(res.code)
  125. console.log(info)
  126. }
  127. 64】获取token并存储到vuex
  128. 先继续写,后面可能需要改造login API
  129. uni.$http.post('/api/public/v1/users/wxlogin', sendData).then(res => {
  130. console.log(res)
  131. if (res.statusCode !== 200) {
  132. return uni.$message("登录失败!")
  133. }
  134. uni.$message("登录成功!")
  135. this.updateToken(
  136. "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjIzLCJpYXQiOjE1NjQ3MzAwNzksImV4cCI6MTAwMTU2NDczMDA3OH0"
  137. )
  138. })
  139. ********************************************************************************************
  140. 我设置的是假的Token,后台接口需要根据信息生成
  141. 65】登录后信息布局展示
  142. <template>
  143. <view style="height: 100%;background-color: #F4F4F4;">
  144. <!-- 头像和昵称区域 -->
  145. <view
  146. style="height: 400rpx;background-color:#C00000;display: flex;justify-content: center;align-items: center;flex-direction: column;">
  147. <image :src="userInfo.url"
  148. style="width: 90px;height: 90px;border-radius: 45px;border: 2px solid #FFF;box-shadow: 0 1px 5px black;">
  149. </image>
  150. <view style="font-size: 16px;color: #FFF;font-weight: bold;margin-top: 10px;">
  151. {{userInfo.nickName}}
  152. </view>
  153. </view>
  154. </view>
  155. </template>
  156. <script>
  157. import {
  158. mapState
  159. } from 'vuex'
  160. export default {
  161. name: "my-user-info",
  162. computed: {
  163. ...mapState('m_user', ['userInfo'])
  164. },
  165. data() {
  166. return {
  167. };
  168. }
  169. }
  170. </script>
  171. <style lang="scss">
  172. </style>
  173. 66】渲染第一个面板区域
  174. <!-- 1个面板 panel1-->
  175. <view>
  176. <view> <!-- panel-body -->
  177. <view> <!-- panel-item -->
  178. <text>8</text>
  179. <text>收藏的店铺</text>
  180. </view>
  181. <view> <!-- panel-item -->
  182. <text>14</text>
  183. <text>收藏的商品</text>
  184. </view>
  185. <view> <!-- panel-item -->
  186. <text>18</text>
  187. <text>关注的商品</text>
  188. </view>
  189. <view> <!-- panel-item -->
  190. <text>84</text>
  191. <text>足迹</text>
  192. </view>
  193. </view>
  194. </view>
  195. ********************************************************************************************
  196. <!-- 1个面板 panel1-->
  197. <view style="padding: 0 10px;position: relative;top:-10px;">
  198. <!-- panel-body -->
  199. <view
  200. style="background-color: white;border-radius: 3px;margin-bottom: 8px;display: flex;justify-content: space-around;">
  201. <!-- panel-item -->
  202. <view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;
  203. font-size: 13px;">
  204. <text>8</text>
  205. <text>收藏的店铺</text>
  206. </view>
  207. <!-- panel-item -->
  208. <view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;
  209. font-size: 13px;">
  210. <text>14</text>
  211. <text>收藏的商品</text>
  212. </view>
  213. <!-- panel-item -->
  214. <view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;
  215. font-size: 13px;">
  216. <text>18</text>
  217. <text>关注的商品</text>
  218. </view>
  219. <!-- panel-item -->
  220. <view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;
  221. font-size: 13px;">
  222. <text>84</text>
  223. <text>足迹</text>
  224. </view>
  225. </view>
  226. </view>
  227. 67】渲染第二个面板区域
  228. <view style="padding: 0 10px;position: relative;top:-10px;">
  229. <!-- title -->
  230. <view
  231. style="line-height: 45px;padding-left: 10px;font-size: 15px;border-bottom: 1px solid #F4F4F4;background-color: white;">
  232. 我的订单
  233. </view>
  234. <!-- body -->
  235. <view
  236. style="background-color: white;border-radius: 3px;margin-bottom: 8px;display: flex;justify-content: space-around;">
  237. <!-- panel-item -->
  238. <view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;
  239. font-size: 13px;">
  240. <image src="/static/my-icons/icon1.png" style="width:35px;height: 35px;"></image>
  241. <text>待付款</text>
  242. </view>
  243. <!-- panel-item -->
  244. <view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;
  245. font-size: 13px;">
  246. <image src="/static/my-icons/icon2.png" style="width:35px;height: 35px;"></image>
  247. <text>待收货</text>
  248. </view>
  249. <!-- panel-item -->
  250. <view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;
  251. font-size: 13px;">
  252. <image src="/static/my-icons/icon3.png" style="width:35px;height: 35px;"></image>
  253. <text>退款/退货</text>
  254. </view>
  255. <!-- panel-item -->
  256. <view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;
  257. font-size: 13px;">
  258. <image src="/static/my-icons/icon4.png" style="width:35px;height: 35px;"></image>
  259. <text>全部订单</text>
  260. </view>
  261. </view>
  262. </view>
  263. 68】第三个面板
  264. <!-- 3个面板 -->
  265. <!-- panel -->
  266. <view style="padding: 0 10px;position: relative;top:-10px;">
  267. <!-- panel list -->
  268. <view style="background-color: white;">
  269. <view
  270. style="display: flex;justify-content: space-between;align-items: center;font-size: 15px;padding: 0 10px;line-height: 45px;">
  271. <text>收货地址</text>
  272. <uni-icons type="arrowright" @size="15"></uni-icons>
  273. </view>
  274. <!-- panel list -->
  275. <view
  276. style="display: flex;justify-content: space-between;align-items: center;font-size: 15px;padding: 0 10px;line-height: 45px;">
  277. <text>联系客服</text>
  278. <uni-icons type="arrowright" @size="15"></uni-icons>
  279. </view>
  280. <!-- panel list -->
  281. <view
  282. style="display: flex;justify-content: space-between;align-items: center;font-size: 15px;padding: 0 10px;line-height: 45px;">
  283. <text>退出登录</text>
  284. <uni-icons type="arrowright" @size="15"></uni-icons>
  285. </view>
  286. </view>
  287. </view>
  288. 69】退出登录功能的实现
  289. methods: {
  290. ...mapMutations('m_user', ['updateAddress', 'updateUserInfo', 'updateToken']),
  291. async logout() {
  292. const [err, success] = await uni.showModal({
  293. title: '提示',
  294. content: '确认需要退出登录吗?'
  295. }).catch(err => err)
  296. if (success && success.confirm) {
  297. this.updateAddress({})
  298. this.updateUserInfo({})
  299. this.updateToken({})
  300. }
  301. }
  302. }
  303. 701823秒后跳转登录页面
  304. if (this.token.length === undefined) {
  305. // return uni.$message("请您先登录账户")
  306. return this.delayNav();
  307. }
  308. },
  309. showTips(n) { // 展示倒计时提示
  310. uni.showToast({
  311. icon: 'none',
  312. title: '请登录后再结算!' + n + '秒后自动跳转到登录页',
  313. mask: true,
  314. duration: 1500
  315. })
  316. },
  317. delayNav() { // 延迟导航到my登录页面
  318. this.showTips(this.endTime)
  319. setInterval(() => {
  320. this.endTime--
  321. this.showTips(this.endTime)
  322. }, 1000)
  323. }
  324. ********************************************************************************************
  325. delayNav() { // 延迟导航到my登录页面
  326. this.showTips(this.endTime)
  327. this.timer = setInterval(() => {
  328. this.endTime--
  329. if (this.endTime <= 0) {
  330. clearInterval(this.timer) // 清除定时器
  331. uni.switchTab({
  332. url: '/pages/my/my'
  333. })
  334. return
  335. }
  336. this.showTips(this.endTime)
  337. }, 1000)
  338. }
  339. 主要是判断+clearInterval的应用!!!!!!!!!!!!!!!!
  340. 和uni.switchTab的使用......................................
  341. ********************************************************************************************
  342. 解决endTime倒计时不会重置的问题,我自己解决的,好屌呀!!!!!!!!!!!!!!
  343. if (this.endTime <= 0) {
  344. this.endTime = 3
  345. }
  1. 71】如果在登录成功之后,返回之前的页面 183
  2. delayNav() { // 延迟导航到my登录页面
  3. if (this.endTime <= 0) {
  4. this.endTime = 3
  5. }
  6. this.showTips(this.endTime)
  7. this.timer = setInterval(() => {
  8. this.endTime--
  9. if (this.endTime <= 0) {
  10. clearInterval(this.timer) // 清除定时器
  11. uni.switchTab({
  12. url: '/pages/my/my',
  13. success: () => {
  14. this.updateRedirectInfo({
  15. openType: 'switchTab',
  16. from: '/pages/cart/cart'
  17. })
  18. }
  19. })
  20. return
  21. }
  22. this.showTips(this.endTime)
  23. }, 1000)
  24. }
  25. ********************************************************************************************
  26. navigateBack() {
  27. if (this.redirectInfo && this.redirectInfo.openType === 'switchTab') {
  28. uni.switchTab({
  29. url: this.redirectInfo.from,
  30. complete: () => {
  31. this.updateRedirectInfo(null) // 重定向后置为null
  32. }
  33. })
  34. }
  35. }
  36. 72】在请求头重添加Token身份认证字段
  37. 搞半天其实是为了安全保证...
  38. // 请求开始之前做一些事情
  39. $http.beforeRequest = function(options) {
  40. uni.showLoading({
  41. title: "数据加载中..."
  42. })
  43. // console.log("我0604:" + JSON.stringify(options))
  44. if (options.url.indexOf('wx') !== -1) { // 这是包含的情况
  45. options.header = {
  46. Authorization: store.state.m_user.token
  47. }
  48. }
  49. // console.log("我0604:" + JSON.stringify(options))
  50. }
  51. 73】了解微信支付的概念
  52. 创建订单,返回订单编号
  53. ********************************************************************************************
  54. 订单预支付
  55. ********************************************************************************************
  56. 发起微信支付
  57. 74】创建订单API接口
  58. // 2创建订单 - 发起请求
  59. uni.$http.post('/wx_buy', sendData).then(res => {
  60. // console.log("0604打印" + JSON.stringify(res))
  61. if (res.data.code !== '200') {
  62. return uni.$message("订单创建失败")
  63. }
  64. const orderNumber = res.data.object.no; // 订单编号
  65. // console.log("0604打印" + orderNumber)
  66. })
  67. ********************************************************************************************
  68. 创建并返回订单编号,这个重点在后端
  69. 75】实现订单的预支付 187集-----------!!!!!!!!!!!!!!!!!!!!!!
  70. ********************************************************************************************
  71. 中间遇到了支付的问题。提交工商户审核
  72. 76】发起微信支付
  73. uni.requestPayment(payInfo)
  74. 77】微信小程序发布的流程
  75. 提升用户体验,缩小体积
  76. 78】uniapp发布为小程序
  77. 点击Hbulid的发行
  78. ---------------------------------------------------------------------------------------------------------
  79. 小程序-微信(第5个)
  80. ---------------------------------------------------------------------------------------------------------
  81. 小程序名称+APPID
  82. ---------------------------------------------------------------------------------------------------------
  83. 这样发型的体积更小 更好用!!!!!!!!!!!!!!!!!这个还挺重要的!!!!!
  84. ---------------------------------------------------------------------------------------------------------
  85. 提交小程序审核即可
  86. 79】发布为Android APP
  87. APP 图标配置
  88. ---------------------------------------------------------------------------------------------------------
  89. 发行—>原生APP—>云打包
  90. ---------------------------------------------------------------------------------------------------------
  91. 注意:选择收货地址、微信登录、微信支付是无法正常使用的!!!!!!!!

****************************************************************************************************************************************************************************

  1. 25、扩展功能:客服+虚拟充值
  2. 1】UNIAPP滑动问题处理:paddingBottom: -100 + 'px', // this.safeAreaInsets
  3. 2】校对与量控制,打通除回调支付外的隐藏支付...哈哈哈!!!!!!!!!!!!

****************************************************************************************************************************************************************************

  1. 26、总要有所突破
  2. 1】Ws长链接!!!!!!!!!!!!
  3. 2】Socket
  4. 客户端要有Socket、服务端也要有Socket
  5. *************************************************************************************
  6. 客户端的要和服务器的建立连接,必须要知道服务器的IP地址。
  7. 通过Socket传到服务端,服务端同样也可以通过Socket传到客户端。
  8. *************************************************************************************
  9. 只要链接不断开,服务端和客户端都可以主动推送消息
  10. 3】应用场景:
  11. 20230615终于实现了稳定的聊天小程序

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/783017
推荐阅读
相关标签
  

闽ICP备14008679号