1. 小程序-起步
1.1 小程序简介
1.1.1 小程序与普通网页开发的区别
- 运行环境不同:网页运行在浏览器环境中,小程序运行在微信环境中
- API不同:由于运行 环境的不同,小程序无法调用DOM和BOM的API
- 开发模式不同:网页的开发模式–>浏览器+代码编辑器;小程序的开发模式–>申请小程序开发账号,安装小程序开发工具,创建和配置小程序项目
1.2 第一个小程序
-
注册小程序开发账号:使用浏览器打开: https://mp.weixin.qq.com 网址,点击右上角的"立即注册",即可进入小程序开发账号的注册流程,完成相关流程。
-
获取小程序的AppID:扫码登入网址后->点击开发->开发设置->AppID
-
下载开发者工具:https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html
-
安装成功后,扫码登录
1.3 小程序代码的构成
-
App.json 文件
app.json是当前⼩程序的全局配置,包括了⼩程序的所有⻚⾯路径、界⾯表现、⽹络超时时间、底部tab等。普通快速启动项⽬⾥边的app.json配置
{ "pages":[ "pages/index/index", "pages/logs/logs" ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle":"black" }, "style":"v2", "sitemapLocation":"sitemap.json" }
字段的含义:
- pages字段⽤于描述当前⼩程序所有⻚⾯路径,这是为了让微信客⼾端知道当前你的⼩程序⻚⾯定义在哪个⽬录。
- window字段定义⼩程序所有⻚⾯的顶部背景颜⾊,⽂字颜⾊定义等。
- style:全局定义小程序组件所使用的样式版本
- sitemapLocation:用来指明sitemap.json的位置
-
sitemap.json文件
sitemap的索引提示是默认开启的,如需要关闭sitemap的索引提示,可在小程序项目配置文件project.config.json的setting中配置字段checkSiteMap为false
-
页面的.json文件
页面中的配置会覆盖app.json的window中相同的配置项
1.4 小程序的宿主环境
1.4.1 什么是宿主环境
宿主环境:指的是程序运行所必须的依赖环境,脱离了宿主环境的软件是没有任何意义的
1.4.2 小程序的宿主环境
手机微信就是小程序的宿主环境,小程序借助宿主环境提供的能力,可以完成许多普通网页无法完成的功能
1.4.3 小程序宿主环境包含的内容
-
通信模型
-
小程序通信的主体是逻辑层和渲染层,其中:WXML模板和WXSS样式工作在渲染层,JS脚本工作在逻辑层
-
小程序的通信模型:逻辑层和渲染层之间的通信(由微信客户端进行转发);逻辑层和第三方服务器之间的通信(由微信客户端进行转发)
-
-
运行机制
-
小程序启动过程:下载代码包到本地–>解析app.json全局配置文件–>执行app.js小程序入口文件,调用App()创建小程序实例–>渲染小程序首页–>小程序启动完成
-
页面渲染过程:加载解析页面的.json配置文件–>加载页面的.wxml模板和.wxss样式–>执行页面的.js文件,调用Page()创建页面实例–>页面渲染完成
-
-
组件
-
容器类组件:view(普通视图区域,类似于div,是块级元素,用来实现页面的布局效果);scroll-view:(可滚动的视图区域,常用来实现滚动列表效果);swiper和swiper-item(轮播图组件和轮播图item组件)
如下是swiper的属性:
-
基础类组件:text(文本文件,类似于span,是行内元素,text的selectable属性,实现长按选中文本内容);rich-text(富文本文件,通过组件的nodes属性结点,把HTML字符串渲染为对应的UI结构)
nodes属性设置:
<rich-text nodes="<h1 style='color:red'>提示</h1>"></rich-text>
-
button(按钮组件,通过open-type属性可以调用微信提供的各种功能)
-
img(图片组件,默认width=300px,height=240px,支持懒加载)
-
navigator(页面导航组件,类似于a标签)
-
-
API
- 事件监听API:以on开头,用来监听某些事件的触发,如:wx.onWindowResize(function callback)监听窗口尺寸变化的事件
- 同步API:以Sync结尾的API,同步API的执行结果,可以通过函数返回值直接获取,如果执行出错会抛出异常,如:wx.setStorageSync(‘key’,‘value’) 向本地存储中写入内容
- 异步API:类似jquery中的**$.ajax(options)**函数,需要通过success、fail、complete接收调用的结果,如:wx.request() 发起网络数据请求,通过success回调函数接收数据
2. 小程序-模板与配置
2.1 使用WXML模板语法渲染页面结构
2.1.1 数据绑定
-
数据绑定的基本原则
- 在data中定义数据
- 在WXML中使用数据
-
在data中定义页面的数据:在页面对应的js文件中,把数据定义到data对象中即可
Page({ data: { info:'hello world' }, })
-
Mustache语法的格式:把data中的数据绑定到页面中渲染,使用Mustache语法(双大括号)将变量包起来即可
<view>{{info}}</view>
-
Mustache语法的应用场景:绑定内容、绑定属性、运算
-
动态绑定内容:
<view>{{info}}</view>
-
动态绑定属性:
Page({ data: { imgSrc:'http://www.itheima.com/images/logo.png' }, }) <image src="{{imgSrc}}"></image>
-
三元运算:
<view hidden="{{flag ? true : false}}"> Hidden </view>
-
算数运算:
randomNum:Math.random().toFixed(2)
2.1.2 事件绑定
- 常用事件
类型 | 绑定方式 | 事件描述 |
---|---|---|
tap | bindtap或bind:tap | 手指触摸后马上离开,类似于HTML中的click时间 |
input | bindinput或bind:input | 文本框的输入事件 |
change | bindchange或bind:change | 状态改变时触发 |
-
事件对象的属性列表
其中,target是触发该事件的源头组件,而currentTarget则是当前事件所绑定的组件
-
bindtap的语法格式
<input bindinput="handleInput" /> <!-- wxml --> Page({ // js // 绑定的事件 handleInput: function(e) { console.log(e); console.log("值被改变了"); } })
-
在事件处理函数中为data中的数据赋值
通过调用
this.setData(dataObject)
方法,可以给页面data中的数据重新赋值,实例如下Page({ data: { count:0 }, // 修改count的值 changeCount(){ this.setData({ count:this.data.count+1 }) }, })
-
事件传参
不能在绑定事件的同时为事件处理函数传递参数,可以通过为组件提供
data-*
自定义属性传参,其中的*
代表的是参数的名字,在事件处理函数中,可以通过even.target.dataset.参数名即可获取到具体参数的值,实例代码如下:<!-- wxml --> <button type="primary" data-currentCount="{{2}}" bindtap="btnTap2">+2</button> <!-- js --> btnTap2(e){ this.setData({ count:this.data.count+e.target.dataset.current }) }
注意:data-后面的参数不能写驼峰
-
bindinput的语法格式
inputHandler(e){ console.log(e.detail.value); }, <input type="text" bindinput="inputHandler"/>
-
实现文本框和data之间的数据同步:定义数据,渲染结构,美化样式,绑定input事件处理函数
<!-- js --> Page({ data:{ msg:'你好' }, inputHandler(e){ // console.log(e.detail.value); this.setData({ msg:e.detail.value }) } }) <!-- wxml --> <input type="text" bindinput="inputHandler" value="{{msg}}" /> <!-- wxss --> input{ border: 1px solid #eee; margin: 5px; padding: 5px; border-radius: 3px; }
2.1.3 条件渲染
-
wx:if
在框架中,使⽤wx:if="{{condition}}"来判断是否需要渲染该代码块
<view wx:if="{{type===1}}">男</view> <view wx:elif="{{type===2}}">女</view> <view wx:else>保密</view>
-
结合
<block>
使用wx:if<block>
:实现一次性控制多个组件的展示和隐藏,并在block标签上使用wx:if来控制属性,另外,block并不是一个组件,只是一个包裹性质的容器,不会在页面中做任何渲染<block wx:if="{{true}}"> <view>view1</view> <view>view2</view> </block> <!-- 以动态创建和移除元素的样式,控制元素的展示与隐藏,控制条件复杂时使用 -->
-
hidden:直接使用hidden="{{condition}}"也可以实现元素的显示与隐藏
<view hidden="{{flag}}">条件为true,隐藏元素,否则隐藏</view> <!-- 以切换样式的方式,来控制元素的显示与隐藏,频繁切换时使用 -->
2.1.4 列表渲染
-
wx:for 可以根据指定的数组,循环渲染重复的组件结构
wx:for-item可以指定数组当前元素的变量名,wx:for-index可以指定数组当前下标的变量名
<view wx:for="{{arr}}" wx:key="*this"> 索引是:{{index}},item项是:{{item}} </view> <view wx:for="{{arr}}" wx:for-index="idx" wx:for-item="itemName" wx:key="*this"> 索引是:{{idx}},item项是:{{itemName}} </view> <!-- 默认情况下,当前循环项的索引用index表示,当前循环用item表示 -->
-
wx:key ⽤来提⾼数组渲染的性能
<view wx:for="{{userList}}" wx:key="id">{{item.name}}</view> data:{ userList:[ {id:1,name:'小红'}, {id:2,name:'小白'}, {id:3,name:'小化'}, ] } // wx:key的值还可取:保留字*this,它的意思是item本⾝,*this代表的必须是唯⼀的字符串和数组
2.2 使用WXSS样式美化页面结构
与CSS相比,WXSS扩展的特性:rpx尺寸单位,@import样式导入
2.2.1 rpx
rpx(responsive pixel):可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx
建议:开发微信小程序时设计师可以⽤iPhone6作为视觉稿的标准。
使用步骤:
- 确定设计稿宽度pageWidth
- 计算比例750rpx = pageWidth px,因此1px=750rpx/pageWidth。
- 在less⽂件中,只要把设计稿中的px=>750/pageWidth rpx即可
2.2.2 样式导入
语法格式:@import后跟需要导入的外联样式表的相对路径,用==;==表示语句结束,如
@import '/common/common.wxss';
2.2.3 全局样式和局部样式
-
全局样式:定义在app.wxss中的样式为全局样式,作用于每一个页面
-
在页面的.wxss文件中定义的样式为局部样式,只作用于当前页面
-
当局部样式和全局样式冲突时,根据就近原则,局部样式会覆盖全局样式
-
当局部样式的权重大于或等于全局样式的权重时,才会覆盖全局样式
2.3 使用app.json对小程序进行全局配置
2.3.1 全局配置文件及常用的配置项
2.3.2 window节点常用的配置项
2.3.3 tabBar
-
tabBar是移动端应用常见的页面效果,用于实现页面的快速切换,小程序中通常将其分为:底部tabBar,顶部tabBar
-
注意:tabBar中只能配置最后2个,最多5个tab页签,当渲染顶部tabBar时,不显示icon,只显示文本
-
tabBar的6个组成部分
- backgroundColor:tabBar的背景色
- selectedIconPath:选中时的图片路径
- selectedColor:tabBar上的文字选中时的颜色
- borderStyle:tabBar上边框的颜色
- iconPath:未选中时的图片路径
- color:tabBar上文字的默认(未选中)颜色
-
tabBar节点的配置项
-
每个tabBar项的配置选项
2.4 使用page.json对小程序页面进行个性化配置
- 当页面配置与全局配置冲突时,根据就近原则,最终的效果以页面配置为准
- 页面配置中常用的配置项与全局一样
2.5 发起网络数据请求
2.5.1 GET和POST请求
-
小程序中网络数据请求的限制
- 只能请求HTTPS类型的接口
- 必须将接口的域名添加到信任列表中
-
配置request的合法域名
登录到微信小程序的管理后台->开发->开发设置->服务器域名->修改request合法域名
-
发起GET请求
调用微信小程序提供的wx.request()方法,可以发起GET数据请求
getInfo(){ wx.request({ url: 'https://www.escook.cn/api/get', method:'GET', data:{ name:'zs', age:20 }, success:(res)=>{ console.log(res.data); } }) },
-
发起POST请求
调用微信小程序提供的wx.request()方法,可以发起POST数据请求
postInfo(){ wx.request({ url: 'https://www.escook.cn/api/post', method:"POST", data:{ name:'ls', age:33 }, success:(res)=>{ console.log(res.data); } }) },
-
在页面加载时请求数据
onLoad: function (options) { this.getInfo() this.postInfo() }
-
跳过request合法域名校验(只能在开发与调试阶段使用)
3. 小程序-视图与逻辑
3.1 页面导航
3.1.1 声明式导航
-
小程序中实现页面导航的两种方式
- 声明式导航:在页面上声明一个
<navigator>
导航组件;通过点击<navigator>
组件实现页面跳转 - 编程式导航:调用小程序的导航 API,实现页面的跳转
- 声明式导航:在页面上声明一个
-
导航到 tabBar 页面:在使用
<navigator>
组件跳转到指定的 tabBar 页面时,需要指定 url 属性和 open-type 属性,其中:- url 表示要跳转的页面的地址,必须以
/
开头 - open-type 表示跳转的方式,必须为
switchTab
- url 表示要跳转的页面的地址,必须以
-
导航到非tabBar页面:在使用
<navigator>
组件跳转到普通的非 tabBar 页面时,则需要指定 url 属性和 open-type 属性,其中:- url 表示要跳转的页面的地址,必须以
/
开头 - open-type 表示跳转的方式,必须为
navigate
- 在导航到非 tabBar 页面时,open-type=“navigate” 属性可以省略
- url 表示要跳转的页面的地址,必须以
-
后退导航:如果要后退到上一页面或多级页面,则需要指定 open-type 属性和 delta 属性,其中:
- open-type 的值必须是 navigateBack,表示要进行后退导航
- delta 的值必须是数字,表示要后退的层级
- 如果只是后退到上一页面,则可以省略 delta 属性,因为其默认值就是 1
<navigator url="/pages/message/message" open-type="switchTab">导航到消息页面</navigator>
<navigator url="/pages/index/index" open-type="navigate">导航到index页面</navigator>
<navigator open-type="navigateBack" delta="1">后退一个页面</navigator>
3.1.2 编程式导航
-
导航到 tabBar 页面:调用 wx.switchTab(Object object) 方法。参数的属性如下:
属性 类型 是否必选 说明 url string 是 需要跳转的 tabBar 页面的路径,路径后不能带参数 success function 否 接口调用成功的回调函数 fail function 否 接口调用失败的回调函数 complete function 否 接口调用结束的回调函数(调用成功、失败都会执行) -
导航到非tabBar页面:调用 wx.navigateTo(Object object) 方法,参数的属性如下:
属性 类型 是否必选 说明 url string 是 需要跳转到的非 tabBar 页面的路径,路径后可以带参数 success function 否 接口调用成功的回调函数 fail function 否 接口调用失败的回调函数 complete function 否 接口调用结束的回调函数(调用成功、失败都会执行) -
后退导航:调用 wx.navigateBack(Object object) 方法,可以返回上一页面或多级页面,参数的属性如下:
属性 类型 默认值 是否必选 说明 delta number 1 否 返回的页面数,如果 delta 大于现有页面数,则返回到首页 success function 否 接口调用成功的回调函数 fail function 否 接口调用失败的回调函数 complete function 否 接口调用结束的回调函数(调用成功、失败都会执行)
<button bindtap="gotoMessage">跳转到message页面</button>
<button bindtap="gotoIndex">跳转到index页面</button>
<button bindtap="gotoBack">后退一个页面</button>
// 通过编程式导航跳转到tabBar页面
gotoMessage(){
wx.switchTab({
url: '/pages/message/message',
})
}
// 通过编程式导航跳转到非tabBar页面
gotoIndex(){
wx.navigateTo({
url: '/pages/index/index',
})
}
// 后退一个页面
gotoBack(){
wx.navigateBack()
},
3.1.3 导航传参
-
声明式导航传参:在路径的后面还可以携带参数:参数与路径之间使用
?
分隔;参数键与参数值用=
相连;不同参数用&
分隔<navigator url="/pages/index/index?name=zs&age=20">跳转到index页面</navigator>
-
编程式导航传参:调用 wx.navigateTo(Object object) 方法跳转页面时,也可以携带参数
<button bindtap="gotoIndex2">跳转到index页面</button> gotoIndex2(){ wx.navigateTo({ url: '/pages/index/index?name=zs&age=20', }) },
-
在onLoad中接收导航参数(声明式或编程式都一样接收,并且是在跳转页面对应的onLoad中接收)
onLoad: function (options) { console.log(options); },
3.2 页面事件
3.2.1 下拉刷新
-
启用下拉刷新有两种方式:
- 全局开启下拉刷新:在 app.json 的 window 节点中,将 enablePullDownRefresh 设置为 true
- 局部开启下拉刷新:在页面的 .json 配置文件中,将 enablePullDownRefresh 设置为 true(推荐使用)
-
在全局或页面的 .json 配置文件中,通过 backgroundColor 和 backgroundTextStyle 来配置下拉刷新窗口的样式,其中:
- backgroundColor 用来配置下拉刷新窗口的背景颜色,仅支持16 进制的颜色值
- backgroundTextStyle 用来配置下拉刷新 loading 的样式,仅支持 dark 和 light
-
监听页面的下拉刷新事件:在页面的 .js 文件中,通过 onPullDownRefresh() 函数即可监听当前页面的下拉刷新事件
<button bindtap="addCount">点击+1</button> addCount(){ this.setData({ count:this.data.count+1 }) } onPullDownRefresh: function () { // console.log("触发了Message下拉刷新事件"); this.setData({ count:0 }) },
-
停止下拉刷新:调用 wx.stopPullDownRefresh() 可以停止当前页面的下拉刷新
/** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh: function () { // console.log("触发了Message下拉刷新事件"); this.setData({ count:0 }) // 当数据重置成功后,调用此函数,关闭下拉刷新的效果 wx.stopPullDownRefresh() },
3.2.2 上拉触底事件
是指通过手指在屏幕上的上拉滑动操作,从而加载更多数据的行为。
-
监听页面的上拉触底事件:在页面的 .js 文件中,通过 onReachBottom() 函数即可监听当前页面的上拉触底事件
/** * 页面上拉触底事件的处理函数 */ onReachBottom: function () { console.log("上拉触底事件触发了"); },
-
配置上拉触底距离(触发上拉触底事件时,滚动条距离页面底部的距离):可以在全局或页面的 .json 配置文件中,通过 onReachBottomDistance 属性来配置上拉触底的距离(默认50px)
3.2.3 自定义编译模式
3.3 生命周期
3.3.1 生命周期与声明周期函数
-
生命周期(Life Cycle)是指一个对象从创建 -> 运行 -> 销毁的整个阶段,强调的是一个时间段
-
生命周期的分类:
- 应用生命周期:特指小程序从启动 -> 运行 -> 销毁的过程
- 页面生命周期:特指小程序中,每个页面的加载 -> 渲染 -> 销毁的过程
-
生命周期函数:是由小程序框架提供的内置函数,会伴随着生命周期,自动按次序执行,允许程序员在特定的时间点,执行某些特定的操作
注意:生命周期强调的是时间段,生命周期函数强调的是时间点
-
生命周期函数的分类:
- 应用的生命周期函数:特指小程序从启动 -> 运行 -> 销毁期间依次调用的那些函数
- 页面的生命周期函数:特指小程序中,每个页面从加载 -> 渲染 -> 销毁期间依次调用的那些函数
-
应用生命周期函数:小程序的应用生命周期函数需要在 app.js 中进行声明
App({ // 当小程序初始化完成时,会触发 onLaunch(全局只触发一次) onLaunch: function () {}, // 当小程序启动,或从后台进入前台显示,会触发 onShow onShow: function (options) {}, // 当小程序从前台进入后台,会触发 onHide onHide: function () {}, // 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息 onError: function (msg) {} })
-
页面的生命周期函数:小程序的页面生命周期函数需要在页面的 .js 文件中进行声明
Page({ onLoad: function (options) {}, // 生命周期函数--监听页面加载,一个页面只调用一次 onReady: function () {}, // 生命周期函数--监听页面初次渲染完成,一个页面只调用一次 onShow: function () {}, // 生命周期函数--监听页面显示 onHide: function () {}, // 生命周期函数--监听页面隐藏 onUnload: function () {}, // 生命周期函数--监听页面卸载,一个页面只调用一次 })
3.4 WXS脚本
WXS(WeiXin Script)是小程序独有的一套脚本语言,结合 WXML,可以构建出页面的结构
3.4.1 WXS与JavaScript的关系
- wxs 有自己的数据类型
- number 数值类型、string 字符串类型、boolean 布尔类型、object 对象类型、
- function 函数类型、array 数组类型、 date 日期类型、 regexp 正则
- wxs 不支持类似于 ES6 及以上的语法形式
- 不支持:let、const、解构赋值、展开运算符、箭头函数、对象属性简写、etc…
- 支持:var 定义变量、普通 function 函数等类似于 ES5 的语法
- wxs 遵循 CommonJS 规范
- module 对象
- require() 函数
- module.exports 对象
3.4.2 基础语法
-
内嵌WXS脚本
wxml 文件中的每个
<wxs></wxs>
标签,必须提供 module 属性,用来指定当前 wxs 的模块名称,方便在 wxml 中访问模块中的成员<view>{{m1.toUpper(username)}}</view> <wxs module="m1"> module.exports.toUpper=function(str){ return str.toUpperCase() } </wxs>
-
定义外联的WXS脚本
wxs 代码还可以编写在以 .wxs 为后缀名的文件内,就像 javascript 代码可以编写在以 .js 为后缀名的文件中一样
function toLower(str){ return str.toLowerCase() } module.exports={ toLower:toLower }
-
使用外联的WXS脚本
在 wxml 中引入外联的 wxs 脚本时,必须为
<wxs>
标签添加 module 和 src 属性,其中:module 用来指定模块的名称,src 用来指定要引入的脚本的路径,且必须是相对路径<view>{{m2.toLower(country)}}</view> <wxs src="../../utils/tools.wxs" module="m2"></wxs>
4. 小程序-基础加强
4.1 自定义组件
4.1.1 组件的创建与引用
-
创建组件
- 在项目的根目录中,鼠标右键,创建 components -> test 文件夹
- 在新建的 components -> test 文件夹上,鼠标右键,点击“新建 Component”
- 键入组件的名称之后回车,会自动生成组件对应的 4 个文件,后缀名分别为 .js,.json, .wxml 和 .wxss
- 建议把不同的组件,存放到单独目录中
-
局部引用组件:在页面的 .json 配置文件中引用组件的方式
// 在页面的.json文件中,引入组件 { "usingComponents": { "my-test1":"/components/test/test" } } // 在页面的.wxml中引入组件 <my-test1></my-test1>
-
全局引用组件:在 app.json 全局配置文件中引用组件的方式
// 在app.json文件中,引入组件 { "pages":[....], "window":{....}, "usingComponents": { "my-test2":"/components/test/test" }, } // 在页面的.wxml中引入组件 <my-test2></my-test2>
-
组件和页面的区别
- 组件的 .json 文件中需要声明 “component”: true 属性
- 组件的 .js 文件中调用的是 Component() 函数
- 组件的事件处理函数需要定义到 methods 节点中
4.1.2 样式
-
组件样式隔离:默认情况下,自定义组件的样式只对当前组件生效,不会影响到组件之外的 UI 结构
-
组件样式隔离的注意点:
- app.wxss 中的全局样式对组件无效
- 只有 class 选择器会有样式隔离效果,id 选择器、属性选择器、标签选择器不受样式隔离的影响
-
修改组件的样式隔离选项:可以通过 styleIsolation 修改组件的样式隔离选项
// 在组件的.js中新增如下配置 Component({ options:{ styleIsolation:'isolated' } }) // 或在组件的.json中新增如下配置 { "styleIsolation":"isolated" }
建议:在组件和引用组件的页面中建议使用 class 选择器,不要使用 id、属性、标签选择器
4.1.3 数据、方法和属性
-
data数据:在小程序组件中,用于组件模板渲染的私有数据,需要定义到 data 节点中,data 更倾向于存储组件的私有数据
-
methods 方法:在小程序组件中,事件处理函数和自定义方法需要定义到 methods 节点中
-
properties属性:在小程序组件中,properties 是组件的对外属性,用来接收外界传递到组件中的数据,properties 更倾向于存储外界传递到组件中的数据
Component({ properties: { // 组件的属性列表 /* max:{ // 完整定义属性的方式 type:Number, // 属性值的数据类型 value:10 // 属性默认值 }, */ max:Number // 简化方式,不指定默认值 }, data: { // 组件的初始数据 count:0 }, methods: { // 组件的方法列表(包含事件处理函数和自定义方法) addCount(){ // 事件处理函数 if(this.data.count>=this.properties.max) return this.setData({ count:this.data.count+1, // max:this.properties.max+1 // 使用setData修改properties值 }) this._showCount() // 通过this调用自定义方法 }, _showCount(){ // 自定义方法建议以 _ 开头 wx.showToast({ title: 'count的值为: '+this.data.count, icon:'none' }) } } }) <my-test1 max="10"></my-test1>
4.1.4 数据监听器
-
数据监听器用于监听和响应任何属性和数据字段的变化,从而执行特定的操作。它的作用类似于 vue 中的 watch 侦听器
-
数据监听器的基本用法:
<view>{{n1}}+{{n2}}={{sum}}</view> <button bindtap="addN1">n1+1</button> <button bindtap="addN2">n2+1</button> Component({ data:{n1:0,n2:0,sum:0}, methods:{ addN1(){ this.setData({ n1:this.data.n1+1 }) }, addN2(){ this.setData({ n2:this.data.n2+1 }) } }, observers:{ 'n1,n2':function(newN1,newN2){ this.setData({ sum:newN1+newN2 }) } } })
-
监听对象属性的变化
-
数据监听器案例
<view style="background-color: rgb({{fullColor}});" class="color-box">颜色值:{{fullColor}}</view> <button size="mini" type="default" bindtap="changeR">R</button> <button size="mini" type="primary" bindtap="changeG">G</button> <button size="mini" type="warn" bindtap="changeB">B</button> Component({ options:{ pureDataPattern:/^_/ // 指定所有的_开头的为纯数据字段 }, data: { rgb:{ // _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(newR,newG,newB){ // 'rgb.**':function(obj){ this.setData({ fullColor:`${newR},${newG},${newB}` // :`${obj.r},${obj.g},${obj.b}` }) } } })
-
监听对象中所有属性的变化:使用通配符
**
来监听,如'rgb.**':function(obj){}
4.1.5 纯数据字段
-
纯数据字段指的是那些不用于界面渲染的 data 字段
-
使用规则:在 Component 构造器的 options 节点中,指定 pureDataPattern 为一个正则表达式,字段名符合这个正则表达式的字段将成为纯数据字段
4.1.6 组件的生命周期
-
小程序组件的声明周期:
-
lifetimes 节点:在小程序组件中,生命周期函数可以直接定义在 Component 构造器的第一级参数中,可以在 lifetimes 字段内进行声明(这是推荐的方式,其优先级最高)
4.1.7 组件所在页面的生命周期
- 组件所在页面生命周期函数:
-
pageLifetimes 节点:
4.1.8 插槽
-
在自定义组件的 wxml 结构中,可以提供一个
<slot>
节点(插槽),用于承载组件使用者提供的 wxml 结构 -
单个插槽:在小程序中,默认每个自定义组件中只允许使用一个
<slot>
进行占位 -
启用多个插槽:在组件的 .js 文件定义
-
定义多个插槽:在组件的 .wxml 中使用多个
<slot>
标签,以不同的 name 来区分不同的插槽
4.1.9 父子组件之间的通信
-
父子组件的通信方式
-
属性绑定
-
事件绑定步骤:
-
在父组件的 js 中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件
-
在父组件的 wxml 中,通过自定义事件的形式,将步骤 1 中定义的函数引用,传递给子组件
-
在子组件的 js 中,通过调用
this.triggerEvent('自定义事件名称', { /* 参数对象 */ })
,将数据发送到父组件 -
在父组件的 js 中,通过 e.detail 获取到子组件传递过来的数据
-
-
获取组件实例:可在父组件里调用 this.selectComponent(“id或class选择器”) ,获取子组件的实例对象,从而直接访问子组件的任意数据和方法。调用时需要传入一个选择器,如 this.selectComponent(".my-component")
4.1.10 behaviors
-
是在小程序中,用于实现组件间代码共享的特性,类似于 Vue.js 中的 “mixins”
-
behaviors 的工作方式:每个 behavior 可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中。每个组件可以引用多个 behavior,behavior 也可以引用其它 behavior
-
创建:调用 Behavior(Object object) 方法即可创建一个共享的 behavior 实例对象,供所有的组件使用
-
导入并使用:在组件中,使用 require() 方法导入需要的 behavior,挂载后即可访问 behavior 中的数据或方法
-
behavior可用节点
-
同名字段处理规则:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html
4.2 使用npm包
4.2.1 Vant Weapp
-
官方文档地址 https://youzan.github.io/vant-weapp
-
安装 :https://youzan.github.io/vant-weapp/#/quickstart#an-zhuang
- 通过 npm 安装(建议指定版本为@1.3.3)
- 构建 npm 包
- 修改 app.json
-
使用:安装完 Vant 组件库之后,可以在 app.json 的 usingComponents 节点中引入需要的组件,即可在 wxml 中直接使用组件
-
定义全局主体样式:https://developer.mozilla.org/zh-CN/docs/Web/CSS/Using_CSS_custom_properties
在 app.wxss 中,写入 CSS 变量,即可对全局生效,所有可用的颜色变量
4.2.2 API Promise化
-
默认情况下,小程序官方提供的异步 API 都是基于回调函数实现的
-
实现:在小程序中,实现 API Promise 化主要依赖于
miniprogram-api-promise
这个第三方的 npm 包注意,微信小程序每次安装第三方包之后必须需要构建npm,建议先将miniprogram_npm先删除再构建
-
调用
4.3 全局数据共享
-
全局数据共享(又叫做:状态管理)是为了解决组件之间数据共享的问题,如Vuex,Redux,MobX 等
-
在小程序中,可使用 mobx-miniprogram 配合 mobx-miniprogram-bindings 实现全局数据共享。其中:
- mobx-miniprogram 用来创建 Store 实例对象
- mobx-miniprogram-bindings 用来把 Store 中的共享数据或方法,绑定到组件或页面中使用
4.3.1 MobX
-
安装包:
npm i --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1
注意:MobX 相关的包安装完毕之后,记得删除 miniprogram_npm 目录后,重新构建 npm
-
创建 MobX 的 Store 实例 store.js
-
将 Store 中的成员绑定到页面中
-
在页面上使用 Store 中的成员
-
将 Store 中的成员绑定到组件中
-
在组件中使用 Store 中的成员
4.4 分包
4.4.1 概念
-
分包指的是把一个完整的小程序项目,按照需求划分为不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载
-
分包后,小程序项目由 1 个主包 + 多个分包组成:
- 主包:一般只包含项目的启动页面或 TabBar 页面、以及所有分包都需要用到的一些公共资源
- 分包:只包含和当前分包有关的页面和私有资源
-
加载规则
- 在小程序启动时,默认会下载主包并启动主包内页面:tabBar 页面需要放到主包中
- 当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示:非 tabBar 页面可以按照功能的不同,划分为不同的分包之后,进行按需下载
-
体积限制
- 整个小程序所有分包大小不超过 16M(主包 + 所有分包)
- 单个分包/主包大小不能超过 2M
4.4.2 分包的基本用法
-
配置方法
-
打包规则
- 小程序会按 subpackages 的配置进行分包,subpackages 之外的目录将被打包到主包中
- 主包也可以有自己的 pages(即最外层的 pages 字段)
- tabBar 页面必须在主包内
- 分包之间不能互相嵌套
-
引用规则
- 主包无法引用分包内的私有资源
- 分包之间不能相互引用私有资源
- 分包可以引用主包内的公共资源
4.4.3 独立分包
-
独立分包本质上也是分包,只不过它比较特殊,可以独立于主包和其他分包而单独运行
-
独立分包与普通分包的区别:
- 普通分包必须依赖于主包才能运行
- 独立分包可以在不下载主包的情况下,独立运行
-
应用场景
-
当小程序从普通的分包页面启动时,需要首先下载主包
-
而独立分包不依赖主包即可运行,可以很大程度上提升分包页面的启动速度
注意:一个小程序中可以有多个独立分包
-
-
配置方法
-
引用规则
- 主包无法引用独立分包内的私有资源
- 独立分包之间,不能相互引用私有资源
- 独立分包和普通分包之间,不能相互引用私有资源
- 特别注意:独立分包中不能引用主包内的公共资源
4.4.4 分包预下载
-
是指在进入小程序的某个页面时,由框架自动预下载可能需要的分包,从而提升进入后续分包页面时的启动速度。
-
配置:会在进入指定的页面时触发,在 app.json 中,使用 preloadRule 节点定义分包的预下载规则
-
限制:同一个分包中的页面享有共同的预下载大小限额 2M
4.5 自定义tabBar
官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html
-
首先在app.json中设置如下:
-
在根目录新建store/store.js文件
// 在这个js文件中,专门创建Store的实例对象 import {observable,action} from 'mobx-miniprogram' export const store=observable({ // 数据字段 numA:1, numB:2, activeTabBarIndex: 0, // 计算属性 get sum(){ return this.numA+this.numB }, // actions方法,用来修改store中的数据 updateActiveTabBarIndex:action(function(index){ this.activeTabBarIndex=index }) })
-
在根目录新建custom-tab-bar文件夹,在里面新建index组件,名字固定
// custom-tab-bar/index.js import {storeBindingsBehavior} from 'mobx-miniprogram-bindings' import {store} from '../store/store' Component({ options:{ styleIsolation:'shared' }, behaviors:[storeBindingsBehavior], storeBindings:{ // 数据源 store, fields:{ sum:'sum', active:'activeTabBarIndex' }, actions:{ updateActive:'updateActiveTabBarIndex' } }, observers:{ 'sum':function(val){ this.setData({ 'list[1].info':val }) } }, data: { // 组件的初始数据 "list": [ { "pagePath": "/pages/home/home", "text": "首页", "iconPath": "/images/tabs/home.png", "selectedIconPath": "/images/tabs/home-active.png" }, { "pagePath": "/pages/message/message", "text": "消息", "iconPath": "/images/tabs/message.png", "selectedIconPath": "/images/tabs/message-active.png", "info":2 }, { "pagePath": "/pages/contact/contact", "text": "联系我们", "selectedIconPath": "/images/tabs/contact-active.png", "iconPath": "/images/tabs/contact.png" } ], }, methods: { // 组件的方法列表 onChange(event) { // event.detail 的值为当前选中项的索引 // this.setData({ active: event.detail }); this.updateActive(event.detail) wx.switchTab({ url: this.data.list[event.detail].pagePath, }) }, } }) <!--custom-tab-bar/index.wxml--> <van-tabbar active="{{active}}" bind:change="onChange" active-color="#13A7A0"> <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> /* custom-tab-bar/index.wxss */ .van-tabbar-item{ --tabbar-item-margin-bottom:0 }
-
实现效果