UNIAPP小程序从入门到精通

news/2024/5/21 1:52:02

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

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

2、项目的基本结构   
【1】代码构成
pages用来存放所有小程序的页面
************************************************************************************
utils用于存放工具类的
************************************************************************************
app.js(入口) / app.json(全局配置) / app.wxss(全局样式文件)
************************************************************************************
project.config.json项目配置文件
************************************************************************************
sitemap.json用来配置小程序及其页面是否允许被微信索引
************************************************************************************
@小程序页面重点概述
index  【 index.js函数    index.json配置    index.wxml页面结构     index.wxss页面样式 】
index.wxss可以用style代替的!!!!!!!!!!!!!!
************************************************************************************
json配置文件的作用:app.json(全局配置)    project.config.json    sitemap.json    
每个页面xxx.json
************************************************************************************
app.json:全局配置。
{"pages":[  // 有几个页面"pages/index/index","pages/logs/logs"],"window":{ // 窗口颜色"backgroundTextStyle":"light","navigationBarBackgroundColor": "#fff","navigationBarTitleText": "Weixin","navigationBarTextStyle":"black"},"style": "v2", // 全局定义小程序所有页面背景色、文字颜色    可以删除或保留"sitemapLocation": "sitemap.json"
}
************************************************************************************
project.config.json:项目配置
{"description": "项目配置文件","packOptions": {"ignore": [],"include": []},"setting": { // 开发者工具的配置记录   在开发工具里可以配置"bundle": false,"userConfirmedBundleSwitch": false,"urlCheck": true,"scopeDataCheck": false,"coverView": true,"es6": true,"postcss": true,"compileHotReLoad": false,"lazyloadPlaceholderEnable": false,"preloadBackgroundData": false,"minified": true,"autoAudits": false,"newFeature": false,"uglifyFileName": false,"uploadWithSourceMap": true,"useIsolateContext": true,"nodeModules": false,"enhance": true,"useMultiFrameRuntime": true,"useApiHook": true,"useApiHostProcess": true,"showShadowRootInWxmlPanel": true,"packNpmManually": false,"enableEngineNative": false,"packNpmRelationList": [],"minifyWXSS": true,"showES6CompileOption": false,"minifyWXML": true,"babelSetting": {"ignore": [],"disablePlugins": [],"outputPath": ""}},"compileType": "miniprogram","libVersion": "2.19.4","appid": "wx775c2214e34aa966", //  小程序的appid  可以修改"projectname": "miniprogram-92", // 这个项目不等于小程序名称!!!!!"condition": {},"editorSetting": {"tabIndent": "insertSpaces","tabSize": 2}
}
************************************************************************************
sitemap.json 
小程序内搜索,效果类似于PC网页的SEO。
{"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html","rules": [{"action": "allow", // 允许被微信索引   disallow  是不允许被索引"page": "*"  // 所有页面}]
}
************************************************************************************
页面的.json配置文件(个性化配置会覆盖全局json配置)
{"pages":["pages/index/index","pages/logs/logs"],"window":{"backgroundTextStyle":"light","navigationBarBackgroundColor": "#fff", // 全局是白色"navigationBarTitleText": "Weixin","navigationBarTextStyle":"black"},"style": "v2","sitemapLocation": "sitemap.json"
}
****************
{"usingComponents": {},"navigationBarBackgroundColor":"#00B26A" // 局部是绿色,最终显示是绿色
} 

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

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

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

4、组件的使用
【1】组件的分类:
视图容器(view scroll-view swiper swiper-item)、基础内容、表单组件、导航组件!!!!
+媒体组件、map地图组件、canvas画布组件、开放能力、无障碍方向。
【2】view的使用
<!-- 分割线,这是下面的内容... 我先都用style写,快速上手目的是-->
<view style="display: flex;justify-content: space-around;"><view style="width: 100px;height: 100px;text-align: center;line-height: 100px;background-color: lightgreen;">1</view><view style="width: 100px;height: 100px;text-align: center;line-height: 100px;background-color: lightskyblue;">2</view><view style="width: 100px;height: 100px;text-align: center;line-height: 100px;background-color: lightcoral;">3</view>
</view>
【3】scroll-view的使用:height: 120px;" scroll-y
<!-- 分割线,这是下面的内容... -->
<scroll-view style="display: flex;justify-content: space-around;height: 120px;" scroll-y><view style="width: 100px;height: 100px;text-align: center;line-height: 100px;background-color: lightgreen;">1</view><view style="width: 100px;height: 100px;text-align: center;line-height: 100px;background-color: lightskyblue;">2</view><view style="width: 100px;height: 100px;text-align: center;line-height: 100px;background-color: lightcoral;">3</view>
</scroll-view>
【4】轮播图样式实现:swiper和swiper-item组件的基本使用。用style真是真清晰,上手块,牛批呀
<!-- 分割线,这是下面的内容... -->
<swiper style="height: 150px;" indicator-dots><swiper-item><view style="height:100%;line-height: 150px;text-align: center;background-color: green;">A</view></swiper-item><swiper-item><view style="height:100%;line-height: 150px;text-align: center;background-color: yellow;">B</view></swiper-item><swiper-item><view style="height: 100%;line-height: 150px;text-align: center;background-color: blue;">C</view></swiper-item>
</swiper>
【5】其他自定义属性:
indicator-dots是否展示小圆点
<swiper style="height: 150px;" indicator-dots indicator-color="white" indicator-active-color="red" 
autoplay interval="2000" circular>
************************************************************************************
基础内容组件text 、rich-text
text支持长按选中
<view>长按选中<text selectable> // !!!!!!!!!!!!!!!!!!1592129198</text>
</view>
************************************************************************************
rich-text,感觉用的不多吧!!!!!!!!!!!!!!!!!!!!!
<view><rich-text nodes="<h1 style='color:red'>示例</h1>"></rich-text>
</view>
【6】其他常用组件
button
<!-- 分割线,这是下面的内容...和VUE好像 -->
<button>默认按钮</button>
<button type="primary">主要按钮</button>
<button type="warn">主要按钮</button>
<button type="primary" size="mini">主要小按钮</button>
<button type="primary" plain="true">主要镂空按钮</button>
************************************************************************************
image使用(同时优化了自己的服务器,作为图片上传与预览的功能,牛批)
<!-- 分割线,这是下面的内容...和VUE好像 -->
<image src="https://wdfgdzx.top/document/pre_see/f75ffca9d133429c97622a5093ff6a80.jpg"></image>
<image src="https://wdfgdzx.top/document/pre_see/f75ffca9d133429c97622a5093ff6a80.jpg" mode="aspectFit"></image>
<image src="https://wdfgdzx.top/document/pre_see/f75ffca9d133429c97622a5093ff6a80.jpg" mode="aspectFill"></image>
<image src="https://wdfgdzx.top/document/pre_see/f75ffca9d133429c97622a5093ff6a80.jpg" mode="widthFix"></image>
<image src="https://wdfgdzx.top/document/pre_see/f75ffca9d133429c97622a5093ff6a80.jpg" mode="heightFix"></image>
************************************************************************************
【7】小程序的宿主环境API:事件监听类API、同步API、异步API
事件监听类API:以on开头,wx.onWindowResize
同步API:Sync结尾的API  wx.setStorageSync("key","value")
异步API:需要通过success、fail、complete来接收结果的。wx.request()发起网络请求,通过success接收

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

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

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

6、WXML页面结构渲染
【1】数据绑定
data中定义、wxml中使用
***************************************************************************************
data: {list: {name: "默认名称"}
},
***************************************************************************************
<text>数据详情:{{list.name}}</text> // 胡子语法
【2】胡子语法使用:内容绑定、绑定属性、三元运算
绑定属性:和VUE有点不同了data: {list: {name: "默认名称",src: "https://wdfgdzx.top/document/pre_see/fe78f50f0dee49569735e9c4ab608708.jpg"}},
***************************************************************************************<image src="{{list.src}}"></image>// 成功调用<image src="{{list.src}}" mode="widthFix"></image>
***************************************************************************************
三元运算:data: {list: {name: "默认名称",src: "https://wdfgdzx.top/document/pre_see/fe78f50f0dee49569735e9c4ab608708.jpg",randomNum1: Math.random() * 10}},
***************************************************************************************
<!-- 分割线,这是下面的内容...和VUE好像 -->
<text>数据详情:{{list.name}}{{list.randomNum1}}</text>
<image src="{{list.src}}" mode="widthFix"></image>
<text>\n{{list.randomNum1>=5?'大于等于5':'小于5'}}</text>
【3】算术运算data: {list: {name: "默认名称",src: "https://wdfgdzx.top/document/pre_see/fe78f50f0dee49569735e9c4ab608708.jpg",randomNum1: Math.random().toFixed(2) // 生成一个随机的两位小数}},
***************************************************************************************
<text>数据详情:{{list.randomNum1}}----{{list.randomNum1*100}}</text>
【4】事件绑定:tap input change
event:type事件类型、target触发事件的组件、detail额外的信息
***************************************************************************************
target和currentTarget的区别:
target是触发事件的源头组件,而currentTarget是当前事件所绑定的组件show() {wx.showToast({title: '点击了按钮',})},
***************************************************************************************
<view bindtap="show" style="background-color: aquamarine;"> //currentTarget<button type="primary">按钮</button> // target 
</view>
【5】bindtap的语法格式
<button type="primary" bindtap="show">点击我能响应</button>
***************************************************************************************show(e) {console.log(e)console.log(e.target)wx.showToast({title: '点击了按钮',})},
【6】为data中数据赋新值giveNewVal(e) {this.setData({list: {name: '新值'}})},
***************************************************************************************
<!-- 分割线,这是下面的内容...和VUE好像 -->
<text>{{list.name}}</text>
<button type="primary" bindtap="giveNewVal">重新赋值</button>
***************************************************************************************giveNewVal(e) {this.setData({list: {count: this.data.list.count + 1 // 主要是这里!!!!!!!!!!!!!!!!!!}})},
***************************************************************************************
<text>{{list.count}}</text>
<button type="primary" bindtap="giveNewVal">重新赋值</button>
【7】事件传参
<button type="primary" bindtap="showVal" data-info="{{'大家好'}}">传参调用</button>
***************************************************************************************showVal(e) { // 说明小程序中e很重要的,都能通过它传参了,卧槽 日你大爷//console.log(e.target.dataset.info)wx.showToast({title: e.target.dataset.info,})},
*************************************************************************************** 
<button type="primary" bindtap="showVal" data-info="{{2}}">传参调用</button>// 传的是数值
<button type="primary" bindtap="showVal" data-info="{{'2'}}">传参调用</button> // 传的是字符串
*************************************************************************************** 
注意:小程序不能直接在括号里传参,日尼玛反人类!!!!!!!!!!!!!!!!
【8】bindinput的语法格式showVal(e) {console.log(e.detail.value)  // 这里拿到的方式注意!!!!!!!!!},
*************************************************************************************** 
<input bindinput="showVal" style="background-color: aquamarine;border: 1px solid gray;"></input>
【9】实现文本框和data之间的数据同步,太简单了showVal(e) {console.log(e.detail.value)this.setData({list: {name: e.detail.value}})},
*************************************************************************************** 
<input bindinput="showVal" style="background-color: aquamarine;border: 1px solid gray;"></input>
{{list.name}}
*************************************************************************************** 
不管wxss确实省事很多了,集中精力放在重点的事情上,后面自己一统江山就靠这个了,起飞!!!
【10】条件渲染data: {list: {name: '默认值',flag: false}},
***************************************************************************************  
<text wx:if="{{list.flag}}">true</text>
<text wx:else>false</text>
*************************************************************************************** 
结合<block>使用wx:if,实现整体的显示切换,能够避免在页面渲染不必要的元素。
<block wx:if="{{list.flag}}"><text>true</text><text>\ntrue显示2</text>
</block>
<block wx:else><text>false</text><text>\nfalse显示2</text>
</block>
【11】hidden的使用
<view hidden="{{list.flag}}">false</view>
<view hidden="{{!list.flag}}">true</view>
【12】wx:if与hidden的比对
wx:if是创建和移出、hidden是加样式。和VUE好像呀!!!!!频繁切换用hidden.....
【13】列表渲染wx:fordata: {test: {list: ['陈翔', '球球', '蘑菇头', '米线儿', '闰土']}},
*************************************************************************************** 
<view wx:for="{{test.list}}">索引是:{{index}} 当前项:{{item}}
</view>
*************************************************************************************** 
wx:key的使用,可以提高渲染效率
<view wx:for="{{test.list}}" wx:key="index">索引是:{{index}} 当前项:{{item}}
</view>
*************************************************************************************** data: {test: {list: [{id:1,name:'陈翔'},{id:2,name:'球球'},{id:3,name:'米线儿'},]}},
*************************************************************************************** 
<view wx:for="{{test.list}}" wx:key="id"> // 数据库查询的基本都有id索引是:{{index}} 当前项:{{item.name}}
</view>

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

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

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

8、app.json全局配置     
【1】app.json就是全局配置文件!!!!!!!!!!!!!!!!!!
**********************************************************************************************
@pages 记录当前小程序所有页面的存放路径
@window 全局设置小程序窗口的外观
@设置小程序底部的tabBar效果
@style 是否启用新版组件样式
【2】window常用配置
navigationBar开头的都是配置导航栏效果的
backgroundColor开头的都是配置窗口背景的
下拉刷新页面效果的选项
**********************************************************************************************
"navigationBarTitleText": "物品回收",  配置标题文本的
**********************************************************************************************
设置导航栏的背景色
"navigationBarBackgroundColor": "#2b4b6b",
"navigationBarBackgroundColor":"#00B26A"
**********************************************************************************************
设置标题文字颜色
"navigationBarTextStyle": "white"
**********************************************************************************************
全局开启下拉刷新功能"window": {"backgroundTextStyle": "light","navigationBarBackgroundColor": "#2b4b6b","navigationBarTitleText": "物品回收","navigationBarTextStyle": "white","enablePullDownRefresh": true  //!!!!!!!!!!!!!!!!!!!这个点!!!!!!},
这个下拉刷新,会作用全局所有页面。
模拟器并不能100%还原真机,发布的时候还是用真机测试下!!!!!!!!!
**********************************************************************************************
"backgroundColor": "#efefef"   配置下拉刷新区域的颜色值。
**********************************************************************************************
设置下拉刷新时,loading效果"window": {"backgroundTextStyle": "dark", // !!!!!!!!!!!!!!!!!!!!!"navigationBarBackgroundColor": "#2b4b6b","navigationBarTitleText": "物品回收","navigationBarTextStyle": "white","enablePullDownRefresh": true,"backgroundColor": "#efefef"},
**********************************************************************************************
设置上拉触底的距离:上拉滑动操作,来加载更多数据的问题。
onReachBottomDistance 默认是50px加载下一页,如果希望改变。不建议改,50px即可"window": {"backgroundTextStyle": "dark","navigationBarBackgroundColor": "#2b4b6b","navigationBarTitleText": "物品回收","navigationBarTextStyle": "white","enablePullDownRefresh": true,"backgroundColor": "#efefef","onReachBottomDistance": 100 // 知识说明下这个知识点},
【3】tabBar:实现多页面的快速切换,一般是底部tabBar(2-5项标签)
6个组成部分:backgroundColor tabBar的背景色。
selectedIconPath:选中时图片路径
borderStyle 上边框颜色
iconPath:未选中的图片路径
selectedColor:选中的时候的颜色
color:未选中时候的颜色
**********************************************************************************************
配置tabBar效果!!!!!!!!!!!!!!!!
{"pages": ["pages/index/index","pages/test/test","pages/logs/logs"],"window": {"backgroundTextStyle": "dark","navigationBarBackgroundColor": "#2b4b6b","navigationBarTitleText": "物品回收","navigationBarTextStyle": "white","enablePullDownRefresh": true,"backgroundColor": "#efefef"},"style": "v2","sitemapLocation": "sitemap.json","tabBar": {  //  !!!!!!!!!!!!!!!!"list": [{"pagePath": "pages/index/index",  //  !!!!!!!!!!!!!!!!"text": "主页"},{ "pagePath": "pages/test/test",   //  !!!!!!!!!!!!!!!!"text": "测试"}]}
}
**********************************************************************************************
有了云服务器真方便,自己的七牛云呀,嘿嘿嘿!!!必须放在本地,emmm 有意思!!!!!
"tabBar": {"list": [{"pagePath": "pages/index/index","text": "主页","iconPath": "/common/主页1.png","selectedIconPath": "/common/主页2.png"},{"pagePath": "pages/test/test","text": "测试","iconPath": "/common/测试1.png","selectedIconPath": "/common/测试2.png"}]}

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

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

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

10、发起网络请求
【1】网络数据请求,只能请求https类型的接口
必须将接口的域名添加到信任列表中,我就信任https://wdfgdzx.top  哈哈
https://mp.weixin.qq.com/wxamp/devprofile/get_profile?token=1582776250&lang=zh_CN
上述地址添加
**********************************************************************************************
不能用localhost,而且还必须备案,emmm
【2】发起get请求getInfo() {wx.request({url: 'https://wdfgdzx.top/wx_test', // 请求的地址接口,必须基于https协议method: 'GET', // 请求的方式data: { // 发送到服务器的数据 page: 1},success: res => {wx.showToast({title: res.data,icon: 'success',duration: 2000}); // 请求成功之后的回调函数}})},
**********************************************************************************************getInfo() {let thisA = this;  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!wx.request({url: 'https://wdfgdzx.top/wx_test', // 请求的地址接口,必须基于https协议method: 'GET', // 请求的方式data: { // 发送到服务器的数据 page: 1},success: res => {thisA.setData({   // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"test": {"name": res.data}})}})},
【3】发起post请求   P34   16分postInfo() {let thisA = this;wx.request({url: 'https://wdfgdzx.top/wx_post',method: "post",data: {name: "接口必将返回---陈翔六点半"},success: (res) => {thisA.setData({"test": {"name": res.data}})}})},
**********************************************************************************************
<button type="primary" bindtap="postInfo">发起网络请求</button>
<view>{{test.name}}</view>
【4】页面加载时,请求数据onLoad(options) {wx.showToast({title: '执行了!',})this.wx_post()},
【5】跳过request合法域名校验
合法域名校验只提供了https
***************************************************************************************
但是为了方便开发,可以在:设置-项目设置-不校验合法域名!
注意只能在开发与调试阶段使用。
***************************************************************************************
关于跨域问题,小程序是不存在的,吼吼牛批!!!!!!!!!
***************************************************************************************
Ajax技术依赖于XMLHttpRequest,小程序的请求是自带的,是叫发起网络请求!

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

11、本地生活案例
【1】步骤
新建项目--->配置导航栏效果--->配置tabBar效果--->实现轮播图--->九宫格效果--->图片布局
【2】项目备份+项目结构改变"pages": ["pages/home/home","pages/message/message","pages/contact/contact"],【3】配置导航栏的效果"window": {"backgroundTextStyle": "dark","navigationBarBackgroundColor": "#2b4b6b","navigationBarTitleText": "本地生活","navigationBarTextStyle": "white","enablePullDownRefresh": true,"backgroundColor": "#efefef"},
【4】配置tabBar"tabBar": {"list": [{"pagePath": "pages/home/home","text": "首页","iconPath": "/common/主页2.png","selectedIconPath": "/common/主页1.png"},{"pagePath": "pages/message/message","text": "消息","iconPath": "/common/消息2.png","selectedIconPath": "/common/消息1.png"},{"pagePath": "pages/contact/contact","text": "联系","iconPath": "/common/联系2.png","selectedIconPath": "/common/联系1.png"}]}
【5】实现轮播图
<!-- 轮播图区域 -->
<swiper style="height: 350rpx;" indicator-dots="true" circular="true"><swiper-item wx:for="{{home.list}}" wx:key="id"><image src="{{item.preview}}" style="width: 100%;height: 100%;"></image></swiper-item>
</swiper>
【6】实现九宫格数据
<!-- 九宫格数据 -->
<view style="display: flex;flex-wrap: wrap;border-left: 1rpx solid #efefef;border-top: 1rpx solid #efefef;"><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;"><image src="{{item.preview}}" style="width: 60rpx;height: 60rpx;"></image><text style="font-size: 24rpx;margin-top: 10rpx;">{{item.name}}</text></view>
</view>
【7】底部图片的展示
<!-- 图片区域 -->
<view style="display: flex;padding: 20rpx 10rpx;justify-content: space-around;"><image src="{{home.list[0].preview}}" mode="widthFix" style="width: 45%;"></image><image src="{{home.list[1].preview}}" mode="widthFix" style="width: 45%;"></image>
</view>
***************************************************************************************************
发现没?当wxss融入了wxml,逻辑非常清晰,就是样式的调整而已,还不简单吗!!!!哈哈
***************************************************************************************************  data: {home: {list: []}},
selectHomeList() {// let thisA = this;wx.request({url: 'https://localhost/document/list_page',method: 'post',data: {currentPage: 1,pageSize: 9},success: (res) => {// console.log(res.data.object.data)this.setData({home: {list: res.data.object.data}})// console.log(this.data.home.list)}})},

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

12、页面间导航跳转
【1】页面之间的相互跳转
传统HTML:<a>链接跳转、localtion.href跳转
*********************************************************************************************
小程序实现跳转的两种方式:
@声明式导航:<navigator>
@编程式导航:调用小程序的导航API,实现页面的跳转
*********************************************************************************************
<navigator url="/pages/contact/contact" open-type="switchTab" style="background-color: aqua;">跳转联系页面</navigator>
open-type="switchTab"这个必须指定,不然不能跳转对应的tabBar页面。
注意点!!!!!!!!!!!!!!!!!!!!
*********************************************************************************************
跳转非tabBar页面
<navigator url="/pages/info/info" style="background-color: aqua;">跳转info页面</navigator>
这个自己前面用了很多了!!!!!!!!!!!!!!!
【2】后退导航
<navigator open-type="navigateBack" delta="1" style="background-color: aqua;">返回上一页</navigator>
open-type="navigateBack"  注意!!!!!!!!!!!!!!!!!!!!
delta="1"   注意!!!!!!!!!!!!!!!!!!!!
【3】编程式导航
跳转tabBar页面:
<button bindtap="goContact">跳转联系页面</button> 这个就是在js方法里用函数调转了
*********************************************************************************************
goContact() {wx.switchTab({  // 注意!!!!!!!!!!!!!url: '/pages/contact/contact',})},
*********************************************************************************************
跳转到非tabBar页面
<button bindtap="goInfo">跳转info页面</button>goInfo() {wx.navigateTo({  // 注意!!!!!!!!!!!!!url: '/pages/info/info',})},
*********************************************************************************************
后退导航:
<button bindtap="goBack">后退</button>goBack() {wx.navigateBack()},
感觉学会声明式就行了。
【4】声明式导航传参
<navigator url="/pages/info/info?name='陈翔'&age=20">跳转到info页面</navigator>
*********************************************************************************************
goInfo() { // 编程式导航传参wx.navigateTo({  // 注意!!!!!!!!!!!!!url: '/pages/info/info?name='陈翔'&age=20',})},
*********************************************************************************************
在onLoad中接收导航参数
data: {
name: '',
age: ''
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log(options)  // 这里接收了
this.setData({"name": options.name,"age": options.age
})
},
*********************************************************************************************
data: {
query: {}   // 老师还是牛批,封装的思想
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log(options)
this.setData({query: options   // 老师还是牛批,封装的思想
})
},

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

13、下拉刷新
【1】概述
就是下拉开启刷新效果;
"enablePullDownRefresh": true,
**********************************************************************************
建议在页面的.json配置文件中开启"enablePullDownRefresh": true,
{"usingComponents": {},"enablePullDownRefresh": true  // 这里!!!!!!!!!!!!!!!
}
**********************************************************************************
设置样式:我是在app.json中统一配置的!!!!
"navigationBarTextStyle": "white",
"backgroundColor": "#efefef"
【2】监听页面的下拉刷新事件,主要实现下拉后count的值置为0
<view>count的值是:{{count}}</view>
<button bindtap="addCount">自增+1</button>
**********************************************************************************onPullDownRefresh() {console.log("触发下拉刷新");this.setData({count: 0})},
**********************************************************************************
解决下拉刷新后,没有自动关闭刷新效果的问题:
onPullDownRefresh() {// console.log("触发下拉刷新");this.setData({count: 0})wx.stopPullDownRefresh() // !!!!!!!!!!!!!!!!!!这里是重点},

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

14、上拉加载  
【1】上拉触底概念
这个操作往往是实现分页功能的。
【2】监听上拉触底事件
<view style="height: 2000rpx;background-color: aqua;"></view>
*******************************************************************************************
// 需要做节流处理,访问非法的数据请求onReachBottom() {console.log("触发了上拉触底事件")},
*******************************************************************************************
配置上拉触底的距离,一般不需要配置
{"usingComponents": {},"onReachBottomDistance": 100
}
【3】上拉触底案例介绍
定义获取随机颜色的方法-在页面加载时获取初始数据-渲染UI结构美化页面效果
-在上拉触底时调用获取随机颜色的方法-添加loading提示效果-对上拉触底节流
*******************************************************************************************data: {photoList: []},getPhotoList() {wx.request({url: 'https://localhost/document/list_page',method: 'post',data: {currentPage: 1,pageSize: 18},success: (res) => {// console.log(res.data.object.data)this.setData({// 新旧数据拼接,得到大数组photoList: [...this.data.photoList, ...res.data.object.data] // 这里是个关键点})// console.log(this.data.home.list)}})},
*******************************************************************************************
果然什么都要用自己的数据,这样才能知道底层的一些东西,是怎么用的,怎么提供的!!!!
UI结构的渲染:
<view wx:for="{{photoList}}" wx:key="id"><image src="{{item.preview}}" style="width: 100%;border-radius: 10rpx;"></image>
</view>
*******************************************************************************************
上拉触底后再次调用getPhotoList()函数onReachBottom() {// console.log("执行了")this.getPhotoList()  // 会再次发起wx.request请求},
*******************************************************************************************
添加loading效果
getPhotoList() {
wx.showLoading({title: '数据加载中...', // 本地的网络太好了,效果一闪而过
})
wx.request({url: 'https://localhost/document/list_page',method: 'post',data: {currentPage: 1,pageSize: 18},complete: (res) => {wx.hideLoading()},
*******************************************************************************************
解决上拉处理节流的问题:!!!!!!!!!!!!!!!!!!!
定义节流阀--->修改loadingFlag的值--->判断loadingFlag从而实现节流(红绿灯)
getPhotoList() {  // VUE的语法也能用呀 哈哈哈哈哈!!!!!!!!!!!!
wx.showLoading({title: '数据加载中...',
})
this.data.loadingFlag = true
wx.request({url: 'https://localhost/document/list_page',method: 'post',data: {currentPage: 1,pageSize: 18},complete: (res) => {wx.hideLoading()this.data.loadingFlag = false},
*******************************************************************************************onReachBottom() {// console.log("执行了")if (!this.data.loadingFlag) {this.getPhotoList()} else {return}},
【4】自定义编译模式
在普通编译-添加编译模式-里面来改变,方便直接看当前修改页面的效果!!!!!!!
提高开发效率是最根本的目的!!!!!!!!!!!!!

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

15、生命周期函数
【1】概述
生命周期:创建---运行---销毁的整个阶段。强调的是一个时间段。
*****************************************************************************************
小程序从开始运行,到程序结束关闭的阶段。
【2】分类
应用生命周期:小程序的启动-运行-销毁的过程
页面生命周期:页面的加载---渲染---销毁的过程
应用生命周期>页面生命周期
小程序启动---页面A的生命周期---页面B的生命周期---...---小程序结束
【3】生命周期函数
作用:允许程序员在特定的时间点,执行某些特定的操作
onLoad:页面初始化数据
生命周期函数:强调的是时间点。
【4】生命周期函数分类:
应用的生命周期函数、页面的生命周期函数
应用的生命周期函数
*******************************************************************************************
需要再app.js中声明:
onLaunch、onShow、onHide
console.log("触发了onLaunch...")
*******************************************************************************************
onShow  从手机进入小程序
onHide 从手机退出小程序
【5】页面声明周期函数
onLoad()  // 初始化页面 仅调用一次!!!!!!!!!!!!!!!!!
onShow() // 页面展示
onReady() // 初次渲染完毕后,可以修改页面的UI结构了!!!!!!!!
onHide()// 页面被隐藏了
onUnload()// 一个页面调用一次
【6】wxs脚本概述
wxs典型应用场景是”过滤器“
*******************************************************************************************
wxs类似于js,不支持ES6及以上语法、wxs遵循了CommonJS规范
*******************************************************************************************
wxs内嵌使用语法:可以内嵌到wxml中
可以用于封装方法呀 感觉!!!!!!!!!!!
<!--pages/message/message.wxml-->
<text>pages/message/message.wxml</text>
<view>count的值是:{{count}}</view>
<button bindtap="addCount">自增+1</button>
{{name}}
{{m1.toUpperCase(name)}} // 使用!!!!!!!!!!!!!!!!
<wxs module="m1"> // 定义!!!!!!!!!!!!!!!!!!!module.exports.toUpperCase = function (str) {return str.toUpperCase()}
</wxs>
*******************************************************************************************
定义外联的wxs脚本!!!!!!!!!!!!!!!!!!!!!!
/* tools.wxs */
function toUpperCase(str) {return str.toUpperCase()
}
module.exports = {toUpperCase: toUpperCase  // 和VUE不一样,不能使用简写!!!!!!!!!!
}<!--pages/message/message.wxml-->
<text>pages/message/message.wxml</text>
<view>count的值是:{{count}}</view>
<button bindtap="addCount">自增+1</button>
{{name}}
{{m1.toUpperCase(name)}}<wxs src="../../utils/tools.wxs" module="m1"></wxs> // !!!!!!!!!!这里是重点
*******************************************************************************************
wxs特点,wxs和js是两种语言。
wxs典型场景就是过滤器,要配合胡子语法使用!!!!!!有很大局限性呀
隔离性:wxs运行环境和其他js代码是隔离的
wxs不能调用js中定义的函数,也不能调用小程序提供的API
性能好:iOS上而已,会快2-20倍,在安卓上一样。

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

16、本地生活案例扩展
【1】完成列表页面的开发
效果:页面导航传参---上拉触底---下拉刷新
***************************************************************************************
<!-- 九宫格数据 -->
<view style="display: flex;flex-wrap: wrap;border-left: 1rpx solid #efefef;border-top: 1rpx solid #efefef;"><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;"><image src="{{item.preview}}" style="width: 60rpx;height: 60rpx;"></image><text style="font-size: 24rpx;margin-top: 10rpx;">{{item.name}}</text></navigator>
</view>
导航+传参navigator url="/pages/beauty_list/beauty_list?id={{item.id}}&name={{item.name}}"
***************************************************************************************
动态设置页面的标题data: {query: {}},
***************************************************************************************onLoad(options) {// console.log(options)this.data.query = options; // 还是我牛批  三步走!!!!!!说明可以用this.data.query来赋值},
***************************************************************************************onReady() {wx.setNavigationBarTitle({title: this.data.query.name,})},
***************************************************************************************query: {},  // 重新定义包装数据类型 // 神经百战才知道结构化和统一性的重要性!!!!!!!!!!!!// 要不统一改写自己的VUE项目吧,感觉肯定是获益匪浅!!!!!!!!!!!!!!list: [],sendData: {currentPage: 1, // 这里都是和服务器对应的pageSize: 9},sendDataForm: {total: 0},returnData: {}
***************************************************************************************
事实证明: 更靠谱点 卧槽 emmm
this.setData({list: res.data.object.data
})
可以优化,但是不要玩火!!!!!!!!!!!!
【2】列表页面的开发list: [...this.data.list, ...res.data.object.data],  这个写法需要注意下!!!!!!!!
***************************************************************************************
排查了一圈,感觉自己的后端逻辑代码真牛皮。
<!--pages/beauty_list/beauty_list.wxml-->
<!-- <text>pages/beauty_list/beauty_list.wxml</text> -->
<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;"><view><image src="{{item.preview}}" style="width: 250rpx;height:250rpx;display: block;margin-right: 15rpx;"></image></view><view style="display: flex;flex-direction: column;justify-content: space-around;font-size: 24rpx;"><text style="font-weight: bold;">名称:{{item.name}}</text><text>大小:{{item.size}}</text><text>类型:{{item.type}}</text><text>MD5:{{item.md5}}</text></view>
</view>
***************************************************************************************55集0分钟
实现加载中效果!!!!!!!!!!!!!!!!wx.showLoading({title: '数据加载中...',})
complete: () => {wx.hideLoading()},
***************************************************************************************
上拉触底的分页加载效果:
onReachBottom() {
// console.log("执行了")
this.data.sendData.currentPage = this.data.sendData.currentPage + 1
console.log(this.data.sendData)  // 我搞的好,当超过3也的时候,会不断加载第一页
this.selectList()  
},
***************************************************************************************
定义节流阀
loadingFlag: false
selectList() {// let thisA = this;this.data.loadingFlag = truewx.showLoading({title: '数据加载中...',})wx.request({url: 'https://localhost/document/list_page',method: 'post',data: this.data.sendData,complete: () => {wx.hideLoading()this.data.loadingFlag = false},onReachBottom() {// console.log("执行了")if (!this.data.loadingFlag) {this.data.sendData.currentPage = this.data.sendData.currentPage + 1console.log(this.data.sendData)} else {return false}this.selectList()},
Network下网络改成slow 3G可以模拟出效果
【3】分页问题的处理
如果只有3页,会发送为第4 5页的请求吗?
自己虽然牛批,但是还需要处理重复的数据的.....
***************************************************************************************
页码值*每页数据>=总页数了,就没有下一页了!!!!牛批!!!哥哥
if (this.data.sendData.currentPage * this.data.sendData.pageSize >= this.data.returnData.total) {// 证明没有下一页了return wx.showToast({title: '数据加载完毕!',icon: "none"})
}
***************************************************************************************
启动下拉刷新
{"usingComponents": {},"enablePullDownRefresh": true // !!!!!!!!!!!!!!!!
}
*****************************************
onPullDownRefresh() {// 下拉刷新充值关键数据this.data.sendData.currentPage = 1this.data.list = []this.data.returnData.total = 0// 重新发起请求console.log(this.data.sendData)this.selectList()},
*****************************************
解决下拉刷新不会自动关闭的问题
complete: () => {wx.hideLoading()this.data.loadingFlag = falsewx.stopPullDownRefresh()  // 自动关闭下拉刷新的效果},
优化下*********************this.selectList(() => {wx.stopPullDownRefresh()})
********************************************
selectList(cb) {
// let thisA = this;
this.data.loadingFlag = true
wx.showLoading({title: '数据加载中...',
})
wx.request({url: 'https://localhost/document/list_page',method: 'post',data: this.data.sendData,complete: () => {wx.hideLoading()this.data.loadingFlag = false// wx.stopPullDownRefresh()cb && cb()},success: (res) => {// console.log(res)this.setData({list: [...this.data.list, ...res.data.object.data],returnData: {total: res.data.object.total - 0}})console.log(this.data.list)}
})
},
【4】wxs店铺手机号的处理:过滤器
/* tools.wxs */
function toUpperCase(str) {return str.toUpperCase()
}function shortMd5(str) {return str.substring(0, 23)
}module.exports = {toUpperCase: toUpperCase,shortMd5: shortMd5
}
*****************************************************************<view style="display: flex;flex-direction: column;justify-content: space-around;font-size: 24rpx;"><text style="font-weight: bold;">名称:{{item.name}}</text><text>大小:{{item.size}}</text><text>类型:{{item.type}}</text><text>MD5:{{tools.shortMd5(item.md5)}}</text></view>
</view><wxs src="../../utils/tools.wxs" module="tools"></wxs>
真能实现我的md5缩减功能,牛批,过滤手机电话号码,应该是一样的
【5】总结
导航跳转、下拉刷新、上拉加载更多、知道小程序的生命周期函数

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

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

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

17、自定义组件
【1】创建组件
在componets--->test文件夹--->新建Component
组件也是对应4个文件:.js、.json、.wxml和.wxss
每个组件建议存在单独的目录中,如test1组件 test2组件,创建Component选项
【2】组件的应用
局部引用、全局引用!
{"usingComponents": {"test1": "/components/test1/test1"}
}
********************************************************************************************
直接使用即可!!!!!感觉VUE使用还行,小程序有点杀鸡用牛刀的感觉吧
<!-- home.wxml -->
<test1></test1>
【3】全局引用
在app.json里 和pages平级,增加配置,即可
"usingComponents": {
"test1": "/components/test1/test1"
}
【4】全局引用与局部引用的使用场景!
如果会在多个页面,建议全局引用。
如果只在少数页面使用,建议使用局部引用。
【5】组件和页面的区别?
@组件的test1.json中必须有个字段,  "component": true,
@组件的test1.js中,调用的是Component函数
@组件的函数,需要定义到methods节点中,和VUE一样了!!!!!
【6】组件的样式隔离   63集 0分钟(数据记录 三方管理继续修改)
组件样式有隔离的特性:页面不会影响组件,组件不会影响页面
***************************************************************************************
组件样式隔离的注意点:全局样式声明的样式表对组件是无效的。(仅是类选择器)
.g_red_text {color: red;
}
<text class="g_red_text">components/test1/test1.wxml</text>
***************************************************************************************
只有这样才有效
<text style="color: green;">components/test1/test1.wxml</text>
***************************************************************************************
所以使用的使用建议使用类选择器,这样能样式隔离,我更懒,我就用style,嘿嘿嘿...
***************************************************************************************
修改组件的样式隔离选项:
Component({options: {styleIsolation: 'apply-shared' // isolated默认  apply-shared页面影响组件  shared 双向影响},这时候页面就影响组件了:
<text class="allRed">components/test1/test1.wxml</text>
就是样式的额变化,没有必要这么玩,都搞迷糊了,卧槽!!!!!!!!!!!!!!!
【7】自定义组件-数据方法和属性data: {name: '组件'},
***************************************************************************************
_myShowToast() {wx.showToast({title: 'name的值:' + this.data.name,icon: 'none'})
}
只要是自己定义的函数都以_开头。methods: {addPoint() {this.setData({name: this.data.name + '.'})this._myShowToast()},_myShowToast() {wx.showToast({title: 'name的值:' + this.data.name,icon: 'none'})}}
***************************************************************************************
<!--components/test1/test1.wxml-->
<text>components/test1/test1.wxml</text>
<view>name的值是:{{name}}
</view>
<button bindtap="addPoint">给name加.</button>
***************************************************************************************
就是VUE的prop卧槽,现在才明白!!!!!!!!!!!!!!!!!!!!
properties: {max: {type: Number,value: 10 // 默认值},min: Number // 简化形式},
***************************************************************************************
<!--components/test1/test1.wxml-->
<text>components/test1/test1.wxml</text>
<view>name的值是:{{name}}
</view>
<button bindtap="addPoint">给name加.</button>
我的prop是:{{max}} {{min}}  !!!!!!!!!!!!!!!
***************************************************************************************
<!-- home.wxml -->
<test1 max="5" min='2'></test1>
***************************************************************************************
展示的是我的prop是: 5  2 ,懂了吧!!!!!!!!!!!!!!!!!!!methods: {addPoint() {if (this.data.count >= this.properties.max) { //控制自增最大值!!!!!!!!!!!!return false}this.setData({count: this.data.count + 1})this._myShowToast()},_myShowToast() {wx.showToast({title: 'count的值:' + this.data.count,icon: 'none'})}}
***************************************************************************************
data和properties的区别:小程序里都差不多。
data存储私有数据,properties是外界传过来的数据,两者都是可读可写的。
this.data.xxx
this.properties.xxx  注意下使用的区别!!!!!!!!!!!!!!!!
***************************************************************************************
setData修改properties的值
this.setData({count: this.data.count + 1,min: this.properties.min - 1 // !!!!!!!!!!注意是this.properties哦!!!!!})
【8】自定义组件-数据监听器
类似VUE里的watch侦听器observers: {'count,min': function name(count, min) {console.log("count的值发生变化:" + count + "---" + min)}}说明不仅能监控data,还能监控properties,卧槽 卧槽 好屌呀
***************************************************************************************
监听器监听对象属性的变化:observers: {'person.name,person.age': function name(name, age) {console.log("person属性的值发生变化:" + name + "---" + age)}}
***************************************************************************************
数据监听器案例:
<!--components/test1/test1.wxml-->
<text>components/test1/test1.wxml</text>
<view style="background-color: rgb({{fullColor}});line-height: 200rpx;font-size: 24rpx;color: white;text-shadow: 0rpx 0rpx 2rpx black;text-align: center;">颜色值:{{fullColor}}
</view>
<button size="mini" bindtap="changeR" type="default"></button>
<button size="mini" bindtap="changeG" type="primary"></button>
<button size="mini" bindtap="changeB" type="warn"></button>
***************************************************************************************
// components/test1/test1.js
Component({/*** 组件的初始数据*/data: {rgb: {r: 0,g: 0,b: 0},fullColor: '0,0,0'},/*** 组件的方法列表*/methods: {changeR() {this.setData({'rgb.r': this.data.rgb.r + 5 > 255 ? 255 : this.data.rgb.r + 5 // 看看对象的赋值})},changeG() {this.setData({'rgb.g': this.data.rgb.g + 5 > 255 ? 255 : this.data.rgb.g + 5 // 看看对象的赋值})},changeB() {this.setData({'rgb.b': this.data.rgb.b + 5 > 255 ? 255 : this.data.rgb.b + 5 // 看看对象的赋值})},},observers: {'rgb.r,rgb.g,rgb.b': function name(r, g, b) {this.setData({fullColor: `${r},${g},${b}`})}}
})
***************************************************************************************
对象监控的优化:!!!!!!!!!!!!!!!!!对象.**observers: {'rgb.**': function name(obj) {this.setData({fullColor: `${obj.r},${obj.g},${obj.b}`})}}
【9】自定义组件-纯数据字段
什么是纯数据字段?那些不用于界面渲染的data字段,比如r g b就是纯数据字段。
***************************************************************************************
纯数据字段能够提升页面更新的性能。
***************************************************************************************
怎么定义?options: {pureDataPattern: /^_/ // 凡是以_开头的都是纯数据字段},data: {_a: true, // 纯数据字段
***************************************************************************************
全局改造!!!!!!!!!!!!!!!!!!提升性能!!!!!!!!!!
// components/test1/test1.js
Component({/*** 组件的初始数据*/options: {pureDataPattern: /^_/ // 凡是以_开头的都是纯数据字段},data: {_rgb: {r: 0,g: 0,b: 0},fullColor: '0,0,0'},/*** 组件的方法列表*/methods: {changeR() {this.setData({'_rgb.r': this.data._rgb.r + 5 > 255 ? 255 : this.data._rgb.r + 5})},changeG() {this.setData({'_rgb.g': this.data._rgb.g + 5 > 255 ? 255 : this.data._rgb.g + 5})},changeB() {this.setData({'_rgb.b': this.data._rgb.b + 5 > 255 ? 255 : this.data._rgb.b + 5})},},observers: {'_rgb.**': function name(obj) {this.setData({fullColor: `${obj.r},${obj.g},${obj.b}`})}}
})
【10】组件的生命周期
created:常用
attached:常用
ready
moved
detached:常用
error
***************************************************************************************
主要的生命周期函数:
created 组件示例刚创建好的时候,这时候还不能使用setData
attached 这时候setData可以执行,可以进行初始化数据
detached 组件被销毁的时候,适合做一些清理性质的工作
***************************************************************************************
如何定义组件的生命周期函数:
lifetimes节点:(新的方式,推荐的)
// components/test1/test1.js
Component({data: {},/*** 组件的方法列表*/lifetimes: {created() {console.log('created 执行')},attached() {console.log('attached 执行')}},methods: {},
})
【11】自定义组件-组件所在!!!“页面”!!!的生命周期函数
例如:每当触发页面show生命周期函数时,希望生成一个随机的RGB颜色值
***************************************************************************************
组件所在页面的声明周期函数有3个:show hide resize
***************************************************************************************
pageLifetimes节点:
// components/test1/test1.js
Component({data: {},/*** 组件的方法列表*/pageLifetimes: { // 所在页面的生命周期函数show() {console.log("show 执行")},hide() {console.log("hide 执行")},resize() {console.log("resize 执行")}},methods: {},
})
***************************************************************************************
// components/test1/test1.js  这个是我自己实现的呦!!!!!!!!!!!!!!!
Component({data: {_rgb: {r: 0,g: 0,b: 0},fullColor: '0,0,0'},/*** 组件的方法列表*/pageLifetimes: { // 所在页面的生命周期函数show() {console.log("show 执行")this._randomColor()},hide() {console.log("hide 执行")},resize() {console.log("resize 执行")}},methods: {_randomColor() {this.setData({_rgb: {r: Math.floor(Math.random() * 256),g: Math.floor(Math.random() * 256),b: Math.floor(Math.random() * 256),},})this.setData({fullColor: this.data._rgb.r + ',' + this.data._rgb.g + ',' + this.data._rgb.b})// console.log(this.data.fullColor)}},
})
【12】自定义组件-插槽
什么是插槽?用于承载!!!!组件使用者!!!提供的wxml结构。
<slot></slot>
好像VUE也没怎么用过,鸡肋
***************************************************************************************
单个插槽:
<!--components/test1/test1.wxml-->
<view><view>这是组件的内部节点</view><slot></slot>
</view>
***************************************************************************************
<test1><view style="color: red;">这里是插入到slot中的content</view>
</test1>
***************************************************************************************
启用多个插槽
options: {multipleSlots: true // 启用多个插槽},
***************************************************************************************
多个要给slot 加name属性加以区分
<!--components/test1/test1.wxml-->
<view><slot name="one"></slot><view>这是组件的内部节点</view><slot name="two"></slot>
</view>
***************************************************************************************
<test1><view style="color: red;" slot="one">这里是插入到slot one中的content</view><view style="color: red;" slot="two">这里是插入到slot two中的content</view>
</test1>
【13】父子组件之间的通信
三种方式:属性绑定(父-子)   事件绑定(子-父)    获取组件实例
***************************************************************************************
属性绑定!!!!!!!!!!!:home首页是父组件   test1是子组件!!!!!!!!!!!
<!-- home.wxml -->
<view>父组件中count的值:{{count}}</view>
<!-- 组件 -->
<test1 count="{{count}}">子组件:</test1>
*****************************************
data: { // 父组件count: 0},
***************************************************************************************
子组件接收:使用properties: {count: Number},
*****************************************
<!--components/test1/test1.wxml-->
<view>我是子组件~~~~~~~~count的值是:{{count}}
</view>
*****************************************
子组件自增+1
addCount() {this.setData({fff_son_count: this.properties.fff_son_count + 1})}
*****************************************
发现子组件是变化了,但是父组件没变化,所以要实现子组件向父组件传值:事件绑定!!!!!
***************************************************************************************
事件绑定!!!!!!!!!!!!!!!!!!!!!!!!!!!!!子传父
父组件js定义函数// 供子组件调用的函数son_fff_count() {console.log("son_fff_count")},
*****************************************
<test1 fff_son_count="{{count}}" bind:son_fff_count="son_fff_count">子组件:</test1>
*****************************************
this.triggerEvent("son_fff_count")
*****************************************this.triggerEvent("son_fff_count", {value: this.properties.fff_son_count // 传递的值})
*****************************************// 供子组件调用的函数son_fff_count(e) {console.log("son_fff_count " + e.detail.value)this.setData({count: e.detail.value})},
***************************************************************************************
至此就实现了父传子、子传父了,牛批!!!!!!!!!!!!!!!
***************************************************************************************
获取组件实例实现父子组件的通信!!!!!!!!!!
建议使用id选择器:
<test1 fff_son_count="{{count}}" bind:son_fff_count="son_fff_count" id="sonTest1">子组件:</test1>
<!-- 通过获取实例 -->
<button bindtap="getSon">获取子组件实例</button>
***************************************************************************************getSon() {const test1 = this.selectComponent("#sonTest1")console.log(test1)  test1.setData({  // 直接操作子组件fff_son_count: test1.properties.fff_son_count + 1})},

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

18、behaviors作用
【1】概念
用于实现组件间代码共享的特性,类似vue.js中的mixins,类java的静态变量呀。
***********************************************************************************
每一个组件可以引用多个behavior,behavior也可以引用其他behavior
【2】behavior的创建
module.exports = Behavior({data: {name: '陈翔'},properties: {},methods: {}
})
【3】导入并使用behavior
// components/test1/test1.js
const my_behavior = require('../../behaviors/my_behavior.js')Component({behaviors: [my_behavior],
***********************************************************************************
使用:
<view>在behavior中定义的用户名是:{{name}}
</view>
【4】behavior中所有可用的节点
properties、data、methods、behaviors(引入其他behavior的作用)
***********************************************************************************
同名字段的覆盖和组合规则。这也太low了
【5】组件-总结
创建并引用组件 usingComponents
***********************************************************************************
修改组件的样式隔离选项
***********************************************************************************
如何定义和使用数据监听器
***********************************************************************************
能够知道如何定义和使用纯数据字段
***********************************************************************************
知道实现组件父子通信有哪3中方式
***********************************************************************************
知道定义和使用behaviors

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

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

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

 20、MobX实现全局数据共享【1】什么是全局数据共享?
Vuex Redx Mobx  更强大的组件间的数据传递
***************************************************************************************
mobx-miniprogram来创建save示例对象
mobx-miniprogram-bindings 把save中的共享数据或方法,绑定到组件或页面中使用
***************************************************************************************
npm i --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1
-------------------------------------------------------------------------------------
删除miniprogram_npm,然后执行工具---npm构建
【2】创建Mbox save实例
// 在这里js中专门创建save实例对象
import {observable
} from 'mobx-miniprogram'export const save = observable({saveName: '陈翔',saveAge: 26
})
***************************************************************************************
// 在这里js中专门创建store实例对象
import {action,observable
} from 'mobx-miniprogram'export const store = observable({storeName: '陈翔',storeAge: 26,// 定义计算属性get add() { // add就是计算属性的名字return this.storeAge + 1},// 定义全局方法修改save里的数据updateStoreAge: action(function (step) {this.storeAge = this.storeAge + step})
})
【3】如何将save里的成员绑定到页面中?
// pages/message/message.js
import {createStoreBindings
} from 'mobx-miniprogram-bindings'
import {store
} from '../../store/store'
-------------------------------------------------------------------------------------
onLoad(options) {this.saveBindings = createStoreBindings(this, {save,fields: ['saveName', 'saveAge'],actions: ['updateSaveAge']})},onUnload() {this.saveBindings.destroyStoreBindings()},
【4】在页面上使用save里的成员
<view>{{storeName}} {{storeAge}}
</view>
<vant_button type="primary" bindtap="saveAgeAdd">storeAge+1</vant_button>
<vant_button type="danger" bindtap="saveAgeReduce" data-step="{{-2}}">storeAge-2</vant_button>
-------------------------------------------------------------------------------------saveAgeAdd() {// console.log("saveAgeAdd")this.updateStoreAge(1)},saveAgeReduce(e) {// console.log(e)this.updateStoreAge(e.target.dataset.step)},
【5】将store中的成员绑定到组件中
app.json:"usingComponents": {"vant_button": "@vant/weapp/button/index","test_component": "components/test_component"},
-------------------------------------------------------------------------------------
// components/test_component.js
import {storeBindingsBehavior
} from 'mobx-miniprogram-bindings'
import {store
} from '../store/store'
// 使用
Component({behaviors: [storeBindingsBehavior],storeBindings: {store,fields: {storeName: () => store.storeName, // 第一种storeAge: (store) => store.storeAge, // 第二种add: 'add' // 绑定字段的第三种方式},actions: {updateStoreAge: 'updateStoreAge'}},properties: {},data: {},methods: {saveAgeAdd() {// console.log("saveAgeAdd")this.updateStoreAge(1)},saveAgeReduce(e) {// console.log(e)this.updateStoreAge(e.target.dataset.step)},}
})
-------------------------------------------------------------------------------------
<!--components/test_component.wxml-->
<text>components/test_component.wxml</text>
<view>~~~~~~~~~~~~~~~~~~~~~分割</view>
<view>{{storeName}} {{storeAge}}
</view>
<vant_button type="primary" bindtap="saveAgeAdd">storeAge+1</vant_button>
<vant_button type="danger" bindtap="saveAgeReduce" data-step="{{-2}}">storeAge-2</vant_button>

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

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

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

22、分包
【1】概念
分包是把一个完整的小程序,划分为不同的子包,在构建时打包成不同的分包,让用户在使用的时候
可以按需加载。
***********************************************************************************************
优点:优化小程序首次启动的下载时间,在多人共同开发的时候更高效、解耦写作
【2】分包前项目的构成
分包前项目过大:所有页面+公共资源
***********************************************************************************************
分包后:
主包:项目启动页面或TabBar页面,以及分包都需要的一些公共资源
分包:只包含当前分包有关的页面和私有资源 N个分包
【3】分包的加载规则
tabBar肯定放在主包...
-----------------------------------------------------------------------------------------------
非tabBar页面可以按照功能的不同,划分为不同的包,进行按需下载
【4】分包的体积限制
整个小程序主包+分包不能超过16M
-----------------------------------------------------------------------------------------------
单个分包/主包不能超过2M
【5】配置使用分包
在app.json里的subpackage节点中声明分包的结构
***********************************************************************************************
"subpackages": [{"root": "pkgA","pages": ["pages/cat/cat","pages/dog/dog"]}, {"root": "pkgB","pages": ["pages/apple/apple","pages/orange/orange"]}],
***********************************************************************************************
起别名:!!!!!!!!!!!!!!!!!!!"subpackages": [{"root": "pkgA","name": "p1","pages": ["pages/cat/cat","pages/dog/dog"]}, {"root": "pkgB","name": "p2","pages": ["pages/apple/apple","pages/orange/orange"]}],
***********************************************************************************************
在详情-基本信息-本地代码-可以看到每个包的大小
***********************************************************************************************
分包的打包原则:
@ subpackages分包之外的,都会被打包的主包里面!!!!!!!!!!!!!!
@ 主包也有自己的pages
@ tabBar页面必须在主包内
@ 分包之间不能互相嵌套
***********************************************************************************************
分包的引用原则:
@ 主包无法引用分包内的私有资源
@ 分包之间不能相互引用私有资源
@ 分包可以引用主包内的公共资源!!!!!!!!!!!!!!!!!!!!!!!!!!!
【6】独立分包
可以独立于主包和分包独立运行!!!!
感觉像是另一个入口,emmmm
@ 特点就是是否需要依赖主包才能运行
***********************************************************************************************
独立分包的应用场景:
@ 独立分包不依赖主包即可运行,提升分包页面的启动速度。
注意: 一个小程序可以有多个独立分包
***********************************************************************************************
独立分包的配置方法:
, {"root": "pkgC","name": "p3","pages": ["pages/beauty/beauty","pages/girl/girl"],"independent": true // !!!!!!!!!!!!!!!!主要是这里}
***********************************************************************************************
独立分包的引用原则:
@ 主包无法引用独立分包资源
@ 独立分包之间无法相互引用资源
@ 独立分包和普通分包也无法引用资源
@ 独立分包也不能应用主包的公共资源!!!!!!!!!!!!
【7】分包预下载
在进入小程序某个页面时,框架自动预下载可能需要的分包,从而提升用户对页面的访问速度。
***********************************************************************************************
配置分包的预下载
"preloadRule": { // !!!!!!!!!!!!这里这里这里"pages/contact/contact": {"packages": ["p1"],"network": "all" // 所有网络都会下载}},"subpackages": [{"root": "pkgA","name": "p1",
-----------------------------------------------------------------------------------------------
点击联系的时候,控制台会自动打印:
preloadSubpackages: p1
preloadSubpackages: success
***********************************************************************************************
分包预下载的限制:
同一个主包页面,享有的所有的预下载大小限额2M(总体预下载分包不能超过2M)

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

23、自定义tabBar  89集
【1】自定义tabBar的实现步骤
@ 配置信息
@ 添加tabBar代码文件
@ 编写tabBar代码"tabBar": {"custom": true,  // !!!!!!!!!!!!!!!!!!!"list": [{"pagePath": "pages/home/home","text": "首页","iconPath": "/common/主页2.png","selectedIconPath": "/common/主页1.png"},{"pagePath": "pages/message/message","text": "消息","iconPath": "/common/消息2.png","selectedIconPath": "/common/消息1.png"},{"pagePath": "pages/contact/contact","text": "联系","iconPath": "/common/联系2.png","selectedIconPath": "/common/联系1.png"}]}
【2】初步实现自定义tabBar效果
custom-tab-bar在pages同级,然后新建index组件Component,记录哦 这个很重要!!!!!!!
******************************************************************************************
紧接着底部就出现了custom-tab-bar/index.wxml
******************************************************************************************"usingComponents": {"vant_button": "@vant/weapp/button/index","test_component": "components/test_component","van-tabbar": "@vant/weapp/tabbar/index","van-tabbar-item": "@vant/weapp/tabbar-item/index"},
---------------------------------------------------------------------------------------------
<!--custom-tab-bar/index.wxml-->
<!-- <text>这是自定义tabBar</text> -->
<van-tabbar active="{{ active }}" bind:change="onChange"><van-tabbar-item icon="home-o">标签</van-tabbar-item><van-tabbar-item icon="search">标签</van-tabbar-item><van-tabbar-item icon="friends-o">标签</van-tabbar-item><van-tabbar-item icon="setting-o">标签</van-tabbar-item>
</van-tabbar>
---------------------------------------------------------------------------------------------
// custom-tab-bar/index.js
// 使用
Component({properties: {},data: {active: 0},methods: {onChange(event) { // event.detail 的值为当前选中项的索引this.setData({active: event.detail});},}
})
******************************************************************************************
自定义徽标:感觉没有组件给的好看,哈哈哈哈
<!--custom-tab-bar/index.wxml-->
<!-- <text>这是自定义tabBar</text> -->
<van-tabbar active="{{ active }}" bind:change="onChange"><van-tabbar-item info="3"><image slot="icon" src="/common/主页2.png" mode="aspectFit" style="width: 30px; height: 18px;" /><image slot="icon-active" src="/common/主页1.png" mode="aspectFit" style="width: 30px; height: 18px;" />首页</van-tabbar-item><van-tabbar-item icon="home-o">标签</van-tabbar-item><van-tabbar-item icon="search">标签</van-tabbar-item><van-tabbar-item icon="friends-o">标签</van-tabbar-item><van-tabbar-item icon="setting-o">标签</van-tabbar-item>
</van-tabbar>
---------------------------------------------------------------------------------------------
data: {active: 0,"list": [{"pagePath": "pages/home/home","text": "首页","iconPath": "/common/主页2.png","selectedIconPath": "/common/主页1.png"},{"pagePath": "pages/message/message","text": "消息","iconPath": "/common/消息2.png","selectedIconPath": "/common/消息1.png"},{"pagePath": "pages/contact/contact","text": "联系","iconPath": "/common/联系2.png","selectedIconPath": "/common/联系1.png"}]},
---------------------------------------------------------------------------------------------
<!--custom-tab-bar/index.wxml-->
<!-- <text>这是自定义tabBar</text> -->
<van-tabbar active="{{ active }}" bind:change="onChange"><van-tabbar-item wx:for="{{list}}" wx:key="index"><image slot="icon" src="{{item.iconPath}}" mode="aspectFit" style="width: 25px; height: 25px;" /><image slot="icon-active" src="{{item.selectedIconPath}}" mode="aspectFit" style="width: 25px; height: 25px;" />{{item.text}}</van-tabbar-item>
</van-tabbar>
【3】如何渲染出徽标info="2"
******************************************************************************************
处理徽标超出tabBar边界的问题:
// custom-tab-bar/index.js
// 使用
Component({options: {styleIsolation: "shared"  // 不开启不会生效的哈},
---------------------------------------------------------------------------------------------
/* custom-tab-bar/index.wxss */
.van-tabbar-item {--tabbar-item-margin-bottom: 0
}
---------------------------------------------------------------------------------------------
按需渲染徽标{"pagePath": "pages/message/message","text": "消息","iconPath": "/common/消息2.png","selectedIconPath": "/common/消息1.png",info: 2},
---------------------------------------------------------------------------------------------
<!--custom-tab-bar/index.wxml-->
<!-- <text>这是自定义tabBar</text> -->
<van-tabbar active="{{ active }}" bind:change="onChange"><van-tabbar-item wx:for="{{list}}" wx:key="index" info="{{item.info?item.info:''}}"><image slot="icon" src="{{item.iconPath}}" mode="aspectFit" style="width: 25px; height: 25px;" /><image slot="icon-active" src="{{item.selectedIconPath}}" mode="aspectFit" style="width: 25px; height: 25px;" />{{item.text}}</van-tabbar-item>
</van-tabbar>
******************************************************************************************
如何把徽标动态化?  // 用store.js全局引用和修改,牛批!!!!!!!!!!!
// custom-tab-bar/index.js
// 使用
import {storeBindingsBehavior
} from 'mobx-miniprogram-bindings'
import {store
} from '../store/store'
Component({behaviors: [storeBindingsBehavior],options: {styleIsolation: "shared"},properties: {},storeBindings: {store,fields: {changeInfo: 'changeInfo' // 全局存储的字段}},observers: {'changeInfo': function (newVal) {// console.log(newVal)this.setData({'list[1].info': newVal // 把changeInfo的最新值给到list.info})}},data: {active: 0,"list": [{"pagePath": "pages/home/home","text": "首页","iconPath": "/common/主页2.png","selectedIconPath": "/common/主页1.png"},{"pagePath": "pages/message/message","text": "消息","iconPath": "/common/消息2.png","selectedIconPath": "/common/消息1.png",info: 2},{"pagePath": "pages/contact/contact","text": "联系","iconPath": "/common/联系2.png","selectedIconPath": "/common/联系1.png"}]},methods: {onChange(event) { // event.detail 的值为当前选中项的索引this.setData({active: event.detail});},}
})
【4】如何实现tabBar页面的切换onChange(event) { // event.detail 的值为当前选中项的索引this.setData({active: event.detail});wx.switchTab({url: '/' + this.data.list[event.detail].pagePath,  // 调用切换!!!!!!!!!!!!!})},
******************************************************************************************
// 在这里js中专门创建save实例对象
import {action,observable
} from 'mobx-miniprogram'export const store = observable({storeName: '陈翔',storeAge: 26,changeInfo: 2,active: 0,// 修改active下标的函数updateActive: action(function (index) {this.active = index}),// 定义计算属性get add() { // add就是计算属性的名字return this.storeAge + 1},// 定义全局方法修改save里的数据updateStoreAge: action(function (step) {this.storeAge = this.storeAge + stepthis.changeInfo = this.changeInfo + step})
})
---------------------------------------------------------------------------------------------
处理索引标记的问题
// custom-tab-bar/index.js
// 使用
import {storeBindingsBehavior
} from 'mobx-miniprogram-bindings'
import {store
} from '../store/store'
Component({behaviors: [storeBindingsBehavior],options: {styleIsolation: "shared"},properties: {},storeBindings: {store,fields: {changeInfo: 'changeInfo', // 全局存储的字段active: 'active'},actions: {updateActive: 'updateActive'}},observers: {'changeInfo': function (newVal) {// console.log(newVal)this.setData({'list[1].info': newVal // 把changeInfo的最新值给到list.info})}},data: {"list": [{"pagePath": "pages/home/home","text": "首页","iconPath": "/common/主页2.png","selectedIconPath": "/common/主页1.png"},{"pagePath": "pages/message/message","text": "消息","iconPath": "/common/消息2.png","selectedIconPath": "/common/消息1.png",info: 2},{"pagePath": "pages/contact/contact","text": "联系","iconPath": "/common/联系2.png","selectedIconPath": "/common/联系1.png"}]},methods: {onChange(event) { // event.detail 的值为当前选中项的索引/*  this.setData({active: event.detail}); */this.updateActive(event.detail)wx.switchTab({url: '/' + this.data.list[event.detail].pagePath,})},}
})
【5】修改选中项文本的颜色
<van-tabbar active="{{ active }}" bind:change="onChange" active-color="red">
active-color="red"!!!!!!!!!!!!默认的也挺好的,噗嗤
【6】总结:
@ vant-weapp组件库配置使用
@ Mbox 就是store.js的使用
@ 小程序的API promise化
@ 实现自定义tabBar效果!!!!!!!!!!!!!!!!!!

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

24、小程序大项目(uni-app)
【1】项目概述:
4个tabBar
***********************************************************************************
@ 商品分类
@ 分类的布局,商品列表页面
@ 加入购物车
@ 收货地址
@ 一键登录
@ 我的页面  收货客服
@ 支付
【2】uni-app概述与开放环境
uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到
iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ
/快手/钉钉/淘宝)、快应用等多个平台。卧槽 这么屌吗!!!!!!!!!!!!!!!
---------------------------------------------------------------------------------------------
基于vue.js语法的uni-app模板项目,好牛皮,可以发布小程序项目、H5、Android、iOS、etc等等....
***********************************************************************************
下载和配置uniapp开发工具:HBuilderX
https://www.dcloud.io/hbuilderx.html
---------------------------------------------------------------------------------------------
下载后解压即可
---------------------------------------------------------------------------------------------
安装scss/sass编译插件
https://ext.dcloud.net.cn/plugin?id=2046
---------------------------------------------------------------------------------------------
个性化配置:工具-自定义快捷键
【2】新建uniapp项目
文件---新建项目---所在位置+文件名---选择uni-ui项目
***********************************************************************************
组成结构:
pages:所有小程序页面
---------------------------------------------------------------------------------------------
static:静态资源
---------------------------------------------------------------------------------------------
main.js vue的初始化入口
---------------------------------------------------------------------------------------------
App.vue 配置小程序的全局样式
---------------------------------------------------------------------------------------------
manifest.json
---------------------------------------------------------------------------------------------
pages.json
---------------------------------------------------------------------------------------------
uni.scss
***********************************************************************************
如何把uniapp项目运行到微信小程序里
填写微信小程序APPID---manifest.json---微信小程序配置---粘贴小程序appid
---------------------------------------------------------------------------------------------
工具-设置-运行配置---小程序运行配置---微信开发者工具路径:C:\Program Files (x86)\Tencent\微信web开发者工具
---------------------------------------------------------------------------------------------
微信-开发者工具-设置-安全-服务端口打开
---------------------------------------------------------------------------------------------
通过Hbuilder运行-运行到小程序模拟器---即可打开微信小程序开效果,我日尼玛!!!
***********************************************************************************
使用Git管理项目
根节点新建:.gitignore文件
/node_modules
/uppackage/dist
.gitkeep
***********************************************************************************
把本地项目托管到码云
F:\A计算机\IT01项目\4.UNIAPP\uni-shop-2\static
cmd
然后执行如下命令:
git init 
git status
git add .
git commit -m "init project"
git config --global user.email "wdfgdzx@163.com"
git config --global user.name "wdfgdzx"
git config --global user.password "s19911009!" 
再执行git commit -m "init project"即可!
---------------------------------------------------------------------------------------------
git remote add origin https://gitee.com/wdfgdzx/uniapp.git
git push -u origin "master"
推到码云:::::!!!!!!!!!!毕老师讲的简单过了  我日尼玛!!!
***********************************************************************************
配置tabBar效果
git checkout -b tabbar  创建分支
git branch 查看分支
在pages下面右击新建页面
***********************************************************************************
{"tabBar": {"list": [{"pagePath": "pages/home/home","text": "首页","iconPath": "static/tab_icons/home.png","selectedIconPath": "static/tab_icons/home-active.png"}, {"pagePath": "pages/cate/cate","text": "分类","iconPath": "static/tab_icons/cate.png","selectedIconPath": "static/tab_icons/cate-active.png"}, {"pagePath": "pages/cart/cart","text": "购物车","iconPath": "static/tab_icons/cart.png","selectedIconPath": "static/tab_icons/cart-active.png"}, {"pagePath": "pages/my/my","text": "我的","iconPath": "static/tab_icons/my.png","selectedIconPath": "static/tab_icons/my-active.png"}]},"pages": [{"path": "pages/home/home","style": {"navigationBarTitleText": "","enablePullDownRefresh": false}}, {"path": "pages/cate/cate","style": {"navigationBarTitleText": "","enablePullDownRefresh": false}}, {"path": "pages/cart/cart","style": {"navigationBarTitleText": "","enablePullDownRefresh": false}}, {"path": "pages/my/my","style": {"navigationBarTitleText": "","enablePullDownRefresh": false}}],"globalStyle": {"navigationBarTextStyle": "black","navigationBarTitleText": "uni-app","navigationBarBackgroundColor": "#F8F8F8","backgroundColor": "#F8F8F8","app-plus": {"background": "#efeff4"}}
}
***********************************************************************************
"selectedColor": "#C00000",
***********************************************************************************
pages下面是重点,如果看不到记得删除index也就是首页,牛批呀 我的哥哥
***********************************************************************************
提交与合并
git add .
git status
git commit -m "完成tabBar"
git push -u origin "tabbar"
git checkout master
git merge tabbar
git push
git branch
git branch -d tabbar  删除本地分支
【3】实现首页相关的功能!!!!!!!!!!!!!!轮播图
不搞分支了,真JB麻烦
***********************************************************************************
npm init -y
npm i @escook/request-miniprogram
---------------------------------------------------------------------------------------------
// 导入网络请求包
import {$http
} from '@escook/request-miniprogram'uni.$http = $http// 请求拦截器
$http.beforeRequest = function(options) {uni.showLoading({title: '数据加载中...'})
}// 响应拦截器
$http.afterRequest=function(){uni.hideLoading()
}
***********************************************************************************
请求轮播图数据
原来是我的服务没有设置跨域导致的,我天 卧槽 沃日!!!!!!!!!!!
***********************************************************************************
我也不知道怎么折腾的,反正更新跨域后就解决了,哈哈哈哈!!!!
onLoad() {// 加载的时候就调用方法this.selectList()
},
methods: {selectList() {uni.$http.post("/document/list_page", this.sendData).then(res => {console.log(res)})}
}
至此,就实现了VUE类似的开发,但是可以运行N+个平台,卧槽 牛批!!!!!!!!!!!!!
***********************************************************************************
selectList() {uni.$http.post("/document/list_page", this.sendData).then(res => {// console.log(res)if (res.data.code === "200") {this.list = res.data.object.data} else {return uni.showToast({title: '数据请求失败',duration: 1500,icon: 'none'})}})}
h5 app 小程序 浏览器 皆可以
***********************************************************************************
usw可以快速生成轮播图:
<template><view><swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true"style="height: 330rpx;"><!-- 循环渲染item项目 --><swiper-item v-for="item in list" :key="item.id"><view style="width: 100%;height: 100%;"><image :src="item.url" style="width: 100%;height: 100%;"></image></view></swiper-item></swiper></view>
</template><script>export default {data() {return {// list集合list: [],sendData: {currentPage: 1,pageSize: 10,total: 10}};},onLoad() {// 加载的时候就调用方法this.selectList()},methods: {selectList() {uni.$http.post("/document/list_page", this.sendData).then(res => {// console.log(res)if (res.data.code === "200") {this.list = res.data.object.data} else {return uni.showToast({title: '数据请求失败',duration: 1500,icon: 'none'})}})}}}
</script><style lang="scss"></style>
【4】配置小程序分包,万众则归一!!!!!!!!!!!!!!!!!!
先建立subpkg目录
然后再pages.json里配置下
"subPackages": [{"root": "subpkg","pages": [{"path": "goods_detail/goods_detail","style": {}}]}],
---------------------------------------------------------------------------------------------
然后手动到subpkg下新建页面就行了,弹出的页面中注意选择分包名称,完成OVER
【5】点击轮播图,跳转商品详情页的功能
<template><view><swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true"style="height: 330rpx;"><!-- 循环渲染item项目 --><swiper-item v-for="item in list" :key="item.id"><navigator style="width: 100%;height: 100%;" :url="'/subpkg/goods_detail/goods_detail?id='+item.id"><image :src="item.url" style="width: 100%;height: 100%;"></image></navigator></swiper-item></swiper></view>
</template>
---------------------------------------------------------------------------------------------
这就完事了,到详情页,有id参数值
【6】封装uni.$showMsg(0方法
因为当调用失败的时候,每次都要写uni.showToast方法,非常麻烦,所以要封装!!!!
---------------------------------------------------------------------------------------------
// 封装一个报错的方法
uni.$message = function(title = "数据请求失败!", duration = 1500) {uni.showToast({title,duration,icon: 'none'})
}
---------------------------------------------------------------------------------------------
selectList() {uni.$http.post("/document/list_page", this.sendData).then(res => {// console.log(res)if (res.data.code === "200") {this.list = res.data.object.datareturn uni.$message("数据请求成功")} else {return uni.$message()}})}
【7】实现分类导航区域
selectNavList() { // 请求分类图uni.$http.post("/kind/list_page", this.sendData).then(res => {console.log(res)if (res.data.code === "200") {this.navList = res.data.object.data // 注意是navList的赋值了return uni.$message("数据请求成功!")} else {return uni.$message()}})
}
---------------------------------------------------------------------------------------------
<!-- 分类导航区域 --><view style="display: flex;justify-content: space-around;margin: 15px 0;"><view v-for="item in navList" :key="item.id" @click="navClick(item)"><image :src="item.urlIcon" style="width: 128rpx;height: 140rpx;"></image><view style="font-size: 24rpx;margin-left: 24rpx;">{{item.type}}</view></view></view>
---------------------------------------------------------------------------------------------
点击第一项,实现分类页面:
navClick(item) {// console.log(item)if (item.type === "点分类") {uni.switchTab({   // !!!!!!!!!!!!!这是重点url: '/pages/cate/cate'})}},
【8】获取楼层数据并渲染楼层的标题
<view style=""><view v-for="(item,index) in floorList" :key="index"><!-- 楼层标题 --><view style="height: 60rpx;width: 100%;display: flex;color: crimson;font-size: 36rpx;">{{item.floor_title}}</view></view></view>
【9】渲染楼层里面的图片
<!-- 左侧大图 mode="widthFix" 如果图片本身合规的话-->
<view><image :src="item.product_list[0].url" style="width: 232rpx;"></image>
</view>
---------------------------------------------------------------------------------------------
<!-- 楼层数据 -->
<view style=""><view v-for="(item,index) in floorList" :key="index"><!-- 楼层标题 --><viewstyle="height: 60rpx;width: 100%;display: flex;color: crimson;font-size: 36rpx;padding-left: 10rpx;">{{item.floor_title}}</view><!-- 楼层的图片区域 --><view style="display: flex;padding-left: 10rpx;"><!-- 左侧大图 mode="widthFix" 如果图片本身合规的话--><view><image :src="item.product_list[0].url" style="width: 232rpx;"></image></view><!-- 右侧4小图 --><view style="display: flex;flex-wrap: wrap;justify-content: space-around;"><view v-for="(subItem,subIndex) in item.product_list" :key="subIndex" v-if="subIndex!==0"><image :src="subItem.url" style="width: 232rpx;height: 236rpx;"></image></view></view></view></view>
</view>
【10】点击楼层图片跳转到商品列表页
在分包里新建goods_list页面,感觉用了uniapp好清晰呀,就一个vue文件,哈哈哈哈!!!!!!
res.data.object.data.forEach(item => { // 挂载上页面属性item.navUrl = "/subpkg/goods_list/goods_list?query=" + item.kind
})
---------------------------------------------------------------------------------------------
<navigator :url="item.product_list[0].navUrl"><image :src="item.product_list[0].url" style="width: 232rpx;"></image></navigator>
---------------------------------------------------------------------------------------------
<view style="display: flex;flex-wrap: wrap;justify-content: space-around;"><navigator v-for="(subItem,subIndex) in item.product_list" :key="subIndex" v-if="subIndex!==0":url="subItem.navUrl"><image :src="subItem.url" style="width: 232rpx;height: 236rpx;"></image></navigator>
</view>
【11】分支的合并与提交
对于我来说就是规整下项目,存下百度网盘!!!!!!!!!!!!!!【12】108集 创建cate分支以及分类页面的编译模式
微信小程序里点击小程序模式,新建模式,选择cate页面,这样方便开发!!!!
【13】109集初始化分类区域的页面布局
滑动区域
***************************************************************************************
主要是通过scroll-view scroll-y="true" style="height: 300px;width: 120px;"
加样式实现:
***************************************************************************************
占满整个屏幕的高度:
自带的方法拿到屏幕高度...
---------------------------------------------------------------------------------------
windowHeight
---------------------------------------------------------------------------------------
onLoad() {const sysInfo = uni.getSystemInfoSync();// console.log(sysInfo)this.windowsHeight = sysInfo.windowHeight}
---------------------------------------------------------------------------------------
:style="{height:windowsHeight+'px',width:'120px'}" // 动态属性绑定
---------------------------------------------------------------------------------------
.leftView {background-color: #F7F7F7;line-height: 60px;text-align: center;font-size: 12px;&.active {background-color: #FFFFFF;position: relative;&::before {content: ' ';display: block;width: 3px;height: 30px;background-color: #C00000;position: absolute;top: 50%;left: 0%;transform: translateY(-50%)}}}
---------------------------------------------------------------------------------------
有时候不得不用css,哎
【14】获取并渲染一级分类列表数据
实操的时候,一级分类需要从mysql group by 下。然后分类肯定有很多吗....
【15】渲染二级和三级分类类表:
<!-- 右侧滑动区域 --><scroll-view scroll-y="true" :style="{height:windowsHeight+'px'}"><view style="font-size: 12px;font-weight: bold;text-align: center;padding: 15px 0;"><!-- 按道理二级分类应该是动态的 -->/ 爆款服装-2级 /</view><view style="display: flex;flex-wrap: wrap;"><view v-for="item in cateListLevel2" :key="item.id"style="width: 33.33%;display: flex;flex-direction: column;justify-content: center;align-items: center;margin-bottom: 10px;"><!-- 图片 --><image :src="item.url" style="width: 60px;height: 60px;"></image><!-- 文本 --><text style="font-size: 12px;">{{item.name}}</text></view></view></scroll-view>
【16】切换的时候滚动条的位置没有从顶部开始
解决bug:
:scroll-top="scrollTop"
this.scrollTop = this.scrollTop === 0 ? 0.01 : 0 // 因为不能赋值一样的
***************************************************************************************
点击图片跳转到商品类表页面:
<view v-for="item in cateListLevel2" :key="item.id"
style="width: 33.33%;display: flex;flex-direction: column;justify-content: center;align-items: center;margin-bottom: 10px;"
@click="goGoodsList(item)">
---------------------------------------------------------------------------------------
goGoodsList(item) { // 跳转到商品列表页面uni.navigateTo({url: '/subpkg/goods_list/goods_list?kind=' + item.kind // 传递分类})
},
【17】搜索相关的功能:自定义搜索组件、搜索建议、搜索历史
创建自定义搜索组件:
***************************************************************************************
新建components目录,新建my-search组件
---------------------------------------------------------------------------------------
<template><view>这是自定义搜索组件</view>
</template><script>export default {name: "my-search",data() {return {};}}
</script><style lang="scss"></style>
---------------------------------------------------------------------------------------
<!-- 使用自定义组件 -->
<my-search></my-search>
---------------------------------------------------------------------------------------
优化组件布局
<template><view style="height: 50px;background-color: #C00000;display: flex;align-items: center;padding: 0 10px;"><viewstyle="height: 36px;background-color: #FFFFFF;border-radius: 18px;width: 100%;display: flex;justify-content: center;align-items: center;"><!-- icon组件 --><uni-icons type="search" size="17"></uni-icons><text style="font-size: 15px;margin-left: 5px;">搜索</text></view></view>
</template><script>export default {name: "my-search",data() {return {};}}
</script><style lang="scss"></style>
---------------------------------------------------------------------------------------
解决添加搜索区域后滚动显示不全的问题:
this.windowsHeight = sysInfo.windowHeight - 50
***************************************************************************************
自定义组件的形式,增加通用性:
没必要这么人性化,都能自定义,你要知道你的代码谁去用...!!!!!!!!!!!!!
用props绑定属性
动态绑定style  :style="{a:'1',b:'2'}"
***************************************************************************************
为自定义组件封装click事件:
<view style="height: 50px;background-color: #C00000;display: flex;align-items: center;padding: 0 10px;"@click="searchHandler">
---------------------------------------------------------------------------------------
searchHandler() {console.log("-----!!!!!")this.$emit('click')  // 注意这个名字和引用组件页面的@ click是一样的}
---------------------------------------------------------------------------------------
<my-search @click="goSearch"></my-search>
---------------------------------------------------------------------------------------
goSearch() { // 跳转搜索页console.log("外界调用")
},			
【18】导航跳转与吸顶效果
goSearch() { // 跳转搜索页   // 这才是真正有用的!!!!!!!!!!!!!!!// console.log("外界调用")uni.navigateTo({url: '/subpkg/search/search'})
},
***************************************************************************************
<!-- 搜索组件 --><view style="position:sticky;top:0;z-index:999"><my-search @click="goSearch"></my-search></view>
【19】搜索建议
<template><view><view style="background-color: #C00000;position:sticky;top:0;z-index:999"><uni-search-bar @input="input" :radius="100" cancelButton="none" placeholder="请输入搜索内容"></uni-search-bar></view></view>
</template><script>export default {data() {return {};},methods: {input(e) {console.log(e)}}}
</script><style lang="scss"></style>
***************************************************************************************
搜索框自动获取焦点:
uni_modules----uni-search-bar---componets---uni-search-bar.vue
修改里面的data
data() {return {show: true,showSync: true, // !!!!!!!!!!!!!!这里searchVal: ''}},
***************************************************************************************
处理下搜索框的防抖,防止无效的请求
<script>export default {data() {return {timer: null, //延时器keyWord: ''};},methods: {input(e) {// console.log(e)clearTimeout(this.timer)this.timer = setTimeout(() => {// console.log(e)this.keyWord = e // 赋值关键词}, 500)}}}
</script>
【20】关键词查询建议列表118集合
selectSearchList() {// 搜索关键词是否为空if (this.keyWord.length === 0) {this.searchResultList = []return false}this.sendData.kind = this.keyWorduni.$http.post("/document/list_page", this.sendData).then(res => {console.log(res)if (res.data.code === "200") {this.searchResultList = res.data.object.data} else {return uni.$message()}})}
*******************************************************************************************
【21】点击跳转详情页
goDetail(item) { // 跳转详情uni.navigateTo({url: "/subpkg/goods_detail/goods_detail?id=" + item.id})},
*******************************************************************************************
【22】渲染搜索历史
<view style="padding: 0 5px;"><!-- 标题区域 --><viewstyle="display: flex;justify-content: space-between;height: 40px;align-items: center;font-size: 13px;border-bottom: 1px solid lightgray;"><text>搜索历史</text><uni-icons type="trash" size="17"></uni-icons></view><!-- 列表区域 --><view style="display: flex;flex-wrap: wrap;"><uni-tag v-for="(item,index) in historyList" :key="index" :text="item"style="margin-top: 5px;margin-right: 5px;"></uni-tag></view>
</view>
*******************************************************************************************
按需展示!!!!!!!!!!!!!!!!!
<!-- 搜索建议列表 --><view style="padding: 0 5px;" v-if="searchResultList.length!==0"><view v-for="item in searchResultList" :key="item.id" @click="goDetail(item)"style="display: flex;align-items: center;justify-content: space-between;font-size: 12px;padding: 13px 0;border-bottom: 1px solid lightgray;"><view style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;margin-right: 3px;">{{item.kind}}+{{item.name}}</view><uni-icons type="arrowright" size="16"></uni-icons></view></view><!-- 搜索历史 --><view style="padding: 0 5px;" v-else><!-- 标题区域 --><viewstyle="display: flex;justify-content: space-between;height: 40px;align-items: center;font-size: 13px;border-bottom: 1px solid lightgray;"><text>搜索历史</text><uni-icons type="trash" size="17"></uni-icons></view><!-- 列表区域 --><view style="display: flex;flex-wrap: wrap;"><uni-tag v-for="(item,index) in historyList" :key="index" :text="item"style="margin-top: 5px;margin-right: 5px;"></uni-tag></view></view>
【23】处理搜索关键词
saveHistory() { // 保存搜索历史记录this.historyList.push(this.keyWord)},
*******************************************************************************************
但是存在排序与重复的问题:解决bug
computed: {betterHistoryList() {return [...this.historyList].reverse()}},
*******************************************************************************************
<view style="display: flex;flex-wrap: wrap;"><uni-tag v-for="(item,index) in betterHistoryList" :key="index" :text="item"style="margin-top: 5px;margin-right: 5px;"></uni-tag></view>
*******************************************************************************************
解决搜索关键词重复问题
saveHistory() { // 保存搜索历史记录const set = new Set(this.historyList)set.delete(this.keyWord) // 先移出历史set.add(this.keyWord) // 再追加新的this.historyList = Array.from(set)
},
*******************************************************************************************
搜索历史记录持久存储到本地
onLoad() {
this.historyList = JSON.parse(uni.getStorageSync('keyWord') || '[]')
},
methods: {
saveHistory() { // 保存搜索历史记录const set = new Set(this.historyList)set.delete(this.keyWord) // 先移出历史set.add(this.keyWord) // 再追加新的this.historyList = Array.from(set)uni.setStorageSync("keyWord", JSON.stringify(this.historyList))
},
【24】清空历史搜索记录
cleanHistory() { // 清空历史记录this.historyList = []uni.setStorageSync("keyWord", '[]')},
【25】点击搜索历史,跳转商品列表页面
<!-- 列表区域 -->
<view style="display: flex;flex-wrap: wrap;"><uni-tag v-for="(item,index) in betterHistoryList" :key="index" :text="item" @click="goGoodsList(item)"style="margin-top: 5px;margin-right: 5px;"></uni-tag>
</view>
*******************************************************************************************			
goGoodsList(keyWord) {uni.navigateTo({url: "/subpkg/goods_list/goods_list?kind=" + keyWord})
},
【25】125集商品列表页面的开发
<template><view><!-- 外层容器 --><view><!-- item项 --><block v-for="item in list" :key="item.id"><view style="display: flex;padding: 10px 5px;border-bottom: 1px solid lightgray;"><!-- 左侧盒子 --><view style="margin-right: 5px;"><image :src="item.url || defaultImage" style="width: 100px;height: 100px;display: block;"></image></view><!-- 右侧盒子 --><view style="display: flex;flex-direction: column;justify-content: space-between;"><!-- 商品名称 --><view style="font-size: 13px;">{{item.name}}</view><!-- 商品价格 --><view style="color: #C00000;font-size: 16px;">¥ {{item.price}}</view></view></view></block></view></view>
</template><script>export default {data() {return {list: [],defaultImage: 'http://wdfgdzx.top:8000/document/a5dd6d1d1c5c45dd98c6017b1821acb8.jpg', // 默认图片地址sendData: {currentPage: 1,pageSize: 10,total: 10}};}, // 从上个页面获取参数,获取不到默认是空onLoad(options) {// console.log(options)this.sendData.kind = options.kind || '' // 从上个页面获取参数,获取不到默认是空this.selectList()},methods: {selectList() {uni.$http.post("/document/list_page", this.sendData).then(res => {// console.log(res)if (res.data.code = "200") {this.list = res.data.object.datathis.sendData.total = res.data.object.total} else {return uni.$message()}})}}}
</script><style lang="scss"></style>
【26】把商品item项分装成自定义组件
在components中创建my-goods组件:
<view><!-- item项 --><block v-for="item in list" :key="item.id"><my-goods :item="item"></my-goods> <!-- 注意:item和接受页面名字是一样的 --></block>
</view>
*******************************************************************************************
<template><!-- 外层容器 --><view><view style="display: flex;padding: 10px 5px;border-bottom: 1px solid lightgray;"><!-- 左侧盒子 --><view style="margin-right: 5px;"><image :src="item.url || defaultImage" style="width: 100px;height: 100px;display: block;"></image></view><!-- 右侧盒子 --><view style="display: flex;flex-direction: column;justify-content: space-between;"><!-- 商品名称 --><view style="font-size: 13px;">{{item.name}}</view><!-- 商品价格 --><view style="color: #C00000;font-size: 16px;">¥ {{item.price}}</view></view></view></view>
</template><script>export default {name: "my-goods",props: {item: { // 这个名字和页面里使用的名字是一致的,注意!!!!!!!!!!!!type: Object,default: {}}},data() {return {defaultImage: 'http://wdfgdzx.top:8000/document/a5dd6d1d1c5c45dd98c6017b1821acb8.jpg', // 默认图片地址};}}
</script><style lang="scss"></style>
【27】使用过滤器处理商品价格
<template><!-- 外层容器 --><view><view style="display: flex;padding: 10px 5px;border-bottom: 1px solid lightgray;"><!-- 左侧盒子 --><view style="margin-right: 5px;"><image :src="item.url || defaultImage" style="width: 100px;height: 100px;display: block;"></image></view><!-- 右侧盒子 --><view style="display: flex;flex-direction: column;justify-content: space-between;"><!-- 商品名称 --><view style="font-size: 13px;">{{item.name}}</view><!-- 商品价格 --><view style="color: #C00000;font-size: 16px;">¥ {{item.price | toFixed}}</view></view></view></view>
</template><script>export default {name: "my-goods",props: {item: { // 这个名字和页面里使用的名字是一致的,注意!!!!!!!!!!!!type: Object,default: {}}},data() {return {defaultImage: 'http://wdfgdzx.top:8000/document/a5dd6d1d1c5c45dd98c6017b1821acb8.jpg', // 默认图片地址};},filters: {toFixed(num) {return Number(num).toFixed(2)}}}
</script><style lang="scss"></style>
【28】实现下拉加载更多
{"path": "goods_list/goods_list","style": {"onReachBottomDistance": 150}
},
*******************************************************************************************
onReachBottom() {this.sendData.currentPage = this.sendData.currentPage + 1 // 页面+1后 调用selectList方法this.selectList()},methods: {selectList() {uni.$http.post("/document/list_page", this.sendData).then(res => {// console.log(res)if (res.data.code = "200") {this.list = [...this.list, ...res.data.object.data] // 新旧数据拼接this.sendData.total = res.data.object.total} else {return uni.$message()}})}}
*******************************************************************************************
节流阀的实现
*******************************************************************************************
数据是否加载完毕实现
if (this.sendData.currentPage * this.sendData.pageSize >= this.sendData.total) {return uni.$message("数据加载完毕...")
}
【29】实现下拉刷新
{"path": "goods_list/goods_list","style": {"onReachBottomDistance": 150,"enablePullDownRefresh": true,"backgroundColor": "#f8f8f8"}},
*******************************************************************************************
onPullDownRefresh() {this.sendData.currentPage = 1this.sendData.total = 0this.loadingFlag = falsethis.list = []this.selectList(() => uni.stopPullDownRefresh())},
*******************************************************************************************
selectList(cb) {this.loadingFlag = true // 打开节流阀uni.$http.post("/document/list_page", this.sendData).then(res => {// console.log(res)this.loadingFlag = false // 关闭节流阀cb && cb()if (res.data.code = "200") {this.list = [...this.list, ...res.data.object.data] // 新旧数据拼接this.sendData.total = res.data.object.total} else {return uni.$message()}})}
*******************************************************************************************
UPDATE document SET preview=REPLACE(preview,'localhost','wdfgdzx.top');
UPDATE document SET url=REPLACE(url,'localhost','wdfgdzx.top');
*******************************************************************************************
【30】点击商品item跳转到商品详情页
<!-- item项 --><view v-for="item in list" :key="item.id" @click="goDetail(item)"><my-goods :item="item"></my-goods> <!-- 注意:item和接受页面名字是一样的 --></view>
*******************************************************************************************
goDetail(item) { // 去详情页面uni.navigateTo({url: "/subpkg/goods_detail/goods_detail?id=" + item.id})},
【31】商品详情页的开发
<script>export default {data() {return {goodsInfo: {}};},onLoad(options) {const id = options.idthis.selectGoods(id)},methods: {selectGoods(id) {uni.$http.post("/document/select_id/" + id).then(res => {// console.log(res)if (res.data.code = "200") {this.goodsInfo = res.data.object} else {return uni.$message()}})}}}
</script>
*******************************************************************************************
商品详情页的UI结构
<view><!-- 商品详情页 --><swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true"style="height: 750rpx;"><swiper-item v-for="(item,index) in goodsInfo.imageList" :key="index"><image :src="item" style="width: 100%;height: 100%;"></image></swiper-item></swiper></view>
*******************************************************************************************
轮播图预览效果!!!!!!!!!!!!!!!!!!!!!!!!
<template><view><!-- 商品详情页 --><swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true"style="height: 750rpx;"><swiper-item v-for="(item,index) in goodsInfo.imageList" :key="index"><image :src="item" style="width: 100%;height: 100%;" @click="preview(index)"></image></swiper-item></swiper></view>
</template><script>export default {data() {return {goodsInfo: {imageList: []}};},onLoad(options) {const id = options.idthis.selectGoods(id)},methods: {preview(index) { // 预览uni.previewImage({current: index,urls: this.goodsInfo.imageList.map(v => v)})},selectGoods(id) {uni.$http.post("/document/select_id/" + id).then(res => {// console.log(res)if (res.data.code = "200") {this.goodsInfo = res.data.objectthis.goodsInfo.imageList = res.data.object.imageList.split("&&&")// console.log(this.goodsInfo.imageList)} else {return uni.$message()}})}}}
</script><style lang="scss"></style>
【32】渲染美化商品信息区域  136集
<view><!-- 商品价格 --><view>{{goodsInfo.price}}</view><!-- 信息主题区域 --><view><!-- 商品名称 --><view>{{goodsInfo.name}}</view><!-- 收藏 --><view><uni-icons type="star" size="18" color="gray"></uni-icons><text>收藏</text></view></view><!-- 运费区域 --><view>快递:免运费</view></view>
*************************************************************************************************
美化:
<!-- 商品信息区域 --><view style="padding: 10px;padding-right: 0;"><!-- 商品价格 --><view style="color: #C00000;font-size: 18px;margin: 10px 0;">¥ {{goodsInfo.price}}</view><!-- 信息主题区域 --><view style="display: flex;justify-content: space-between;"><!-- 商品名称 --><view style="font-size: 13px;margin-right: 10px">{{goodsInfo.name}}</view><!-- 收藏 --><view style="width: 120px;font-size: 12px;display: flex;flex-direction: column;align-items: center;justify-content: center;border-left: 1px solid lightgray;color: gray;"><uni-icons type="star" size="18" color="gray"></uni-icons><text>收藏</text></view></view><!-- 运费区域 --><view style="font-size: 12px;color: gray;margin: 10px 0;">快递:免运费</view></view>
【33】渲染商品详情数据
<!-- 商品详情图片区域 --><view style="display: flex;justify-content: center;"><image src='https://wdfgdzx.top/document/pre_see/00f3be647229489887b4fa6a9f35459b.jpg' style="width: 100%;"></image></view>
*************************************************************************************************
.webp替换为jpg即可在iOS上显示
*************************************************************************************************
解决商品价格显示闪烁问题:
<view v-if="goodsInfo.name">
【34】渲染商品底部的导航区域
<!-- 底部导航区域 -->
<view style="position: fixed;bottom: 0;left:0;width: 100%;"><uni-goods-nav :fill="true" :options="options" :buttonGroup="buttonGroup" @click="onClick"></uni-goods-nav>
</view>
*************************************************************************************************
options: [{icon: 'headphones',text: '客户'}, {icon: 'shop',text: '店铺',info: 2,backgroundColor: '#007aff',color: 'red'}, {icon: 'cart',text: '购物车',info: 2}],buttonGroup: [{text: '加入购物车',backgroundColor: '#ff0000',color: '#fff'}, {text: '立即购买',backgroundColor: '#ffa200',color: '#fff'}]
*************************************************************************************************
除了说一句:帅!!!!!!!!!!!!!!!!!!!!还能说什么
*************************************************************************************************
点击购物车,跳转到购物车页面
onClick(e) { //点击// console.log(e)if (e.content.text === "购物车") {uni.switchTab({url: "/pages/cart/cart"})}},
【35】140集加入购物车store.js,初始化vuex
import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)const store = new Vuex.Store({modules: {}
})export default store
*************************************************************************************************
// #ifndef VUE3
import Vue from 'vue'
import App from './App'
import store from '@/store/store.js'// 导入网络请求包
import {$http
} from '@escook/request-miniprogram'uni.$http = $http// 请求的根路径
$http.baseUrl = "https://localhost"
//$http.baseUrl = "https://wdfgdzx.top"// 请求开始之前做一些事情
$http.beforeRequest = function(options) {uni.showLoading({title: "数据加载中..."})
}// 请求完成之后做一些事情
$http.afterRequest = function() {uni.hideLoading()
}// 封装一个报错的方法
uni.$message = function(title = "数据请求失败!", duration = 1500) {uni.showToast({title,duration,icon: 'none'})
}Vue.config.productionTip = falseApp.mpType = 'app'const app = new Vue({...App,store
})
app.$mount()
// #endif// #ifdef VUE3
import {createSSRApp
} from 'vue'
import App from './App.vue'
export function createApp() {const app = createSSRApp(App)return {app}
}
// #endif
*************************************************************************************************
购物车数据全局存储
export default {namespaced: true,state: () => ({// 包含6个属性 id name price count image statecart: []}),mutations: {},getters: {}
}
------------------------------------------------------------------------------------------------
import Vue from 'vue'
import Vuex from 'vuex'
import moduleCart from '@/store/cart.js'Vue.use(Vuex)const store = new Vuex.Store({modules: {'m_cart': moduleCart // 关联购物车示例}
})export default store
【36】实现加入购物车功能
辅助函数:
import {mapState} from 'vuex'export default {computed: {...mapState('m_cart', [])},
*************************************************************************************************
...mapMutations('m_cart', ['addCart']), // 使用全局存储方法buttonClick(e) {// console.log(e)if (e.content.text === "加入购物车") {const goods = {id: this.goodsInfo.id,name: this.goodsInfo.name,price: this.goodsInfo.price,count: 1,image: this.goodsInfo.image,state: true // 默认是勾选的}this.addCart(goods)}},
*************************************************************************************************
<template><view v-if="goodsInfo.name" style="padding-bottom: 50px;"><!-- 商品详情页 --><!-- 轮播图区域 --><swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true"style="height: 750rpx;"><swiper-item v-for="(item,index) in goodsInfo.imageList" :key="index"><image :src="item" style="width: 100%;height: 100%;" @click="preview(index)"></image></swiper-item></swiper><!-- 商品信息区域 --><view style="padding: 10px;padding-right: 0;"><!-- 商品价格 --><view style="color: #C00000;font-size: 18px;margin: 10px 0;">¥ {{goodsInfo.price}}</view><!-- 信息主题区域 --><view style="display: flex;justify-content: space-between;"><!-- 商品名称 --><view style="font-size: 13px;margin-right: 10px">{{goodsInfo.name}}</view><!-- 收藏 --><view style="width: 120px;font-size: 12px;display: flex;flex-direction: column;align-items: center;justify-content: center;border-left: 1px solid lightgray;color: gray;"><uni-icons type="star" size="18" color="gray"></uni-icons><text>收藏</text></view></view><!-- 运费区域 --><view style="font-size: 12px;color: gray;margin: 10px 0;">快递:免运费</view></view><!-- 商品详情图片区域  按道理应该是另一个list集合,不和轮播图的问题--><view><view v-for="(item,index) in goodsInfo.imageList" :key="index"style="display: flex;justify-content: center;flex-wrap: wrap;"><image :src="item" style="width: 100%;"></image></view></view><!-- 底部导航区域 --><view style="position: fixed;bottom: 0;left:0;width: 100%;"><uni-goods-nav :fill="true" :options="options" :buttonGroup="buttonGroup" @click="onClick"@buttonClick="buttonClick"></uni-goods-nav></view></view>
</template><script>import {mapState,mapMutations} from 'vuex'export default {computed: {...mapState('m_cart', [])},data() {return {goodsInfo: {imageList: []},options: [// 	{// 	icon: 'headphones',// 	text: '客服'// }, {icon: 'shop',text: '店铺',// info: 2,backgroundColor: '#007aff',color: 'red'}, {icon: 'cart',text: '购物车',info: 2}],buttonGroup: [{text: '加入购物车',backgroundColor: '#ff0000',color: '#fff'}, {text: '立即购买',backgroundColor: '#ffa200',color: '#fff'}]};},onLoad(options) {const id = options.idthis.selectGoods(id)},methods: {...mapMutations('m_cart', ['addCart']), // 使用全局存储方法buttonClick(e) {// console.log(e)if (e.content.text === "加入购物车") {const goods = {id: this.goodsInfo.id,name: this.goodsInfo.name,price: this.goodsInfo.price,count: 1,image: this.goodsInfo.url,state: true // 默认是勾选的}this.addCart(goods) // 调用映射过来的全局存储方法}},onClick(e) { //点击// console.log(e)if (e.content.text === "购物车") {uni.switchTab({url: "/pages/cart/cart"})}},preview(index) { // 预览uni.previewImage({current: index,urls: this.goodsInfo.imageList.map(v => v)})},selectGoods(id) {uni.$http.post("/document/select_id/" + id).then(res => {// console.log(res)if (res.data.code = "200") {this.goodsInfo = res.data.objectthis.goodsInfo.imageList = res.data.object.imageList.split("&&&")// console.log(this.goodsInfo.imageList)} else {return uni.$message()}})}}}
</script><style lang="scss"></style>
*************************************************************************************************
此种有真意,欲辨已忘言
【37】142集 动态统计购物车中商品的总数量
totalNum(state) {let c = 0state.cart.forEach(x => {c = c + x.count})return c // 计算总数}
*****************************************************************************************
watch: {totalNum(newVal) {// console.log(newVal)const findResult = this.options.find(x => x.text === '购物车')if (findResult) {findResult.info = newVal}}},
【38】持久化存储购物车的数据
export default {namespaced: true,state: () => ({// 包含6个属性 id name price count image statecart: JSON.parse(uni.getStorageSync('cart') || '[]')}),mutations: { // 方法在这里定义的addCart(state, goods) {const findResult = state.cart.find(x => x.id === goods.id) // 根据id判断是否存在console.log(findResult)if (!findResult) {state.cart.push(goods)} else {findResult.count++ // 数量+1}// console.log(state.cart)this.commit('m_cart/saveToStorage')},// 持久化存储数据saveToStorage(state) {uni.setStorageSync('cart', JSON.stringify(state.cart)) // 存储到本地}},getters: {totalNum(state) {let c = 0state.cart.forEach(x => {c = c + x.count})return c // 计算总数}}
}
【39】优化total侦听器
因为重新编译后还是0.....日尼玛
watch: {totalNum: {handler(newVal) {const findResult = this.options.find(x => x.text === '购物车')if (findResult) {findResult.info = newVal}},immediate: true // 这个就可以在加载完毕后立刻调用}},
*****************************************************************************************
主要是通过优化侦听器
【40】动态设置tabBar的数字徽标
<script>import {mapGetters} from 'vuex'export default {computed: { // 把全局数据映射到购物车...mapGetters('m_cart', ['totalNum'])},onShow() {this.setBadge()},data() {return {};},methods: {setBadge() {uni.setTabBarBadge({index: 2,text: this.totalNum + ""})}}}
</script>
*****************************************************************************************
把设置tabBar徽标的代码抽离为mixins
因为直接回到首页...等页面,徽标不生效,所以需要抽离!!!!!!!!!!!!!
import {mapGetters
} from 'vuex'export default {computed: { // 把全局数据映射到购物车...mapGetters('m_cart', ['totalNum'])},onShow() {this.setBadge()},methods: {setBadge() {uni.setTabBarBadge({index: 2,text: this.totalNum + ""})}}
}
-------------------------------------------------------------------------------------------------
import mix from '@/mixins/tabbar-badge.js'export default {mixins: [mix],
徽标永存
【41】购物车页面-效果演示和编译模式新增
地址、加减购物、结算----牛批了!!!!!!!!!!!!!
谢谢黑马的老师!!!!!!!!!!!!!
在小程序新增一个直接跳转购物车的模式......简单的一批!!!!!!!!!
*****************************************************************************************
<image :src="item.url ||item.image || defaultImage" style="width: 100px;height: 
100px;display: block;"></image>
我是个人才!!!!!!!!!!!!!!!!!!!!!!!
<!-- 左侧盒子 -->
<view style="margin-right: 5px;display: flex;justify-content: space-between;align-items: center;"><!-- 选择项 --><radio checked="true" color="#C00000"></radio><image :src="item.url ||item.image || defaultImage" style="width: 100px;height: 100px;display: block;"></image>
</view>
*****************************************************************************************
控制显示与隐藏,因为列表也需要隐藏!!!!!!!!!!!!!!!
props: {item: { // 这个名字和页面里使用的名字是一致的,注意!!!!!!!!!!!!type: Object,default: {}},showRadio: {type: Boolean,default: false // 默认不展示选择框 即可,需要的话需要传递true}},
-------------------------------------------------------------------------------------------------
<radio checked="true" color="#C00000" v-if="showRadio"></radio>
-------------------------------------------------------------------------------------------------
验证了一句话:万丈高楼平地起!!!!!!!!!!!!!!又见东风来...
:checked="item.state"
动态绑定选中状态
【42】149集 修改购物车商品的勾选状态
<my-goods :item="item" :showRadio="true" @fff_son_radioChange="fff_son_radioChange"></my-goods>
-------------------------------------------------------------------------------------------------
<radio :checked="item.state" color="#C00000" v-if="showRadio" @click="son_fff_radioClick"></radio>
-------------------------------------------------------------------------------------------------
son_fff_radioClick() { // 子触发父亲函数this.$emit('fff_son_radioChange', {item_id: this.item.id,item_state: !this.item.state})}
-------------------------------------------------------------------------------------------------
fff_son_radioChange(e) {console.log(e)}
*****************************************************************************************
更新购物车里面的商品勾选状态:
// 更新购物车中商品勾选状态
updateGoodsState(state, goods) {const findResult = state.cart.find(x => x.id === goods.id) // 根据id判断是否存在if (findResult) {findResult.state = goods.state // 更新勾选状态this.commit('m_cart/saveToStorage') // 更新存储本地}
}
-------------------------------------------------------------------------------------------------
methods: {...mapMutations('m_cart', ['updateGoodsState']),fff_son_radioChange(e) {// console.log(e)this.updateGoodsState(e) // 更新选中状态 e其实是一个对象,传参对象!!!!!!!!!!!!}}
【43】商品列表-封装NumberBox
<template><!-- 外层容器 --><view><view style="display: flex;padding: 10px 5px;border-bottom: 1px solid lightgray;"><!-- 左侧盒子 --><view style="margin-right: 5px;display: flex;justify-content: space-between;align-items: center;"><!-- 选择项 --><radio :checked="item.state" color="#C00000" v-if="showRadio" @click="son_fff_radioClick"></radio><image :src="item.url ||item.image || defaultImage" style="width: 100px;height: 100px;display: block;"></image></view><!-- 右侧盒子 --><view style="display: flex;flex-direction: column;justify-content: space-between;flex:1;"><!-- 商品名称 --><view style="font-size: 13px;">{{item.name}}</view><!-- 包了一层 --><view style="display: flex;justify-content: space-between;align-items: center;"><!-- 商品价格 --><view style="color: #C00000;font-size: 16px;">¥ {{item.price | toFixed}}</view><!-- 商品数量 --><uni-number-box :min="1" :value="item.count"></uni-number-box></view></view></view></view>
</template><script>export default {name: "my-goods",props: {item: { // 这个名字和页面里使用的名字是一致的,注意!!!!!!!!!!!!type: Object,default: {}},showRadio: {type: Boolean,default: false // 默认不展示选择框 即可,需要的话需要传递true}},data() {return {defaultImage: 'http://wdfgdzx.top:8000/document/a5dd6d1d1c5c45dd98c6017b1821acb8.jpg', // 默认图片地址};},filters: {toFixed(num) {return Number(num).toFixed(2)}},methods: {son_fff_radioClick() { // 子触发父亲函数this.$emit('fff_son_radioChange', {id: this.item.id,state: !this.item.state})}}}
</script><style lang="scss"></style>
*****************************************************************************************
数量框的按需展示:
数据库读取最好用线上,不然麻烦不少呀!!!!!!!!!!!!!!!!
【44】151集 封装num-change事件,也是父传子,子传父的问题
<template><!-- 外层容器 --><view><view style="display: flex;padding: 10px 5px;border-bottom: 1px solid lightgray;"><!-- 左侧盒子 --><view style="margin-right: 5px;display: flex;justify-content: space-between;align-items: center;"><!-- 选择项 --><radio :checked="item.state" color="#C00000" v-if="showRadio" @click="son_fff_radioClick"></radio><image :src="item.url ||item.image || defaultImage" style="width: 100px;height: 100px;display: block;"></image></view><!-- 右侧盒子 --><view style="display: flex;flex-direction: column;justify-content: space-between;flex:1;"><!-- 商品名称 --><view style="font-size: 13px;">{{item.name}}</view><!-- 包了一层 --><view style="display: flex;justify-content: space-between;align-items: center;"><!-- 商品价格 --><view style="color: #C00000;font-size: 16px;">¥ {{item.price | toFixed}}</view><!-- 商品数量 --><uni-number-box :min="1" :value="item.count" v-if="showNum" @change="son_fff_numChange"></uni-number-box></view></view></view></view>
</template><script>export default {name: "my-goods",props: {item: { // 这个名字和页面里使用的名字是一致的,注意!!!!!!!!!!!!type: Object,default: {}},showRadio: {type: Boolean,default: false // 默认不展示选择框 即可,需要的话需要传递true},showNum: {type: Boolean,default: false // 默认不展示数量框 即可,需要的话需要传递true}},data() {return {defaultImage: 'http://wdfgdzx.top:8000/document/a5dd6d1d1c5c45dd98c6017b1821acb8.jpg', // 默认图片地址};},filters: {toFixed(num) {return Number(num).toFixed(2)}},methods: {son_fff_radioClick() { // 子触发父亲函数this.$emit('fff_son_radioChange', {id: this.item.id,state: !this.item.state})},son_fff_numChange(val) { // 子触发父亲函数this.$emit('fff_son_numChange', {id: this.item.id,count: val - 0 // 这就是最新的数量值})}}}
</script><style lang="scss"></style>
【45】152 优化NumberBox组件
uni-number-box.vue已经默认解决了,最大值是100个,可以修改
*****************************************************************************************
inputValue 小数的处理也是默认帮处理了,果然技术的发展是牛批的,不断更新的!!!!!
*****************************************************************************************
uni-number-box.vue已经自优化了!!!!!!
【46】修改购物车数量持久化存储
问题:修改数量后,重新编译后还是变回原来的了....
搞半天,Hbulider没有运行到小程序,搞笑呀!!!!!!!!!!!!!!!!!!!!
// 更新商品的数量并保存到本地updateCount(state, goods) { // 更新商品数量const findResult = state.cart.find(x => x.id === goods.id) // 根据id判断是否存在if (findResult) {findResult.count = goods.count // 更新数量// console.log(findResult)this.commit('m_cart/saveToStorage') // 更新存储本地}}
*****************************************************************************************
fff_son_numChange(e) {// console.log(e)this.updateCount(e) // 更新选中状态 e其实是一个对象,传参对象!!!!!!!!!!!!
}
【47】滑动删除的UI效果
之后查看官网示例时发现options是旧版的写法,我使用的是新版,要用right-options代替。
*****************************************************************************************
坑呀!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*****************************************************************************************
<!-- 渲染购物车中的商品信息 -->
<uni-swipe-action><block v-for="(item,index) in cart" :key="index"><uni-swipe-action-item :right-options="options" @click=""><my-goods :item="item" :showRadio="true" :showNum="true" @fff_son_radioChange="fff_son_radioChange"@fff_son_numChange="fff_son_numChange"></my-goods></uni-swipe-action-item></block>
</uni-swipe-action>
*****************************************************************************************
data() {return {options: [{text: '删除',style: {backgroundColor: '#C00000'}}]};},
*****************************************************************************************
实现滑动删除的功能
代码写错,导致state.cart出错,耗费了我不少时间排查
还得实现保存空,重新保存,没少费劲
removeGoodsById(state, goods) { // 根据id删除商品state.cart = state.cart.filter(x => x.id !== goods.id)this.commit('m_cart/saveToStorage') // 更新存储本地}
*****************************************************************************************
@click="swipeItemClick(item)">
swipeItemClick(item) {// console.log(item)this.removeGoodsById(item)
}
【48】收货地址的实现!!!!!!!!!!!!!!!!!!155集
<template><view>收货地址组件</view>
</template><script>export default {name: "my-address",data() {return {};}}
</script><style lang="scss"></style>
*****************************************************************************************
<template><view><!-- 选择收货地址的盒子 --><view style="height: 90px;display: flex;justify-content: center;align-items: center;"><button type="primary" size="mini" style="">请选择收货地址+</button></view><!-- 底部边框 --><image src="/static/cart_border@2x.png" style="display: flex;width: 100%;height: 5px;"></image></view>
</template><script>export default {name: "my-address",data() {return {};}}
</script><style lang="scss"></style>
*****************************************************************************************
<template><view><!-- 选择收货地址的盒子 --><view style="height: 90px;display: flex;justify-content: center;align-items: center;"><button type="primary" size="mini" style="">请选择收货地址+</button></view><!-- 渲染收货信息的盒子 --><viewstyle="font-size: 12px;height: 90px;display: flex;flex-direction: column;justify-content: center;padding: 0 5px;"><!-- 第一行 --><view style="display: flex;justify-content: space-between;"><!-- 左右布局 --><view>收货人:ask</view><view style="display: flex;"><view>电话:183XXXX0000</view><uni-icons type="arrowright" size="16"></uni-icons></view></view><!-- 第二行 --><view style="display: flex;justify-content: space-between;align-items: center;margin-top: 10px;"><!-- 左右布局 --><view style="white-space: nowrap;">收货地址:</view><view>安徽省合肥市蜀山区创新大道2889号苏宁小店安徽省合肥市蜀山区创新大道2889号苏宁小店安徽省合肥市蜀山区创新大道2889号苏宁小店</view></view></view><!-- 底部边框 --><image src="/static/cart_border@2x.png" style="display: flex;width: 100%;height: 5px;"></image></view>
</template><script>export default {name: "my-address",data() {return {};}}
</script><style lang="scss"></style>
*****************************************************************************************
按需展示<view style="height: 90px;display: flex;justify-content: center;align-items: center;"v-if="JSON.stringify(address)==='{}'"><button type="primary" size="mini" style="">请选择收货地址+</button></view><!-- 渲染收货信息的盒子 --><view v-elsestyle="font-size: 12px;height: 90px;display: flex;flex-direction: column;justify-content:center;padding: 0 5px;">
【49】实现选择收货地址功能
"requiredPrivateInfos": ["getLocation","chooseAddress"]
要使用,先开启
*****************************************************************************************
然后再配置方法
methods: {async pickAddress() {const [err, success] = await uni.chooseAddress().catch(err => err)// console.log(res)if (err === null && success.errMsg === 'chooseAddress:ok') {// console.log(success)this.address = success}}}
【50】渲染收货人信息
computed: {addressStr() {if (!this.address.provinceName) {return ''} else {return this.address.provinceName + this.address.cityName + this.address.countyName + this.address.detailInfo}}},
【51】将客户选择的地址,存储到VUEX全局存储中
export default {namespaced: true, // 开启命名空间// 数据节点state: () => ({address: {}}),// 方法mutations: {updateAddress(state, address) {state.address = address // 更新收货地址}},// 访问方法getters: {}
}
*****************************************************************************************
...mapState('m_user', ['address']),
*****************************************************************************************methods: {...mapMutations('m_user', ['updateAddress']),async pickAddress() {const [err, success] = await uni.chooseAddress().catch(err => err)// console.log(res)if (err === null && success.errMsg === 'chooseAddress:ok') {// console.log(success)// this.address = successthis.updateAddress(success) // 更新地址}}}
【52】持久化存储到store.js中
updateAddress(state, address) {state.address = address // 更新收货地址this.commit('m_user/saveAddressToStorage'); // 调用存储},saveAddressToStorage(state) {uni.setStorageSync('address', JSON.stringify(state.address)) // 存储到本地}
【53】将addressStr抽离为getters,目的是提高代码的复用性
export default {namespaced: true, // 开启命名空间// 数据节点state: () => ({address: JSON.parse(uni.getStorageSync('address') || '{}')}),// 方法mutations: {updateAddress(state, address) {state.address = address // 更新收货地址this.commit('m_user/saveAddressToStorage'); // 调用存储},saveAddressToStorage(state) {uni.setStorageSync('address', JSON.stringify(state.address)) // 存储到本地}},// 访问方法getters: {addressStr(state) {if (!state.address.provinceName) {return ''} else {return state.address.provinceName + state.address.cityName + state.address.countyName + state.address.detailInfo}}}
}
*****************************************************************************************import {mapState,mapMutations,mapGetters} from 'vuex'export default {name: "my-address",data() {return {// address: {}};},computed: {...mapState('m_user', ['address']),...mapGetters('m_user', ['addressStr'])},methods: {...mapMutations('m_user', ['updateAddress']),
【54】重新选择收货地址<view v-else @click="pickAddress"style="font-size: 12px;height: 90px;display: flex;flex-direction: column;justify-content: center;padding: 0 5px;">
*****************************************************************************************
解决收货地址授权失败的问题!!!!!!!!!!
我的项目好像没这个问题,牛批  162说解决了这个问题,但是我的不需要解决,哈哈哈
【55】封装结算区域的组件
<template><view style="position: fixed; bottom: 0;left: 0;width: 100%;height: 50px;background-color: yellow;">结算组件</view>
</template><script>export default {name: "my-settle",data() {return {};}}
</script><style lang="scss"></style>
*****************************************************************************************
<template><view style="position: fixed; bottom: 0;left: 0;width: 100%;height: 50px;background-color: white;display: flex;justify-content: space-between;align-items: center;font-size: 14px;padding-left: 5px;"><!-- 全选 --><label style="display: flex;align-items: center;"><radio color="#C00000" :checked="true" /><text>全选</text></label><!-- 合计 --><view>合计:<text style="color: #C00000;font-weight: bold;">¥ 123.06</text></view><!-- 结算按钮 --><viewstyle="background-color: #C00000;height: 50px;color: white;line-height: 50px;padding: 0 10px;min-width: 100px;text-align: center;">结算(0)</view></view>
</template><script>export default {name: "my-settle",data() {return {};}}
</script><style lang="scss"></style>
【56】动态渲染已勾选商品的总数量!!!!!!!!!!!!!!!!!!!!!!!
checkedCount(state) {// console.log(tempList)let total = 0state.cart.filter(x => x.state).forEach(item => {// console.log(item.count)total = total + item.count})return total}
*****************************************************************************************
动态渲染全选的状态:
computed: {...mapGetters('m_cart', ['checkedCount', 'totalNum']),fullCheckFlag() {return this.totalNum === this.checkedCount}}
【57】商品的全选和反选功能updateAllGoodsState(state, newState) { // 更新所有商品的勾选状态state.cart.forEach(x => x.state = newState)this.commit('m_cart/saveToStorage') // 更新存储本地}
*****************************************************************************************...mapMutations('m_cart', ['updateAllGoodsState']),changeAllState() { // 改变所有商品的勾选状态// console.log("执行了")this.updateAllGoodsState(!this.fullCheckFlag)}
*****************************************************************************************
getGoodsCheckedPrice(state) {let total = 0state.cart.filter(x => x.state).forEach(item => {// console.log(item.count)total = total + item.price * item.count})return total.toFixed(2)}
*****************************************************************************************
...mapGetters('m_cart', ['checkedCount', 'totalNum', 'getGoodsCheckedPrice']),
*****************************************************************************************
<view>合计:<text style="color: #C00000;font-weight: bold;">¥ {{getGoodsCheckedPrice}}</text></view>
*****************************************************************************************
动态计算购物车徽标的数值,就是自己一直关注的tabBar数字不更新问题的处理!!!!
import {mapGetters
} from 'vuex'export default {computed: { // 把全局数据映射到购物车...mapGetters('m_cart', ['totalNum'])},watch: { // !!!!!!!!!!!!!!!!!!!!!this onetotalNum() {this.setBadge()}},onShow() {this.setBadge()},methods: {setBadge() {uni.setTabBarBadge({index: 2,text: this.totalNum + ""})}}
}
【58】购物车细节渲染
<view v-if="cart.length!==0">
<!-- 空购物车 --><view v-else style="display: flex;flex-direction: column;align-items: center;padding-top: 150px;"><image src="/static/cart_empty@2x.png" style="width: 90px;height: 90px;"></image><text style="font-size: 12px;color: gray;margin-top: 15px;">购物车空空如也~</text></view>
【59】170集 登录与支付
settleClick() { // 用户点击了结算按钮if (!this.checkedCount) {return uni.$message("请选择要结算的商品")}if (!this.addressStr) {return uni.$message("请选择收货地址")}if (!this.token) {return uni.$message("请您先登录账户")}}
【60】登录页面UI的初步渲染
创建下我的页面的编译模式
********************************************************************************************
登录和登录后判断条件展示<!-- 登录组件 --><my-login v-if="!token"></my-login><!-- 登录后组件 --><my-user-info v-else></my-user-info>
********************************************************************************************
<template><view><uni-icons type="contact-filled" size="100" color="#AFAFAF"></uni-icons><button type="primary" style="">一键登录</button><text style="">登录后进行更多权益</text></view>
</template><script>export default {name: "my-login",data() {return {};}}
</script><style lang="scss"></style>
********************************************************************************************
<template><viewstyle="height: 750rpx;background-color: #F8F8F8;display: flex;flex-direction: column;justify-content: center;align-items: center;"><uni-icons type="contact-filled" size="100" color="#AFAFAF"></uni-icons><button type="primary"style="width: 90%;border-radius: 100px;margin: 15px 0;background-color: #C00000;">一键登录</button><text style="font-size: 12px;color: gray">登录后进行更多权益</text></view>
</template><script>export default {name: "my-login",data() {return {};}}
</script><style lang="scss"></style>
********************************************************************************************
<template><view class="login-container" style="height: 750rpx;background-color: lightgray;display: flex;flex-direction: column;justify-content: center;align-items: center;position: relative;overflow: hidden;"><uni-icons type="contact-filled" size="100" color="#AFAFAF"></uni-icons><button type="primary"style="width: 90%;border-radius: 100px;margin: 15px 0;background-color: #C00000;">一键登录</button><text style="font-size: 12px;color: gray">登录后进行更多权益</text></view>
</template><script>export default {name: "my-login",data() {return {};}}
</script><style lang="scss">.login-container {&::after {content: '';display: block;width: 100%;height: 40px;background-color: #F5F5F5;position: absolute;bottom: 0;left: 0;border-radius: 100%;transform: translateY(50%);}}
</style>
【61】点击按钮实现登录 172集
open-type="getUserInfo" @getuserinfo="getUserInfo"
前面的那个更重要!!!!!!!!!!!!!!!!!!
【62】将用户的基本信息存储到本地
updateUserInfo(state, userInfo) {state.userInfo = userInfothis.commit('m_user/saveUserInfoToStorage'); // 调用存储},saveUserInfoToStorage(state) {uni.setStorageSync('userInfo', JSON.stringify(state.userInfo))}
********************************************************************************************
...mapMutations('m_user', ['updateUserInfo']),getUserInfo(e) {if (e.detail.errMsg === 'getUserInfo:fail auth deny') {return uni.$message("您取消了登录授权")}this.updateUserInfo(e.detail.userInfo)// console.log(e)}
【63】调动uni.login获取用户登录凭证
async getToken(info) { // 获取code的值// 获取code对应的值const [err, res] = await uni.login().catch(err => err)// console.log(res)if (err || res.errMsg !== 'login:ok') {return uni.$message('登录失败')}console.log(res.code)console.log(info)}
【64】获取token并存储到vuex
先继续写,后面可能需要改造login API
uni.$http.post('/api/public/v1/users/wxlogin', sendData).then(res => {console.log(res)if (res.statusCode !== 200) {return uni.$message("登录失败!")}uni.$message("登录成功!")this.updateToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjIzLCJpYXQiOjE1NjQ3MzAwNzksImV4cCI6MTAwMTU2NDczMDA3OH0")})
********************************************************************************************
我设置的是假的Token,后台接口需要根据信息生成
【65】登录后信息布局展示
<template><view style="height: 100%;background-color: #F4F4F4;"><!-- 头像和昵称区域 --><viewstyle="height: 400rpx;background-color:#C00000;display: flex;justify-content: center;align-items: center;flex-direction: column;"><image :src="userInfo.url"style="width: 90px;height: 90px;border-radius: 45px;border: 2px solid #FFF;box-shadow: 0 1px 5px black;"></image><view style="font-size: 16px;color: #FFF;font-weight: bold;margin-top: 10px;">{{userInfo.nickName}}</view></view></view>
</template><script>import {mapState} from 'vuex'export default {name: "my-user-info",computed: {...mapState('m_user', ['userInfo'])},data() {return {};}}
</script><style lang="scss"></style>
【66】渲染第一个面板区域
<!-- 1个面板 panel1--><view><view> <!-- panel-body --><view> <!-- panel-item --><text>8</text><text>收藏的店铺</text></view><view> <!-- panel-item --><text>14</text><text>收藏的商品</text></view><view> <!-- panel-item --><text>18</text><text>关注的商品</text></view><view> <!-- panel-item --><text>84</text><text>足迹</text></view></view></view>
********************************************************************************************
<!-- 1个面板 panel1--><view style="padding: 0 10px;position: relative;top:-10px;"><!-- panel-body --><viewstyle="background-color: white;border-radius: 3px;margin-bottom: 8px;display: flex;justify-content: space-around;"><!-- panel-item --><view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;font-size: 13px;"><text>8</text><text>收藏的店铺</text></view><!-- panel-item --><view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;font-size: 13px;"><text>14</text><text>收藏的商品</text></view><!-- panel-item --><view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;font-size: 13px;"><text>18</text><text>关注的商品</text></view><!-- panel-item --><view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;font-size: 13px;"><text>84</text><text>足迹</text></view></view></view>
【67】渲染第二个面板区域
<view style="padding: 0 10px;position: relative;top:-10px;"><!-- title --><viewstyle="line-height: 45px;padding-left: 10px;font-size: 15px;border-bottom: 1px solid #F4F4F4;background-color: white;">我的订单</view><!-- body --><viewstyle="background-color: white;border-radius: 3px;margin-bottom: 8px;display: flex;justify-content: space-around;"><!-- panel-item --><view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;font-size: 13px;"><image src="/static/my-icons/icon1.png" style="width:35px;height: 35px;"></image><text>待付款</text></view><!-- panel-item --><view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;font-size: 13px;"><image src="/static/my-icons/icon2.png" style="width:35px;height: 35px;"></image><text>待收货</text></view><!-- panel-item --><view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;font-size: 13px;"><image src="/static/my-icons/icon3.png" style="width:35px;height: 35px;"></image><text>退款/退货</text></view><!-- panel-item --><view style="display: flex;flex-direction: column;align-items: center;justify-content: space-around;padding: 10px 0;font-size: 13px;"><image src="/static/my-icons/icon4.png" style="width:35px;height: 35px;"></image><text>全部订单</text></view></view></view>
【68】第三个面板
<!-- 3个面板 --><!-- panel --><view style="padding: 0 10px;position: relative;top:-10px;"><!-- panel list --><view style="background-color: white;"><viewstyle="display: flex;justify-content: space-between;align-items: center;font-size: 15px;padding: 0 10px;line-height: 45px;"><text>收货地址</text><uni-icons type="arrowright" @size="15"></uni-icons></view><!-- panel list --><viewstyle="display: flex;justify-content: space-between;align-items: center;font-size: 15px;padding: 0 10px;line-height: 45px;"><text>联系客服</text><uni-icons type="arrowright" @size="15"></uni-icons></view><!-- panel list --><viewstyle="display: flex;justify-content: space-between;align-items: center;font-size: 15px;padding: 0 10px;line-height: 45px;"><text>退出登录</text><uni-icons type="arrowright" @size="15"></uni-icons></view></view></view>
【69】退出登录功能的实现
methods: {...mapMutations('m_user', ['updateAddress', 'updateUserInfo', 'updateToken']),async logout() {const [err, success] = await uni.showModal({title: '提示',content: '确认需要退出登录吗?'}).catch(err => err)if (success && success.confirm) {this.updateAddress({})this.updateUserInfo({})this.updateToken({})}}}
【70】182集  3秒后跳转登录页面if (this.token.length === undefined) {// return uni.$message("请您先登录账户")return this.delayNav();}},showTips(n) { // 展示倒计时提示uni.showToast({icon: 'none',title: '请登录后再结算!' + n + '秒后自动跳转到登录页',mask: true,duration: 1500})},delayNav() { // 延迟导航到my登录页面this.showTips(this.endTime)setInterval(() => {this.endTime--this.showTips(this.endTime)}, 1000)}
********************************************************************************************
delayNav() { // 延迟导航到my登录页面this.showTips(this.endTime)this.timer = setInterval(() => {this.endTime--if (this.endTime <= 0) {clearInterval(this.timer) // 清除定时器uni.switchTab({url: '/pages/my/my'})return}this.showTips(this.endTime)}, 1000)}
主要是判断+clearInterval的应用!!!!!!!!!!!!!!!!
和uni.switchTab的使用......................................
********************************************************************************************
解决endTime倒计时不会重置的问题,我自己解决的,好屌呀!!!!!!!!!!!!!!
if (this.endTime <= 0) {this.endTime = 3}
【71】如果在登录成功之后,返回之前的页面 183集
delayNav() { // 延迟导航到my登录页面if (this.endTime <= 0) {this.endTime = 3}this.showTips(this.endTime)this.timer = setInterval(() => {this.endTime--if (this.endTime <= 0) {clearInterval(this.timer) // 清除定时器uni.switchTab({url: '/pages/my/my',success: () => {this.updateRedirectInfo({openType: 'switchTab',from: '/pages/cart/cart'})}})return}this.showTips(this.endTime)}, 1000)}
********************************************************************************************
navigateBack() {if (this.redirectInfo && this.redirectInfo.openType === 'switchTab') {uni.switchTab({url: this.redirectInfo.from,complete: () => {this.updateRedirectInfo(null) // 重定向后置为null}})}}
【72】在请求头重添加Token身份认证字段
搞半天其实是为了安全保证...
// 请求开始之前做一些事情
$http.beforeRequest = function(options) {uni.showLoading({title: "数据加载中..."})// console.log("我0604:" + JSON.stringify(options))if (options.url.indexOf('wx') !== -1) { // 这是包含的情况options.header = {Authorization: store.state.m_user.token}}// console.log("我0604:" + JSON.stringify(options))
}
【73】了解微信支付的概念
创建订单,返回订单编号
********************************************************************************************
订单预支付
********************************************************************************************
发起微信支付
【74】创建订单API接口
// 2创建订单 - 发起请求uni.$http.post('/wx_buy', sendData).then(res => {// console.log("0604打印" + JSON.stringify(res))if (res.data.code !== '200') {return uni.$message("订单创建失败")}const orderNumber = res.data.object.no; // 订单编号// console.log("0604打印" + orderNumber)})
********************************************************************************************
创建并返回订单编号,这个重点在后端
【75】实现订单的预支付 187集-----------!!!!!!!!!!!!!!!!!!!!!!
********************************************************************************************
中间遇到了支付的问题。提交工商户审核
【76】发起微信支付
uni.requestPayment(payInfo)
【77】微信小程序发布的流程
提升用户体验,缩小体积
【78】uniapp发布为小程序
点击Hbulid的发行
---------------------------------------------------------------------------------------------------------
小程序-微信(第5个)
---------------------------------------------------------------------------------------------------------
小程序名称+APPID
---------------------------------------------------------------------------------------------------------
这样发型的体积更小 更好用!!!!!!!!!!!!!!!!!这个还挺重要的!!!!!
---------------------------------------------------------------------------------------------------------
提交小程序审核即可
【79】发布为Android APP
APP 图标配置
---------------------------------------------------------------------------------------------------------
发行—>原生APP—>云打包
---------------------------------------------------------------------------------------------------------
注意:选择收货地址、微信登录、微信支付是无法正常使用的!!!!!!!!

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

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

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

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


http://www.mrgr.cn/p/72053725

相关文章

windows10 资源管理器 卡死 底部任务栏不显示程序 点击底部任务栏两次会重启资源管理器继续卡死

故障存储段 ,类型 0事件名称: AppHangB1响应: 不可用Cab ID: 0 问题签名:P1: explorer.exeP2: 10.0.19041.1266P3: 418a6e83P4: a874P5: 134217728P6: P7: P8: P9: P10: 附加文件:\\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WERE85A.tmp.WERInternalMetadata.xml\\?\C…

偏微分方程算法之混合边界条件下的差分法

目录 一、研究目标 二、理论推导 三、算例实现 四、结论 一、研究目标 我们在前几节中介绍了Poisson方程的边值问题&#xff0c;接下来对椭圆型偏微分方程的混合边值问题进行探讨&#xff0c;研究对象为&#xff1a; 其中&#xff0c;为矩形区域&#xff0c;为上的连续函数…

使用nmcli命令在各Linux系统上统一的配置网络

前言&#xff1a;原文在我的博客网站中&#xff0c;持续更新数通、系统方面的知识&#xff0c;欢迎来访&#xff01; 使用nmcli命令在各Linux系统上统一的配置网络https://myweb.myskillstree.cn/123.html 你是否会遇到在不同的Linux系统中配置网络时&#xff0c;修改的配置文…

深入探索JavaScript中的structuredClone:现代深拷贝的解密指南

在 JavaScript 中,实现深拷贝的方式有很多种,每种方式都有其优点和缺点。今天介绍一种原生 JavaScript 提供的structuredClone实现深拷贝。 下面列举一些常见的方式,以及它们的代码示例和优缺点: 1. 使用 JSON.parse(JSON.stringify(obj)) 代码示例:function deepClone(ob…

keycloak~登录皮肤动态切换的尝试

keycloak的登录皮肤theme,可以设置领域全局的,或者每个客户端进行单独设置,这种设计是没有问题的,但有时,一个客户端可能有多种主题,这时,你只能再加个客户端,对应新的主题,但这样不方便日后的统计,因为很多统计维度都是以client为基础的,所以,我们需要在进入登录页…

基于TRIZ理论的锂电池生产工艺优化思路

在能源科技迅猛发展的今天&#xff0c;锂电池作为重要的储能元件&#xff0c;其生产工艺的优化与革新显得尤为关键。本文将基于TRIZ理论&#xff0c;探讨锂电池生产工艺的优化路径&#xff0c;以期提升能源产业的效率与环保性。 TRIZ&#xff0c;即发明问题解决理论&#xff0…

爆爽,英语小白怒刷 50 课!像玩游戏一样学习英语~

### 重点!!!(先看这) 1. 清楚自己学英语的`目的`, 先搞清楚目标,再行动2. 自身现在最需要的东西:`词汇量`?`口语`?还是`阅读能力`?3. 找对应的书籍,学习资料4. 往`兴趣靠拢`:网上有大量的推荐美剧学习、小说学习,不要被他们迷了眼,适合他们的不一定适合你,找到适合…

【数据结构】 二叉树的顺序结构——堆的实现

普通的二叉树是不适合用数组来存储的&#xff0c;因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储 。 一、堆的概念及结构 父节点比孩子结点大 是大堆 父节点比孩子结点小 是小堆 堆的性质 堆中某…

如何在ArcGIS Pro中添加无标注的底图

在ArcGIS 3.0中,新建一个地图会自带两个图层,分别是 World Topographic Map 和 World _Hillshade,也就是世界地形图和世界山体阴影,这套底图的颜色和符号的使用都非常赏心悦目。 但是我们在制图时,有时候想利用这个底图,却不想使用地图中的标注。而这个标注是没办法通过简…

Google搜索广告怎么开户?谷歌广告开户投放引流技巧、账户搭建、谷歌ads广告推广投放策略 #搜索引擎 #谷歌广告#互联网营销

Google搜索广告开户步骤&#xff1a; 选择代理商&#xff1a;首先&#xff0c;您需要选择一个经验丰富、信誉良好的Google广告代理商。可以选择上海上弦来广告开户和代运营。 初步咨询&#xff1a;与代理商进行初步沟通&#xff0c;了解他们的服务内容、成功案例、收费标准等。…

PyQt 入门

Qt hello - 专注于Qt的技术分享平台 Python体系下GUI框架也多了去了&#xff0c;PyQt算是比较受欢迎的一个。如果对Qt框架熟悉&#xff0c;那掌握这套框架是很简单的。 一&#xff0c;安装 1.PyQt5 pip3 install PyQt5 2.Designer UI工具 pip3 install PyQt5-tools 3.UI…

JL-杰理芯片-认识TA的SDK的第一天

编写不同SDK的软件用宏定义进行包含,方便知道它的效果,也方便删除不用,更容易知道是什么模块的 原理图决定软件板级根据板子名称决定板子的配置 板级文件的选择不注释哪个就使用哪个

SOLIDWORKS参数化设计的作用

SOLIDWORKS参数化设计软件,主要解决加工制造型企业普遍存在的系列化产品设计周期长和出图效率低。重复工作多、人员工作强度大的问题。传统的设计模式下大规模定制型产品结构设计周期长,问题多,以及大量重复性工作让工程师疲于应对,这些严重阻碍了公司订单承接能力和技术创…

使用Docker安装MySQL5.7.36

拉取镜像并查看 docker pull mysql:5.7.36拉取成功后查看&#xff08;非必须&#xff09; docker images创建并设置宿主机 mysql 配置文件目录和数据文件目录 创建相关文件夹将容器中的mysql数据保存到本地&#xff0c;这样即使容器被删除&#xff0c;数据也不会丢失。 mkd…

【IDEA神器插件推荐】国产崛起!地表最强API测试插件

1.前言 在开发SpringBoot网站应用的过程中,前端后端会对接口进行请求测试。相信很多小伙伴都用过Postman,但是在IDE和Postman切换难免令人心烦。所以今天给大家带来一款IDEA内置的接口测试插件。 2.简介 根据插件的简介:Restful Fast Request 是一个类似于 Postman 的 Intel…

京东手势验证码-YOLO姿态识别+Bézier curve轨迹拟合

这次给老铁们带来的是京东手势验证码的识别。 目标网站&#xff1a;https://plogin.m.jd.com/mreg/index 验证码如下图: 当第一眼看到这个验证码的时候&#xff0c;就头大了&#xff0c;这玩意咋识别&#xff1f;&#xff1f;&#xff1f; 静下心来细想后的一个方案&#xf…

django显示网页步骤

显示网页步骤 小白的django学习笔记 2024/5/6 8:30 文章目录 显示网页步骤创建输入框&#xff08;文本、单选、多选&#xff09;效果如何在django中显示网页写函数配置地址运行&#xff0c;要选择这个工程名的&#xff0c;使用socket复制ip&#xff0c;后面在加上名字,成功&…

linux安装python3.8

一、卸载损坏的yum并安装 本来想直接下载安装python3.8,结果过程中损坏了yum,导致yum无法使用。 参考了【故障】6、yum不可用_yum命令无法使用-CSDN博客 1、删除python #删除现有的python rpm -qa|grep python|sudo xargs rpm -ev --allmatches --nodeps #强制删除已安装程…

2024好用的网页客服系统推荐?

2024好用的网页客服系统推荐&#xff1f;Zoho SalesIQ是一款强大的实时聊天工具&#xff0c;专为网站和在线商店设计。它提供了一套全面的功能&#xff0c;帮助企业实时解决客户问题&#xff0c;提高转化率和客户满意度。 实时监控 Zoho SalesIQ能够实时监控网站的访问者活动&…

Spring添加注解读取和存储对象

5大注解 Controller 控制器 Service 服务 Repository 仓库 Componet 组件 Configuration 配置 五大类注解的使用 //他们都是放在同一个目录下&#xff0c;不同的类中 只不过这里粘贴到一起//控制器 Controller public class UserController {public void SayHello(){System.ou…