web前端-微信小程序开发学习
1. 小程序的概述
微信小程序和普通网页开发的区别:

关于微信公众号平台如何注册小程序的账号, 如何获取小程序的appid, 如何下载小程序的开发工具, 这里我不做过多叙述。 大家自行百度安装开发环境。
2. 小程序的项目结构
2.1 小程序项目结构分析
创建一个小程序项目:

项目的基本组成:

pages:用来存放所有小程序的页面untils: 用来存放工具性质的模块(例如:格式化时间的自定义模块)app.js:小程序项目的入口文件app.json:小程序项目的全局配置文件app.wxss:小程序的全局样式文件project.config.json: 项目的配置文件sitemap.json: 用来配置小程序及其页面是否允许被微信索引
小程序官方建议把所有的小程序的页面,都存放在pages目录下,以及单独的文件夹存在,如图所示:

由上图可知每个页面都包含4个文件,它们分别是:
.js文件:页面的脚本文件,存放页面的数据、事件处理函数等.json文件:当前页面的配置文件, 配置窗口的外观、表现等.wxml文件:页面的模版结构文件.wxss文件:当前页面的样式文件
JSON配置文件的作用:JSON是一种数据格式,在实际开发中,JSON总是以配置文件的形式出现。小程序项目也不例外:通过不同的.json配置文件,可以对小程序项目进行不同的级别设置。
小程序中有4种json配置文件,分别是:
- 项目根目录中的
app.json配置文件 - 项目根目录中的
project.config.json配置文件 - 项目根目录中的
sitemap.json配置文件 - 每个页面文件夹中的
.json配置文件
app.json是当前小程序的
全局配置,包括了小程序的所有页面路劲、窗口外观、界面表现、底部tab等

pages: 用来记录当前小程序所有页面的路径windown: 全局定义小程序所有页面的背景色、文字颜色等style:全局定义小程序组件所使用的样式版本sitemapLocation: 用来指明sitemap.json文件的位置
project.config.json是项目配置文件,用来记录我们
对小程序开发工具所做的个性化配置,例如:
setting中保存了编译相关的配置
projectname中保存的是项目名称
appID中保存的是小程序账号ID
sitemap.json: 微信已经开发
小程序内搜索,效果类似于PC网页的SEO。sitemap.json文件用来配置小程序页面是否允许微信索引。
当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索关键字和页面的索引匹配成功的时候,小程序的页面将可能展示在搜索结果中。

注意:sitemap的索引提示是默认开启的,如果需要关闭sitemap的索引提示,可在小程序项目配置文件中project.config.json的setting中配置字段checkSiteMap为false
页面的.json配置文件:小程序中的每一个页面,可以使用.json文件来
对本页面的窗口外观进行配置,页面中的配置会覆盖app.json中的widnow中相同的配置项,例如:

- 新建小程序页面: 只需要在
app.json->pages中新增页面的存放路径, 小程序开发者工具即可帮助我们自动创建对应的页面文件。

- 修改项目首页:只需要调整
app.json->pages数组中页面路劲的前后顺序,即可修改项目的首页。小程序会把排在第一位的页面,当做项目首页进行渲染。
2.2 WXML模版
- WXML和HTML的区别 :

- WXSS和CSS的区别:

- 小程序中JS文件分为三类,分别是:
- app.js : 是
整个小程序项目的入口文件,通过调用APP()函数来启动整个小程序 - 页面的.js文件: 是
页面的入口文件,通过调用Page()函数来创建并运行页面 - 普通的.js文件:是
普通的功能模块文件, 用来封装公共的函数或属性供页面适用
- app.js : 是
2.3 小程序的宿主环境
宿主环境(host environment)指的是程序运行所必须的依赖环境,例如:Android系统和IOS系统是两个不同的宿主环境。安卓版的微信App是不能再IOS环境下运行的,所以Android是安卓软件的宿主环境,脱离了宿主环境的软件是没有任何意义的!

手机微信是小程序的宿主环境:小程序借助宿主环境提供的能力,可以完成许多普通网页无法完成的功能, 例如:微信支付、微信扫码等等

小程序的宿主环境包含的内容: 通信模型、运行机制、组件、API。
通信的主体是渲染层和逻辑层,其中WXML模版和WXSS样式工作在渲染层,JS脚本工作在逻辑层
小程序中的通信模型分为两部分:渲染层和逻辑层之间的通信,是由微信客户端进行转发; 逻辑层和第三方服务器之间的通信,也是由微信客户端进行转发

- 小程序的启动过程:
- 把小程序的代码包下载到本地
- 解析app.json全局配置文件
- 执行app.js小程序入口文件,
调用App()创建小程序实例 - 渲染小程序首页
- 小程序启动完成
- 渲染页面的过程:
- 加载解析页面的.json配置文件
- 加载页面.wxml模版和.wxss样式
- 执行页面的.js文件,
调用Page()创建页面实例 - 页面渲染完成
3. 组件
小程序中的组件也是由宿主环境提供的,开发者可以基于组件快速搭建出漂亮的页面结构。官方把小程序的组件分为9大类,分别是 :视图容器、基础内容、表单组件、导航组件、媒体组件、map地图组件、canvas圈布组件、开放能力、无障碍访问。
3.1 视图容器类组件
view: 普通视图区域、类似于HTML中的div,是一个块级元素、常用来实现页面的布局效果

scroll-view: 可滚动的视图区域,常用来实现滚动列表效果

swiper和swiper-item:轮播图容器组件和轮播图item组件

关于swiper组件的常用属性:

3.2 常用的基础内容组件
text:文本组件,类似HTML中的span标签,是一个行内元素rich-text: 富文本组件,支持HTML字符串渲染为WXML结构

3.3 其它组件
button: 按钮组件,功能比HTML中的button按钮丰富, 通过open-type属性可以调用微信提供的各种功能(客服、转发、获取用户授权、获取用户信息等等)

image: 图片组件, image组件默认宽度约 300px、高度约240px 例如:<image src="图片路径" mode="图片填充模式"/>, image组件的mode属性用来指定图片的裁剪和缩放模式,常用的mode属性值如下:

navigator:页面导航组件,类似于HTML中的a连接(后面会专门介绍到)
小程序官方把API分为了如下3大类:
事件监听API: 特点是以on开头,用来监听某些事件的触发同步API:以Sync结尾的API都是同步API,同步API的执行结果,可以通过函数返回直接获取,如果执行出错会抛出异常,例如:wx.setStorageSync(key, value) 向本地存储中写入内容
*异步API: 类似于jQuery中的$.ajax(options)函数,需要通过回调函数接受调用的结果。
4. 小程序模版与配置
4.1 数据绑定
在页面对应的.js文件中,把数据定义到data对象中即可:

我们如何把data中的数据渲染到页面上了?
我们通过Mustache语法 :{{xxx}}(双大括号)将变量名称抱起来即可。语法格式为:<view>{{motto}}</view>
Mustache语法的主要应用场景如下 :绑定内容、绑定属性、运算(三元运算、算数运算等)
动态绑定内容:

动态绑定属性:

使用Mustache语法进行三元运算:


4.2 事件绑定
事件是渲染层到逻辑层的通信方式。通过这件事情可以将用户在渲染层产生的行为,反馈到逻辑层进行业务的处理

小程序中的常用的事件:

事件对象的相关属性:

target是触发该事件的源头组件,而currentTarget则是当前事件所绑定的组件。

4.2.1 bindtap
bindtap语法格式:在小程序中,不存在HTML中的onclick鼠标点击事件,而是通过tap事件来响应用户的触摸行为。- 通过
bindtap,可以为组件绑定tap触摸事件 - 在页面.js文件中定义对应的事件处理函数,事件的处理函数通过形参
event来接收
- 通过

- 我们如何处理函数中的data中的数据赋值? 通过调用
this。setData(dataObject)方法, 可以给页面data中的数据重新复制。

那么小程序中如何进行事件传参?
小程序中的传参比较特殊,不能在绑定事件的同时为事件处理函数传递参数。例如,下面的代码讲不能正常工作:
<button type="primary" bindtap="btnParamHandle(123)">事件传参</button>
因为小程序会把bindtap的属性值,统一当做事件名称来处理,相当于要调用一个名为btnParamHandle(123)的事件处理函数
我们可以为组件提供data-*自定义属性,其中*代表的是参数的名字,示例代码如下:

注意: info会被解析成参数名字, 数值2会被解析为参数的值。 这里如果数值2没有被mustahce包过,那么值会被解析成字符串

在事件处理函数中,通过event.target.dataset.参数名即可以获取到具体的参数的值
// dataset是一个对象,包含所有通过data-*传递过来的参数项
console.log(event.target.dataset);
// 通过 dataset可以访问到具体的参数的值
console.log(event.target.dataset.info);
4.2.2 bindinput
在小程序中,通过input事件来响应文本框的输入事件,语法格式如下:

实现文本框和data之间的数据同步:
// 输入框的输入事件回调方法
inputHandle(event) {
console.log(event.detail.value);
this.setData({
msg: event.detail.value
})
}
4.3 条件渲染
4.3.1 wx:if 、wx:elif、wx:else
wx:if: 在小程序中,使用wx:if={{condition}}来判断是否需要渲染该代码块, 也可以使用wx:elif和wx:else来添加else判断。 类似于if else语法
<!-- wx:if 语法 -->
<view wx:if="{{type === 1}}">男</view>
<view wx:elif="{{type === 2}}">女</view>
<view wx:else>保密</view>
通过上述语法,我们可以实现元素根据条件来决定是显示还是隐藏
如果要一次性控制多个组件的展示和隐藏,可以使用一个<block></block>标签多个组件包装起来,并在<block>标签上使用wx:if控制属性
<block wx:if="{{true}}">
<view class="view1">view1</view>
<view class="view2">view2</view>
</block>
注意: 并不是一个组件,只是一个包裹性质的容器,不会再页面中做任何渲染。
在小程序中,直接使用hidden={{condition}}也能控制元素的显示和隐藏<view class="hidden" hidden="{{true}}">条件为true隐藏;条件为false显示</view>
- wx:if与hidde的对比:
- wx:if以
动态创建和移除元素的方式,控制元素的展示与隐藏 - hidden以
切换样式的方式(display:none/block)控制元素的显示与隐藏
- wx:if以
- 使用建议:
频繁切换时,建议使用hidden- 控制条件复杂时,建议使用
wx:if搭配wx:elif、wx:else进行展示与隐藏的切换
关于hiddenk可能隐藏失效的问题:

4.3.2 wx:for
通过wx:for可以指定指定的数组,循环渲染重复的组件结构,语法实例如下:

默认情况下,当前循环项的索引用index表示;当前循环项用item表示。
我们也可以手动指定索引和当前项的变量名
- 使用
wx:for-index可以指定当前循环项 的索引的变量名 - 使用
wx:for-item可以指定当前项的变量名
<!-- 指定所以和当前item的名称 -->
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
索引是{{idx}} 当前项是{{itemName}}
</view>
4.3.3 wx:key
类似于Vue列表渲染中的:key,小程序在实现列表渲染时,也建议为渲染出来的列表项指定唯一的key值,从而提高渲染的效率
如果没有指定唯一的key, 编译器报相关警告:


当你循环创建元素时,建议把id设置为wx:key, 如果没有可以考虑把idnex作为wx:key
4.4 模版样式
WXSS(WeiXin Style Sheets)是一套样式语言, 用于美化WXML的组件样式, 类似于网页开发中的CSS。 WXSS具有CSS的大部分特性,同时,WXSS还对CSS进行了扩充以及修改,以适应微信小程序的开发。与CSS相比,WXSS扩展的特性有:rpx尺寸单位、@import样式导入
rpx(responsive pixe):是微信小程序独有的,用来解决屏幕适配的尺寸单位。
rpx的实现原理:rpx的实现原理非常简单:鉴于不同的设备屏幕的大小不同,为了实现屏幕 的自动适配,rpx把所有设备的屏幕,在宽度上等分为750份(即:当前屏幕的总宽度为750rpx)
- 在
较小的设备上,1rpx所代表的宽度较小 - 在
较大的设备上,1rpx所代表的宽度较大
小程序所在不同的设备上运行的时候,会自动把rpx的样式单位换算成对应的像素单位来渲染,从而实现屏幕适配。
rpx与px之间的单位换算: 在iphone6上,屏幕宽度为`375px`,共有`750个物理像素`,等分为`750rpx`则`750rpx = 375px = 750物理像素、1rpx=0.5px=1物理像素`

官方建议:在开发微信小程序时,设计师可以用iphon6作为视觉稿的标准。 开发举例:在iphone6上如果要绘制宽100px、高20px 的盒子 换算成rpx单位,分别为200rpx、40rpx
@import后需要导入的外联样式表的相对路径,用;表示语句的结束:@import common.wxss全局样式:定义在app.wxss中的样式为全局样式,作用于每一个页面。局部样式: 在页面的.wxss文件中定义的样式为局部样式,只作用于当前页面- 注意:
- 当局部样式和全局样式冲突时,根据
就近原则,局部样式会覆盖全局样式 - 当局部样式的
权重大于或等于全局样式的权重时,才会覆盖全局的样式
- 当局部样式和全局样式冲突时,根据
4.5 全局配置
4.5.1 window全局配置
全局配置文件以及常用的配置项, 小程序根据目录下的app.json文件是小程序的全局配置文件,常用配置项如下:
pages: 记录当前小程序所有页面的存放路径window:全局设小程序窗口的外观tabbar:设置小程序底部的tabbar效果style: 是否启用新新版的组件模式
小程序的窗口组成部分:

window节点常用的配置项:

- 设置导航栏的标题:
app.json->widnow->navigationBarTitleText - 设置导航栏的背景色:
app.json->widnow->navigationBarBackgroundColor - 设置导航栏标题的颜色:
app.json->widow->navigationBarTextStyle,这里需要注意的是标题颜色值只有两个black、white - 全局下拉刷新功能开启:
app.json->window->enablePullDownRefresh的值设置为true。注意:在app.json中启用下拉刷新功能,会作用于每个小程序页面
当全局开启下拉刷新的功能之后,默认的窗口背景颜色为白色,如果需要自定义下拉窗口背景色,设置步骤:app.json->widnow->backgroundColor指定为16进制的颜色值

全局开启下拉刷新功能之后,默认窗口的loading样式为白色,如果需要更改loading样式的效果,设置步骤:app.json->windwo->backgroundTextStyle ,该属性只有两个值light、drak
- 设置上拉刷新的触底距离:
app.json->window->onReachBottomDistance设置新的值, 这里默认为50px,如果没有特殊需求,建议使用默认值就可。
4.5.2 tabBar
tabBar是移动端应用常见的页面效果,用于实现多页面的快速切换。小程序中通常将其分为:底部tabBar 、顶部tabBar

- 注意:
- tabBar中只能配置
最少2个、最多5个tab页签 - 当渲染
顶部tabBar时,不显示icon,只显示文本
- tabBar中只能配置
tabBar的6个组成部分:

tabBar结点的配置项:

每一个tab项的配置选项:

// 和window配置同级
"tabBar": {
"list": [{
"pagePath": "pages/event/event",
"text": "事件测试"
},
{
"pagePath": "pages/index/index",
"text": "index"
}]
}
页面配置和全局配置的关系
小程序中,app.json中的window节点,可以全局配置小程序中每个页面的窗口表现。
如果某些小程序页面想要拥有特殊的窗口表现,此时,页面级别的.json配置文件就可以实现这种需求。
注意:当页面配置与全局配置冲突的时,根据就近原则,最终的效果以页面配置为准。

4.5.3 网络数据请求
- 小程序中网络数据请求的限制: 处于安全性的考虑,小程序官方对
数据接口的请求做出了如下两个限制:1.只能请求HTTPS类型的接口; 2. 必须将接口的域名添加到信任列表中

那么如何配置request的合法域名了?
配置步骤: 登录微信小程序管理后台->开发->开发设置->服务器域名->修改request合法域名

- 注意事项:
- 域名只支持https协议
- 域名不能使用IP地址或localhost
- 域名必须经过ICP备案
- 服务器域名一个月内最多可申请5次修改
我们在微信小程序中发送请求是直接调用微信小程序提供的wx.request()方法,可以发送GET或POST请求


如果后端程序员仅仅提供了http协议的接口、暂时没有提供https协议的接口。
此时为了不耽误开发的进度,我们可以在微信开发者工作中,临时开启开发环境不校验请求签名、TLS版本及HTTPS证书选项,跳过request合法域名的校验。
注意:跳过request合法域名校验的选项,仅限在开发与调试阶段使用

关于跨域和Ajax的说明:跨域问题只存在于基于浏览器的web开发中,由于小程序的宿主环境不是浏览器,而是微信客户端,所以小程序中不存在跨域的问题。Ajax技术的核心领域是依赖于浏览器中的XMLHttpRequest这个对象,由于小程序的宿主环境是微信客户端,所以小程序中不能叫做发起Ajax请求,而是叫做发起网络请求
5. 页面导航、事件、生命周期函数
5.1 页面导航
页面导航:指的是页面之间的相互跳转。例如:浏览器中实现页面导航的方式有两种: `连接、location.href
小程序中实现页面导航的两种方式:
- 声明式导航:在页面上声明一个
<navigator>导航组件,通过点击<navagitor>实现组件的页面跳转 - 编程式导航:调用小程序的导航API,实现页面的跳转
5.1.1声明式导航
- 导航到tabBar页面:
tabBar页面指的是被配置为tabBar的页面。在使用<navigator>组件跳转到指定的tabBar页面时,需要指定url属性和open-type属性,其中:- url 表示要跳转的
页面的地址, 地址以/开头 - open-type 表示
跳转的方式,必须为switchtab
- url 表示要跳转的
<navigator url="/pages/message/message" open-type="switchTab">跳转到tabbar页面-message页面</navigator>
- 导航到非tabBar页面: 指的是跳转到没有被配置为tabBar的页面。 在使用
<navigator>组件跳转到普通的非tabBar页面时,则需要指定url属性和open-type属性- url 表示要跳转的
页面的地址,必须以/开头 - open-type表示
跳转的方式,必须为navigator
- url 表示要跳转的
<navigator url="/pages/index/index" open-type="navigate">跳转到非tabBar页面-index页面</navigator>
注意:为了简便,在导航到非tabBar页面时,open-type="navigate"属性可以省略
- 如果需要后退上一页或多级页面,则需要指定open-type属性和delta属性, 其中:
open-type的值必须是navigatoeBack,表示要进行后退导航delta的值必须是数字,表示要后退的层级
<navigator open-type="navigateBack" delta="1">返回上一页</navigator>
注意:为了简便,如果只是后退到上一页,则可以省略delta属性,因为其默认值就是1
5.1.2 编程时导航
通过调用wx.switchTab(Object object)方法,可以跳转到tabBar页面。其中Object参数对象的属性列表如下:

- 导航tabBar页面:
// 跳转你到消息界面
gotoMessage() {
wx.switchTab({
url: '/pages/message/message',//需要跳转的URL
})
}
通过调用wx.navigateTo(Object object)方法,可以跳转到非tabBar的页面。其中Object 参数对象的属性列表:

- 导航到非tabBar页面
// 跳转到非tabBar页面 test页面
gotoTest() {
wx.navigateTo({
url: '/pages/test/test',
})
}
通过调用wx.navigaetBack(Object object)方法, 可以返回上一页面或多级页面。其中Object参数对象可选的属性列表如下:

- 后退导航
// 返回上一级
gotoBack() {
// 编程时导航
wx.navigateBack()
}
5.1.3 声明式导航和编程时导航传参
navigator组件的url属性用来指定讲要跳转到的页面的路径。同时,路径后面还可以携带参数:参数与路径之间使用?分割参数健与参数值用=相连不同参数用&分割
<navigator url="/pages/test/test?name=zs&gender=男" open-type="navigate">声明式导航传参</navigator>
- 通过调用
wx.navigateTo(Object object)方法跳转页面时,也可以携带参数,示例代码如下:
// 跳转到测试页面 并携带参数
gotoTest2() {
wx.navigateTo({
url: '/pages/test/test?name=zs&gender=男',
})
}
通过声明式导航传参或编程式导航传参所携带的参数,可以直接在onLoad事件中直接获取到,示例代码如下:

5.2 页面事件
启用下拉刷新有两种方式:
- 全局开启下拉刷新: app.json的window节点中,将
enablePullDownRefresh设置为true - 局部开启下拉刷新: 在页面.json配置文件中,将
enablePullDownRefresh设置为true
我们可以通过backgroundTextStyle和backgroundColor来配置下拉刷新窗口的样式,前者是用来配置下拉刷新的窗口背景颜色,仅支持16进制的颜色值,后者用来配置下拉刷新loading的样式,仅支持drak和light
在页面.js文件中, 通过onPullDownRefresh()函数即可监听当前页面的下拉刷新事件。当我们处理完下拉刷新后,下拉刷新的loading效果会一直存在,不会主动消失,所以需要手动隐藏loading效果。调用wx.stopPullDownRefresh()可以停止当前页面的刷新。
在页面.js中我们也可以通过onReachBottom()函数即可监听当前页面的上拉触底事件。
上拉触底距离指的是触发上拉触底事件时,滚动条距离页面底部的距离
key在全局或页面的.json配置文件中,通过onReachBottomDistance属性来配置上拉触底的距离。小程序默认的触底距离是50px,在实际开发中可以根据自己的需求修改这个默认值。
上拉触底案例:

- 定义获取随机颜色的方法
- 在页面加载时获取初始数据
- 渲染UI结构并没话页面效果
在上拉触底时调用并获取随机颜色的方法添加loading提示效果对上拉触底进行节流处理
Page({
/**
* 页面的初始数据
*/
data: {
colorList:[], // 随机颜色的列表
isLoading: false
},
// 获取随机颜色列表
getColors() {
wx.request({
url: 'https://www.escook.cn/api/color',
method: "GET",
success: (res) => {
this.setData({
colorList:this.data.colorList.concat(res.data.data)
})
},
complete: () => {
wx.hideToast()
this.setData({
isLoading: false
})
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.getColors()
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
if (this.data.isLoading) {
return
}
wx.showToast({
title: '数据加载中...',
icon: "loading"
})
this.setData({
isLoading: true
})
// 页面上拉加载 请求
this.getColors()
},
})
- 扩展: 自定义编译模式, 当你在开发中想要编译之后,直接显示到某个页面, 那么你可以创建自己的编译模式。


5.3 页面中的生命周期函数
生命周期是指一个对象从创建-运行-销毁的整个阶段,强调的是一个时间段。
每个小程序的运行过程,也概括为生命周期, 小程序的启动,表示生命周期的开始;小程序的关闭,表示生命周期的结束,中间小程序的运行过程,就是小程序的生命周期
在小程序中生命周期分为两类:
应用生命周期: 特指小程序从启动-运行-销毁的过程页面的生命周期:特指小程序中,每个页面的加载-渲染-销毁的过程

生命周期函数:是由小程序框架提供的内置函数,会伴随着生命周期,自动按次序执行生命周期函数的作用:允许程序员在特定的时间点,执行某些特定的操作。例如,页面在刚加载的时候,可以在onLoad生命收起函数中初始化页面的数据- 注意: 生命周期强调的是时间段, 生命周期函数强调的是时间点


5.4 WXS的脚本
WXS: 是小程序独有的一套脚本语言,结合WXML,可以构建出页面的结构。wxml中无法调用在页面的.js中定义的函数,但是wxml中可以调用wxs中定义的函数。因此小程序中wxs的典型应用场景就是过滤器- wxs和JavaScript的关系,虽然wxs的语法类似于JavaScript,但是wxs和JavaScript是完全不同的两种语言:
wxs有自己的数据类型:number数值类型、string字符串类型、boolean类型、object对象类型;function函数类型、array数组类型、date日期类型、regexp正则
wxs不支持类似于ES6及以上的语法格式:不支持:let、const 、结构赋值、展开运算符、箭头函数、对象属性简写、etc支持:var 定义变量、普通function函数类似于ES5的语法
wxs遵循CommonJS规范:module对象、requeire()函数、module.exports对象
- 内嵌wxs脚本:wxs代码可以编写在
wxml文件中的<wxs>标签内,就像Javascript代码可以编写在html文件中的

wxs代码还可以编写在以.wxs为后缀名的文件内,就像javascript代码可以编写在以.js为后缀名的文件中一样。示例代码如下:

注意: 微信中共享的时候不支持简写,必须写全。 不能这样写module.exports = {toLower}
和JavaScript不同,为了降低wxs(WeiXin Script)的学习成本,wxs语言在设计时大量借鉴了JavaScript的语法.但是本质上,wxs和JavaScript是完全不同的两种语言!
wxs的典型应用场景就是过滤器,经常配合Mustache语法进行使用,例如:<view>{{m1.toUpper(username)}}</view>,但是,在wxs中定义的函数不能作为组件的事件回调函数。例如下面用法是错误的:

- wxs的特点
隔离性:指的是wxs的运行环境和其他JavaScript代码是隔离的。体现在如下两方面:wxs不能调用js中定义的函数、wxs不能调用小程序提供的API性能好:在IOS设备上,小程序内的WXS会比JavaScript代码快2~20倍,在android设备上,两者的运行效率差无差异
6 自定义组件
6.1 自定义组件
6.1.2 组件的创建、引用方式
- 创建组件:
- 在项目的根目录中,鼠标右键创建components->test文件夹
- 在新建的components -> test文件夹上,鼠标右键,点击
新建components - 输入组件的名称之后回车,会自动生成组件对应的4个文件,后缀名分别为
.js、.json、.wxml、.wxss 注意:为了保证目录结构的清晰,建议把不同的组件,存放到单独目录中。

局部引用组件:在需要引用的页面的.json配置文件中引用组件的方式,叫做局部引用

全局引用组件:直接在app.json全局配置文件中引用组件的方式,叫做全局引用

- 全局引用和局部引用:根据组件的
使用频率和范围,来选择合适的引用方式:- 如果某组件在
多个页面中经常被用到,建议进行全局引用 - 如果某个组件只
在特定的页面中被用到,建议进行局部引用
- 如果某组件在
- 组件和页面的区别:从表面上看都是由
.js、.json、.wxml、.wxss四个文件组成。但是.js和.json文件有明显的不同:- 组件的.json文件中需要声明
"component":true属性 - 组件的.js文件中调用的是
Component()函数 - 组件的事件处理函数需要定义到
methods节点中
- 组件的.json文件中需要声明
6.1.2 样式影响
- 默认情况下,自定义组件的样式只对当前组件生效,不会影响到组件之外的UI结构,如图所示:
- 组件A的样式
不会影响组件C的样式 - 组件A的样式
不会影响小程序页面的样式 - 小程序页面的样式
不会影响组件A和C的样式 - 好处: 防止外界的样式影响组件内部的样式、防止组件的样式破坏外界的样式
- 组件A的样式

- 组件式隔离的注意点:
app.wxss中的全局样式对组件无效,只有class选择器会有样式隔离效果,其它例如 id选择器、属性选择器、标签选择器不受样式隔离的影响。 建议在组件和引用组件的页面中建议使用class选择器,不要使用id、属性、标签选择器
默认情况下,自定义组件的样式隔离特性能够防止组件内外样式互相干扰的问题。但有时,我们希望在外界能够控制组件内部的样式,此时,可以通过stylesolation修改组件的样式隔离选项, 下面两种配置方式都可以:

styleIsolation的可选值:

6.1.3 数据、方法、属性
关于自定义组件- 数据、方法和属性
- 在小程序组件中,
用于组件模版渲染的私有数据需要定义到data结点中 - 在小程序组件中,
事件处理函数和自定义方法需要定义到methods节点中。自定义方法建议以_开头 - 在小程序组件中,properties是对组件的对外属性,
用来接受外界传递到组件中的数据

在小程序中,properties属性和data数据的用法相同,他们都是可读可写的,只不过:
- data 更倾向于
存储组件私有数据 - properties 更倾向于
存储外界传递到组件中的数据

由上面结果可知data和properties属性 本质上是一样的,都是可读可写的,因此properties属性的值也可以用于页面渲染,或使用setData位properties中的属性重新赋值。
updateMaxVlaue() {
// 使用setData 修改属性的值
this.setData({
max: this.properties.max + 1
})
}
6.1.4 数据监听器
数据监听器用于监听和响应任何属性和数据字段的变化,从而执行特定的操作。它的作用类似于vue中的watch侦听器。在小程序组件中,数据监听器的基本语法格式如下:

数据监听器支持监听对象中的单个或多个属性的变化,

注意: rgb对象中任意一个属性变化都会触发数据监听方法, 导致颜色数值的变化
如果某个对象中需要被监听的属性太多,为了方便, 可以使用通配符 ** 来监听对象中的所有属性变化
// 使用通配符 函数的参数是一个对象
'rgb.**': function (obj) {
fullColor: obj.r + ',' + obj.g + ',' + obj.b
}
6.1.5 存数据字段
纯数字字段指的是那些不用于界面渲染的data字段。
应用场景:例如有些情况,某些data中的字段既不会展示在界面上,也不会传递给其它组件,仅仅在当前组件内部使用。带有这种特性的data字段适合被设为纯数据字段。
好处: 纯数据字段,有助于提升页面更新的性能

6.1.6 组件的生命周期
小程序组件的可用生命周期函数如下:

在小程序组件中,最重要的生命周期函数有3个,分别是created、attached、detached。它们各自的特点如下:
-
组件实例
刚被创建好的时候,created生命周期函数会被触发:此时还不能调用setData,这个生命周期函数中,通常只应该给组件的this添加一些自定义的属性字段 -
在组件
完全初始化完毕,进入页面结点树后,attached生命周期函数被触发,此时this.data已经被初始化完毕,在该函数中,绝大多数的初始化工作都可以在这个时机进行(例如发送请求获取初始数据) -
在组件
离开页面结点树后,detached生命周期函数会被触发,当你退出一个页面时,会触发页面内每个自定义组件的detached生命周期函数,这时候适合做一些请理性工作 -
lifetimes:在小程序组件中,生命周期函数可以直接定义在Component构造器的第一级参数中,可以在lifetimes字段内进行声明(这是 推荐的方式,其优先级最高)

有时候,自定义组件的行为依赖于页面状态的变化,此时就需要用到组件所在页面的生命周期。 例如: 每当触发页面的show生命收起函数的时候,我们希望能够重新生成一个随机的RGB颜色值。在自定义组件中,组件所在的页面的生命周期函数有如下三个:


6.1.7 自定义组件-插槽
在自定义组件的wxml结构中,可以提供一个<slot>结点(插槽),用于承载组件使用者提供的wxml结构。

在小程序中,默认的每个自定义组件中只允许使用一个<slot>进行占位,这种个数上的限制叫做单个插槽

如果你需要再自定义的组件中,使用多个<slot>插槽时,可以在组件的.js文件中,通过如下方式进行启动。

6.1.8 自定义组件-父子组件之间的通信
父子组件之间的3种方式:
- 属性绑定: 用于父组件向子组件的指定属性设置数据,仅能设置JSON兼容的数据
- 事件绑定:用于子组件向父组件传递数据,可以传递任意数据
- 获取组件实例:父组件还可以通过
this.selectComponent()获取子组件实例对象, 这样就可以直接访问子组件的任意数据和方法
6.1.8.1 属性绑定
属性绑定用于实现父向子传值,而且只能传递普通类型的数据,无法将方法传递给子组件。

6.1.8.2 事件绑定
事件绑定用于实现子向父传值,可以传递任何类型的数据。
- 在
父组件的js文件中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件 - 在
父组件的wxml中,通过自定义事件的形式,将步骤1中定义的函数引用,传递给子组件。 - 在
子组件的js中,通过调用this。triggerEvent('自定义事件名称', {参数对象})将数据发送到父组件 - 在
父组件的js中,通过e.detail获取到子组件传递过来的数据

6.1.8.3 获取组件实例
在父组件中里面调用this.selectCpmponent("id或class选择器"),获取子组件的实例对象,从而直接访问子组件的任意数据和方法。调用时需要传入一个选择器,例如:

6.1.9 behaviors
什么是behaviors?
behaviors是小程序中,用于实现组件代码共享的特性, 类似于Vue.js中的mixins.

每个behaviors可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中
每个组件可以引用多个behaviors,behaviors也可以引用其他的behaviors
那么如何创建behavior?
调用Behavior(Object object)方法即可创建一个共享的behavior,供所有的组件使用. 然后直接在组件中,使用require()方法导入需要的behavior,挂载后即可访问behavior中的数据或方法

- behavior中的所有可用节点

同名字段的覆盖和组合规则: 组件和它引用的behavior中可以包含同名的字段,此时参考如下的处理规则:
- 同名的字段(data)
- 同名的属性(
properties)或方法(methods) - 同名的
生命周期函数
关于同名字段的详细覆盖规则参考:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html
6.2 使用npm包
目前小程序已经支持使用npm安装第三方包,从而提高小程序的开发效率。但是,在小程序中使用npm包有如下3个限制:
- 不支持依赖于
Node.js内置库的包 - 不支持依赖于
浏览器内置对象的包 - 不支持依赖于
C++插件的包 - 虽然npm上的包有千千万,但是能供小程序使用的包却”为数不多“
6.2.1 Vant Weapp的安装使用
Vant Weapp是有赞前端团队开源的一套小程序UI组件库,助力开发者快速搭建小程序应用。它所使用的是MIT开源许可协议,官方文档地址:https://youzan.github.io/vant-weapp
安装步骤参考官方文档:Vant快速上手
使用npm init -y 可在项目中初始化package.json文件,当使用npm包时,项目内没有package.json文件时,可以使用该命令创建。 但是一般你使用npm 命令安装包时, npm会自动给你创建package.json文件,不需要你自己去创建
当我们执行npm命令安装好Vant包时,可以在app.json的usingComponents结点中引入需要的组件,即可在wxml中直接使用组件。

Vant Weapp 可使用CSS变来实现定制主题。关于CSS的变量的基本用法,参开文档:https://developer.mozilla.org/zh-CN/docs/Web/CSS/Using_CSS_custom_properties
使用CSS自定义组件的样式: 在app.wxss中写入CSS变量,即可对全局生效

官方文档, [CSS相关变量名列表][https://github.com/youzan/vant-weapp/blob/dev/packages/common/style/var.less]
6.2.2 API Promise化
小程序官方提供的异步API都是基于回调函数实现的,例如,网络请求的API需要按照如下的方式调用:

缺点是容易造成回调地狱的问题,代码的可读性、维护性差
API Promise化:指的是通过额外的配置,将官方提供的、基于回调函数的一部API,升级改造为基于Promise的异步化API,从而提高代码的可读性,避免地狱回调的问题
在小程序中实现API Promise化主要依赖于miniprogram-api-promise这个第三方的npm包。它的安装和使用步骤如下:
npm install --save miniprogram-api-promise@1.0.4 // 这里我安装的是指定1.0.4版本

6.3 全局数据共享
全局数据共享:又叫做状态管理,是为了解决组件之间的数据共享的问题。开发中常用的全局数据共享方法有:Vuex、Redux、Mobx等

小程序中可以使用mobx-miniprogram配合mobx-miniprogram-bindings实现全局数据共享。 前者用来创建Store示例对象,后者用来把Store中的共享数据或方法,绑定到组件或页面中使用
安装命令如下:npm install --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1 这里安装也是指定了对应包的版本。 注意:Mobx相关包安装完毕之后,记得删除miniprogram_npm目录后,重新构建npm, 以免出现错误
创建Mobx的Store实例:
import { observable, action } from 'mobx-miniprogram'
export const store = observable({
//数据字段
numA: 1,
numB: 2,
// 计算属性
get sum() {
return this.numA + this.numB
},
// action 方法, 用来修改store中的数据
updateNumA: action(function (setp) {
this.numA += setp
}),
updateNumB: action(function (setp) {
this.numB += setp
}),
})
将Store中的成员绑定到页面中:

在页面中使用Store中的成员:

将Store中的成员绑定到组件中:

6.4 分包
6.4.1 分包概述
分包:分包是指把一个完整的小程序项目,按照需求划分为不同的子包,在构建时打包成不同的包,用户在使用时按需进行加载。 其优点:可以优化小程序首次启动的下载时间,在多团队共同开发时可以更好的解耦协作
分包前,小程序项目中所有的页面和资源都被打包到了一起,导致整个项目体积过大,影响小程序首次启动的下载时间

分包后,小程序项目由1个主包+多个分包组成
- 主包:一般只包含项目的
启动页面或tabBar页面、以及所有分包都需要用到一些公共资源 - 分包:只包含当前分包有关的页面和私有资源

- 分包的加载机制:
- 在小程序启动时,默认会
下载主包并启动主包页面,tabBar页面需要放到主包中 - 当用户进入分包某个页面时,
客户端会把对应分包下载下来,下载完成后再进行展示,非tabBar页面可以按照功能的不同,划分为不同的分包之后,进行按需下载 - 注意: 分包对于体积有限制,整个小程序的所有分包大小不超过
16M(主包+所有分包)、单个分包/主包大小不能超过2M
- 在小程序启动时,默认会
如何使用配置分包:

- 打包原则:
- 小程序会按
subpakages的配置进行分包,subpackages之外的目录将被打包到主包中 - 主包也可以有自己的pages(即最外层的pages字段)
- tabBar页面必须在主包内
- 分包之间不能互相嵌套
- 小程序会按
- 引用原则:
- 主包
无法引用分包内的私有资源 - 分包之间
不能相互引用私有资源 - 分包
可以引用主包内的公共资源
- 主包

6.4.2 独立分包
独立分包: 独立分包本质上也是分包,只不过比较特殊,可以独立于主包和其他分包而单独运行。

- 独立分包和普通分包的区别:主要区别是
是否依赖于主包才能运行- 普通分包必须依赖于主包才能运行
- 独立分包可以在不下载主包的情况下,独立运行
独立分包的应用场景:开发者可以按需,将具有一定功能独立性的页面配置到独立包中。其中原因如下:
-
当小程序从普通分包页面启动时,需要首先下载主包
-
而独立分包
不依赖主包即可以运行,可以很大程序上提升分包页面的启动速度 -
注意:一个小程序中可以有多个独立分包

-
引用原则:独立分包和普通分包以及主包之间,是
相互隔绝的,不能相互引用彼此的资源,例如:- 主包
无法引用独立分包内的私有资源 - 独立分包之间,
不能相互引用私有资源 - 独立分包和普通分包之间,
不能相互引用私有资源 - 特别注意:独立分包中不能引用主包内的公共资源
- 主包
6.4.3 分包预下载
分包预下载:指的是在进入小程序的某个页面时,由框架自动预下载可能需要的包,从而提升进入后续分包页面时的启动速度
配置分包的预下载:预下载分包的行为,会进入指定的页面时触发,在app.json中,使用proloadRule结点定义分包的预下载规则,示例代码如下:

分包预下载的限制:同一个分包中的页面享有共同的预下载大小限额2M:

微信小程序开发详解:从基础到实践
1625





