微信小程序
1. 小程序简介
小程序与普通网页开发的区别
1、运行环境不同
网页运行在浏览器环境中,小程序运行在微信环境中。网页开发渲染线程和脚本线程是互斥的,这也是为什么长时间的脚本运行可能会导致页面失去响应,而在小程序中,二者是分开的,分别运行在不同的线程中。
2、API不同
由于运行环境的不同,所以小程序中,无法调用 DOM 和 BOM 的 API。
但是,小程序中可以调用微信环境提供的各种 API,例如:地理定位、扫码、支付。
3、开发模式不同
网页的开发模式:浏览器 + 代码编辑器
小程序有自己的一套标准开发模式:
- 申请小程序开发账号
- 安装小程序开发者工具
- 创建和配置小程序项目
2. 开始
注册小程序账号
进入小程序注册页 根据指引填写信息和提交相应的资料,就可以拥有自己的小程序帐号。
获取小程序的AppID
在小程序管理平台 ,我们可以管理自己的小程序的权限,查看数据报表,发布小程序等操作。
在菜单 开发管理
->开发设置
->开发者ID可以看到小程序的 AppID ,其相当于小程序平台的一个身份证。
安装开发者工具
微信开发者工具是官方推荐使用的小程序开发工具,它提供的主要功能如下:
① 快速创建小程序项目
② 代码的查看和编辑
③ 对小程序功能进行调试
④ 小程序的预览和发布
推荐下载和安装最新的稳定版(Stable Build)的微信开发者工具,进入开发者工具下载网址 下载适合的版本,这里我选择的是Windows64位。
下载后按照指示即可完成安装
创建小程序项目
进入小程序开发者工具,选择小程序点击+
填写项目名称,选择代码存放的硬盘路径,填入刚刚申请到的小程序的 AppID。勾选 “不使用云服务” ,选择JavaScript语言,点击新建。
注意
: 要选择一个空的目录才可以创建项目
这样,你就得到了你的第一个小程序。
可以在模拟器上查看项目效果,也可以在真机上预览项目效果
3. 小程序代码构成
整体结构
pages
用来存放所有小程序的页面utils
用来存放工具性质的模块(例如:格式化时间的自定义模块)app.js
小程序项目的入口文件app.json
小程序项目的全局配置文件app.wxss
小程序项目的全局样式文件project.config.json
工具配置,在工具上做的任何配置都会写入到这个文件。- 项目根目录中的
project.config.json
和project.private.config.json
文件可以对项目进行配置,project.private.config.json
中的相同设置优先级高于project.config.json
sitemap.json
用来配置小程序及其页面是否允许被微信索引
page文件
小程序官方建议把所有小程序的页面,都存放在 pages 目录中,以单独的文件夹存在。每个页面由 4 个基本文件组成,它们分别是:
.js
文件:页面的脚本文件,存放页面的数据、事件处理函数等.json
文件:当前页面的配置文件,配置窗口的外观、表现等.wxml
文件:充当的就是类似 HTML 的角色,包含页面的模板结构.wxss
文件:当前页面的样式表文件
json 文件
app.json
是当前小程序的全局配置,包括了小程序的所有页面路径、窗口外观、界面表现、底部 tab 等。
pages
:用来记录当前小程序所有页面的路径window
:全局定义小程序所有页面的背景色、文字颜色等style
:全局定义小程序组件所使用的样式版本sitemapLocation
:用来指明 sitemap.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
是项目配置文件,用来记录我们对小程序开发工具所做的个性化配置,例如:
setting
中保存项目的编译设置projectname
中保存的是项目名称,只在新建项目时读取appid
中保存的是项目的 appid,只在新建项目时读取
小程序根目录下的 sitemap.json
文件用于配置小程序及其页面是否允许被微信索引,文件内容为一个 JSON 对象,如果没有 sitemap.json ,则默认为所有页面都允许被索引;
当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索词条触发该索引时,小程序的页面将可能展示在搜索结果中。
如下,所有页面都会被微信索引(默认情况)
{
"rules":[{
"action": "allow",
"page": "*"
}]
}
配置 path/to/page
页面被索引,其余页面不被索引
{
"rules":[{
"action": "allow",
"page": "path/to/page"
}, {
"action": "disallow",
"page": "*"
}]
}
每一个小程序页面也可以使用同名 .json
文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.json 的 window 中相同的配置项。
我们在app.json
的pages配置中输入新建的页面,就可以自动生成对应的文件夹。
注意
:只需要调整 app.json -> pages 数组中页面路径的前后顺序,即可修改项目的首页。小程序会把排在第一位的页面,当作项目首页进行渲染。
WXML
WXML(WeiXin Markup Language)是小程序框架设计的一套标签语言,用来构建小程序页面的结构,其作用类似于网页开发中的 HTML。
WXML 和 HTML 的区别
(1) 标签名称不同
- HTML (div, span, img, a)
- WXML(view, text, image, navigator)
(2)属性节点不同
<a href="#">超链接</a>
<navigator url="/pages/home/home"></navigator>
(3)提供了类似于 Vue 中的模板语法
- 数据绑定( {{message}} )
- 列表渲染(wx:for)
- 条件渲染(wx:if)
WXSS
WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式,类似于网页开发中的 CSS。
WXSS 和 CSS 的区别
(1)新增了 rpx 尺寸单位
- CSS 中需要手动进行像素单位换算,例如 rem
- WXSS 在底层支持新的尺寸单位 rpx,在不同大小的屏幕上小程序会自动进行换算。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
(2)提供了全局的样式和局部样式
- 项目根目录中的 app.wxss 会作用于所有小程序页面
- 局部页面的 .wxss 样式仅对当前页面生效
(3) WXSS 仅支持部分 CSS 选择器
- .class 和 #id
- element(组件)
- 并集选择器、后代选择器
- ::after 和 ::before 等伪类选择器
JS 逻辑交互
小程序中的 JS 文件分为三大类
app.js
:是整个小程序项目的入口文件,通过调用 App() 函数来启动整个小程序页面的 .js 文件
:是页面的入口文件,通过调用 Page() 函数来创建并运行页面普通的 .js 文件
:是普通的功能模块文件,用来封装公共的函数或属性供页面使用
4. 小程序的宿主环境
微信客户端给小程序所提供的环境是宿主环境
,宿主环境
(host environment)指的是程序运行所必须的依赖环境。小程序借助宿主环境提供的能力,可以完成许多普通网页无法完成的功能,例如:微信扫码、微信支付、微信登录、地理定位、etc…
小程序开发过程中需要面对的是两大操作系统 iOS
和 Android
的微信客户端,以及用于辅助开发的小程序开发者工具。
安卓版的微信 App 是不能在 iOS 环境下运行的,脱离了宿主环境的软件是没有任何意义的!
渲染层和逻辑层
小程序的运行环境分成渲染层和逻辑层,其中
WXML
模板和WXSS
样式工作在渲染层JS
脚本工作在逻辑层。
小程序的渲染层和逻辑层分别由2个线程管理:
- 渲染层的界面使用了WebView 进行渲染;
- 逻辑层采用JsCore线程运行JS脚本。
一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端(
Native
指微信客户端)做中转,逻辑层发送网络请求也经由Native
转发,小程序的通信模型下图所示。
小程序启动的过程
(1)微信客户端在打开小程序之前,会把整个小程序的代码包下载到本地。
(2)通过 app.json 的 pages 字段就可以知道当前小程序的所有页面路径,第一个页面index.js
就是这个小程序的首页 。 微信客户端会把首页的代码装载进来,通过小程序底层的一些机制,渲染出这个首页。
{
"pages":[
"pages/index/index",
"pages/logs/logs"
]
}
小程序启动之后,在 app.js 定义的 App 实例的 onLaunch
回调会被执行。
注意
:整个小程序只有一个 App 实例,是全部页面共享的。
App({
onLaunch: function () {
// 小程序启动之后 触发
}
})
(3)小程序启动完成
页面渲染的过程
(1)微信客户端会先根据.json
配置生成一个界面,顶部的颜色和文字你都可以在这个 json
文件里边定义好。
(2)紧接着客户端就会装载这个页面的 WXML
结构和 WXSS
样式。
(3)最后客户端会装载.js
// .js 文件
Page({
// 页面的初始数据
data: {
},
// 生命周期函数--监听页面加载
onLoad(options) {
},
// 生命周期函数--监听页面初次渲染完成
onReady() {
},
// 生命周期函数--监听页面显示
onShow() {
},
// 生命周期函数--监听页面隐藏
onHide() {
},
// 生命周期函数--监听页面卸载
onUnload() {
},
// 页面相关事件处理函数--监听用户下拉动作
onPullDownRefresh() {
},
// 页面上拉触底事件的处理函数
onReachBottom() {
},
//用户点击右上角分享
onShareAppMessage() {
}
})
Page 是一个页面构造器,这个构造器就生成了一个页面。在生成页面的时候,小程序框架会把 data 数据和 index.wxml 一起渲染出最终的结构。
组件
小程序中的组件也是由宿主环境提供的,开发者可以基于组件快速搭建出漂亮的页面结构。
像 HTML 的 div, p 等标签一样,在小程序里边,你只需要在 WXML 写上对应的组件标签名字就可以把该组件显示在界面上,
<map> </map>
官方把小程序的组件分为:
- 视图容器
- 基础内容
- 表单组件
- 导航组件
- 媒体组件
- map 地图组件
- canvas 画布组件
- 开放能力
- 无障碍访问
- 导航栏
视图容器
1、view
- 普通视图区域
- 类似于 HTML 中的 div,是一个块级元素
- 常用来实现页面的布局效果
WXML
:
<view class='container1'>
<view>A</view>
<view>B</view>
<view>C</view>
</view>
WXSS
/* pages/list/list.wxss */
.container1 view{
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
}
.container1 view:nth-child(1){
background-color: lightgreen;
}
.container1 view:nth-child(2){
background-color: lightpink ;
}
.container1 view:nth-child(3){
background-color: lightskyblue;
}
.container1{
display: flex;
justify-content: space-around;
}
2、 scroll-view
- 可滚动的视图区域
- 常用来实现滚动列表效果
WXML
<!-- scroll-y属性:允许纵向滚动 -->
<!-- scroll-x属性:允许横向滚动 -->
<!-- 使用竖向滚动时,需要给scroll-view一个固定高度,通过 WXSS 设置 height -->
<scroll-view class='container1' scroll-y>
<view>A</view>
<view>B</view>
<view>C</view>
</scroll-view>
WXSS
/* pages/list/list.wxss */
.container1 view{
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
}
.container1 view:nth-child(1){
background-color: lightgreen;
}
.container1 view:nth-child(2){
background-color: lightpink ;
}
.container1 view:nth-child(3){
background-color: lightskyblue;
}
.container1{
border: 1px solid red;
height: 150px;
width: 100px;
}
3、swiper
和 swiper-item
- 轮播图容器组件 和 轮播图 item 组件
WXML
<!-- indicator-dots 是否显示面板指示点 -->
<swiper class="swiper-container" indicator-dots>
<swiper-item>
<view class="item">A</view>
</swiper-item>
<swiper-item>
<view class="item">B</view>
</swiper-item>
<swiper-item>
<view class="item">C</view>
</swiper-item>
</swiper>
WXSS
/* pages/list/list.wxss */
.swiper-container{
height: 150px;
}
.item{
height: 100%;
line-height: 150px;
text-align: center;
}
swiper-item:nth-child(1) .item{
background-color: lightgreen;
}
swiper-item:nth-child(2) .item{
background-color: lightpink ;
}
swiper-item:nth-child(3) .item{
background-color: lightskyblue;
}
常见属性
:属性
基础内容组件
1、text
- 文本组件
- 类似于 HTML 中的 span 标签,是一个行内元素
通过 text 组件的 user-select
属性可以实现长按选中文本内容的效果(其他的不可以):
<!-- 长按不可复制 -->
<view>
手机号哈哈哈哈
</view>
<!-- 长按可复制 -->
<text user-select>
烤肉哈哈哈哈哈
</text>
注意
:这里需要用预览实现长按效果,模拟器不行。
2、rich-text
- 富文本组件
- 支持把 HTML 字符串渲染为 WXML 结构
<rich-text nodes="<h1 style='color:pink'>你好</h1>"></rich-text>
button 按钮组件
功能比 HTML 中的 button 按钮丰富,常见属性如下
size
:default、minitype
: primary(绿色)、default(白色)、warn(红色)plain
:按钮是否镂空,背景色透明
<button type="primary" plain open-type="share" >hh</button>
image 图片组件
image 组件默认宽度约 300px、高度约 240px
<image></image>
image{
border: 1px solid red;
border-style: solid;
}
image
组件的 mode
属性用来指定图片的裁剪和缩放模式
API
宿主环境提供了丰富的API,可以很方便调起微信提供的能力。wx
对象是小程序的宿主环境所提供的全局对象,几乎所有小程序的API都挂载在wx对象底下(除了Page/App等特殊的构造器)。
1、wx.on*
开头的 API 是监听某个事件发生的API接口,接受一个 Callback 函数作为参数。当该事件触发时,会调用 Callback 函数。
// 监听窗口尺寸变化的事件
wx.onWindowResize(function callback)
2、 同步 API
- 以 Sync 结尾的 API 都是同步 API
- 同步 API 的执行结果,可以通过函数返回值直接获取,如果执行出错会抛出异常
wx.setStorageSync('key', 'value')
向本地存储中写入内容
3、异步 API
多数 API 接口为异步接口 ,都接受一个Object作为参数。API的Object参数一般由success、fail、complete三个回调来接收接口调用结果
wx.request({
url: 'test.php',
data: {},
header: { 'content-type': 'application/json' },
success: function(res) {
// 收到https服务成功后返回
console.log(res.data)
},
fail: function() {
// 发生网络错误等情况触发
},
complete: function() {
// 成功或者失败后触发
}
})
4、wx.get*
开头的API是获取宿主环境数据的接口。
5、wx.set*
开头的API是写入数据到宿主环境的接口。
事件
把用户在渲染层的行为反馈
以及组件的部分状态反馈
抽象为渲染层传递给逻辑层的事件
事件是通过bindtap这个属性绑定在组件上的,同时在当前页面的Page构造器中定义对应的事件处理函数tapName,当用户点击该view区域时,达到触发条件生成事件tap,该事件处理函数tapName会被执行,同时还会收到一个事件对象event。
WXML
<!-- page.wxml -->
<view id="tapTest" data-hi="WeChat" bindtap="tapName"> Click me! </view>
js
文件
// page.js
Page({
tapName: function(event) {
console.log(event)
}
})
常见的事件类型如下:
事件绑定与冒泡捕获
以key="value"的形式绑定事件,
- key以bind或者catch开头,然后跟上事件的类型,如
bindtap
、catchtouchstart
。自基础库版本1.5.0起,bind和catch后可以紧跟一个冒号,其含义不变,如bind:tap、catch:touchstart。同时bind和catch前还可以加上capture-
来表示捕获阶段。 - value是一个字符串,需要在对应的页面Page构造器中定义同名的函数,否则触发事件时在控制台会有报错信息。
bind和capture-bind的含义分别代表事件的冒泡阶段和捕获阶段,其触发的顺序如图
点击 inner view 会先后调用handleTap2、handleTap4、handleTap3、handleTap1。
<view
id="outer"
bind:touchstart="handleTap1"
capture-bind:touchstart="handleTap2"
>
outer view
<view
id="inner"
bind:touchstart="handleTap3"
capture-bind:touchstart="handleTap4"
>
inner view
</view>
</view>
bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡。如果将上面代码中的第一个capture-bind改为capture-catch,将只触发handleTap2(capture-catch将中断捕获阶段和取消冒泡阶段)
<view
id="outer"
bind:touchstart="handleTap1"
capture-catch:touchstart="handleTap2"
>
outer view
<view
id="inner"
bind:touchstart="handleTap3"
capture-bind:touchstart="handleTap4"
>
inner view
</view>
</view>
Page.prototype.setData
Page.prototype.setData(Object data, Function callback)
函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的 this.data 的值(同步)。
- Object 以
key: value
的形式表示,将 this.data 中的 key 对应的值改变成 value。其中 key 可以以数据路径的形式给出,支持改变数组中的某一项或对象的某个属性,如array[2].message
,a.b.c.d
,并且不需要在 this.data 中预先定义。 - 直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。
<button type="primary" bindtap="btnTapHandler">{{count}}</button>
Page({
// 页面的初始数据
data: {
count:0
},
btnTapHandler(){
this.setData({
count:this.data.count+1
})
},
})
dataset
在组件节点中可以自定义数据,然后在事件中可以获取这些自定义的节点数据,用于事件的逻辑处理。
自定义数据以
data-
开头,多个单词由连字符 - 连接。这种写法中,连字符写法会转换成驼峰写法,而大写字符会自动转成小写字符。如:
- data-element-type ,最终会呈现为 event.currentTarget.dataset.elementType ;
- data-elementType ,最终会呈现为 event.currentTarget.dataset.elementtype 。
<button type="primary" bindtap="btnTapHandler" data-elementType="2022" data-element-type="2024" >{{count}}</button>
btnTapHandler(event){
console.log(event.currentTarget.dataset);
this.setData({
count:this.data.count+1
})
},
bindinput
在小程序中,通过 input 事件来响应文本框的输入事件。键盘输入时触发,event.detail = {value, cursor, keyCode}
,value为文本框变化后的值,keyCode 为键值。
2.1.0 起支持,处理函数可以直接 return 一个字符串,将替换输入框的内容。
<input type="text" placeholder="hello" bindinput="inputHandler"/>
inputHandler(event){
console.log(event.detail.value);
},
5. WXML
单向绑定
WXML
注意
:属性值必须被包裹在双引号(或单引号)中
<view>{{info}}</view>
<image src='{{image_src}}' mode="widthFix"></image>
WXSS
data: {
info:"hello",
image_src:'../../image/1.jpeg'
},
注意
:没有被定义的变量的或者是被设置为 undefined
的变量不会被同步到 wxml 中
双向绑定
在 WXML 中,普通的属性的绑定是单向的。如果用户修改了输入框里的值,却不会同时改变 this.data.value 。
<input value="{{value}}" />
如果需要在用户输入的同时改变 this.data.value ,需要借助简易双向绑定机制。此时,可以在对应项目之前加入model:
前缀:
<input model:value="{{value}}" />
条件渲染
使用 wx:if=“” 来判断是否需要渲染该代码块:
<view wx:if="{{condition}}"> True </view>
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
<!-- <block/> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性 -->
<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
在小程序中,直接使用 hidden="{{ condition }}"
也能控制元素的显示与隐藏:
<view hidden="{{length>2}}">hello</view>
wx:if
vshidden
(1)运行方式不同
- wx:if 以动态创建和移除元素的方式,控制元素的展示与隐藏
- hidden 以切换样式的方式(display: none/block;),控制元素的显示与隐藏
(2)使用建议
- 频繁切换时,建议使用 hidden
- 控制条件复杂时,建议使用 wx:if 搭配 wx:elif、wx:else 进行展示与隐藏的切换
列表渲染
在组件上使用 wx:for
控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item
<view wx:for="{{array}}">
{{index}}--{{item}}
</view>
data:{
array:[
'吃饭',
'睡觉',
'学习'
]
}
- 使用
wx:for-item
可以指定数组当前元素的变量名, - 使用
wx:for-index
可以指定数组当前下标的变量名:
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}--{{itemName}}
</view>
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
wx:key
的值以两种形式提供
- 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
- 保留关键字
*this
代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字。
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。
<switch wx:for="{{objectArray}}" wx:key="unique" style="display: block;"> {{item.id}} </switch>
<switch wx:for="{{numberArray}}" wx:key="*this" style="display: block;"> {{item}} </switch>
data: {
objectArray: [
{id: 5, unique: 'unique_5'},
{id: 4, unique: 'unique_4'},
{id: 3, unique: 'unique_3'},
{id: 2, unique: 'unique_2'},
{id: 1, unique: 'unique_1'},
{id: 0, unique: 'unique_0'},
],
numberArray: [1, 2, 3, 4]
},
模板
定义模板:使用 name 属性,作为模板的名字。然后在<template/>
内定义代码片段,如:
<template name="one">
<view>{{index}}</view>
<view>{{color}}</view>
</template>
<template is="one" data="{{...wage}}"></template>
<template is="one" data="{{...wage2}}"></template>
data:{
wage:{
index:1,
color:"red"
},
wage2:{
index:2,
color:"green"
},
}
引用
WXML 提供两种文件引用方式import
和include
,具体使用可直接查看官方文档
import
可以在该文件中使用目标文件定义的template。( import 目标文件中定义的 template,而不会 import 目标文件 import 的 template。)
<!-- item.wxml -->
<template name="item">
<text>{{text}}</text>
</template>
<!-- index.wxml -->
<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>
include
可以将目标文件除了<template/>
、<wxs/>
外的整个代码引入,相当于是拷贝到 include 位置
<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>
<!-- header.wxml -->
<view> header </view>
<!-- footer.wxml -->
<view> footer </view>
6. WXSS
WXSS
是一套样式语言,用于描述 WXML 的组件样式。
WXSS 具有 CSS 大部分特性,同时为了更适合开发微信小程序,WXSS 对 CSS 进行了扩充以及修改。与 CSS 相比,WXSS 扩展的特性有:
- 尺寸单位
rpx
- 样式导入
@import
rpx
rpx 的实现原理非常简单:鉴于不同设备屏幕的大小不同,为了实现屏幕的自动适配,rpx 把所有设备的屏幕,在宽度上等分为 750 份(即:当前屏幕的总宽度为 750rpx)。
- 在较小的设备上,1rpx 所代表的宽度较小
- 在较大的设备上,1rpx 所代表的宽度较大
小程序在不同设备上运行的时候,会自动把 rpx 的样式单位换算成对应的像素单位来渲染,从而实现屏幕适配。
建议开发微信小程序时设计师用 iPhone6
作为视觉稿的标准。
开发举例
:在 iPhone6 上如果要绘制宽100px,高20px的盒子,换算成rpx单位,宽高分别为 200rpx
和 40rpx
样式导入
使用@import
语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;
表示语句结束。
/** common.wxss **/
.small-p {
padding:5px;
}
/** app.wxss **/
@import "common.wxss";
.middle-p {
padding:15px;
}
对于内联样式,框架组件上支持使用 style
、class
属性来控制组件的样式。
style
接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度。
<view style="color:{{color}};" />
class
:用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式类名不需要带上.
,样式类名之间用空格分隔。
<view class="normal_view" />
全局样式与局部样式
定义在 app.wxss 中的样式为全局样式,作用于每一个页面。
在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。
7. 全局配置
小程序根目录下的 app.json 文件是小程序的全局配置文件。常用的配置项如下:
pages
: 记录当前小程序所有页面的存放路径window
:全局的默认窗口效果tabBar
:底部 tab栏效果style
:是否启用新版的组件样式
window
用于设置小程序的状态栏、导航条、标题、窗口背景色。
导航栏区域
属性 | 类型 | 默认值 | 描述 | 最低版本 |
---|---|---|---|---|
navigationBarBackgroundColor | HexColor | #000000 | 导航栏背景颜色,如 #000000 (不支持red、pink等英文) | |
navigationBarTextStyle | string | white | 导航栏标题颜色,仅支持 black / white | |
navigationBarTitleText | string | 导航栏标题文字内容 | ||
navigationStyle | string | default | 导航栏样式,仅支持以下值: default 默认样式 custom 自定义导航栏,只保留右上角胶囊按钮 | iOS/Android 微信客户端 6.6.0,Windows 微信客户端不支持 |
背景区域
属性 | 类型 | 默认值 | 描述 | 最低版本 |
---|---|---|---|---|
backgroundColor | HexColor | #ffffff | 窗口的背景色 | |
backgroundTextStyle | string | dark | 下拉 loading 的样式,仅支持 dark / light | |
backgroundColorTop | string | #ffffff | 顶部窗口的背景色,仅 iOS 支持 | 微信客户端 6.5.16 |
backgroundColorBottom | string | #ffffff | 底部窗口的背景色,仅 iOS 支持 | 微信客户端 6.5.16 |
页面区域
属性 | 类型 | 默认值 | 描述 | 最低版本 |
---|---|---|---|---|
enablePullDownRefresh | boolean | false | 是否开启全局的下拉刷新。 详见 Page.onPullDownRefresh | |
onReachBottomDistance | number | 50 | 页面上拉触底事件触发时距页面底部距离,单位为 px。 详见 Page.onReachBottom |
注意
:上拉触底是移动端的专有名词,通过手指在屏幕上的上拉滑动操作,从而加载更多数据的行为。
示例
:
开启下拉刷新才能看到背景区域
tabBar
tabBar 是移动端应用常见的页面效果,用于实现多页面的快速切换。小程序中通常将其分为:
-
底部
tabBar
-
顶部
tabBar
注意
:tabBar中只能配置最少 2 个、最多 5 个 tab 页签。当渲染顶部 tabBar 时,不显示 icon,只显示文本。
属性 | 类型 | 必填 | 默认值 | 描述 | 最低版本 |
---|---|---|---|---|---|
color | HexColor | 是 | tab 上的文字默认颜色,仅支持十六进制颜色 | ||
selectedColor | HexColor | 是 | tab 上的文字选中时的颜色,仅支持十六进制颜色 | ||
backgroundColor | HexColor | 是 | tab 的背景色,仅支持十六进制颜色 | ||
borderStyle | string | 否 | black | tabbar 上边框的颜色, 仅支持 black / white | |
list | Array | 是 | tab 的列表,详见 list 属性说明,最少 2 个、最多 5 个 tab | ||
position | string | 否 | bottom | tabBar 的位置,仅支持 bottom / top | |
custom | boolean | 否 | false | 自定义 tabBar,见详情 | 2.5.0 |
其中 list 接受一个数组,只能配置最少 2 个、最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象,其属性值如下:
属性 | 类型 | 必填 | 说明 |
---|---|---|---|
pagePath | string | 是 | 页面路径,必须在 pages 中先定义 |
text | string | 是 | tab 上按钮文字 |
iconPath | string | 否 | 图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。 当 position 为 top 时,不显示 icon。 |
selectedIconPath | string | 否 | 选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。 当 position 为 top 时,不显示 icon。 |
示例
:
"tabBar": {
"list": [{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "./image/home.png",
"selectedIconPath": "./image/home-active.png"
},
{
"pagePath": "pages/message/message",
"text": "消息",
"iconPath": "./image/message.png",
"selectedIconPath": "./image/message -active.png"
}
]
},
8. 网络数据请求
出于安全性方面的考虑,小程序官方对数据接口的请求做出了如下两个限制:
- 只能请求 HTTPS 类型的接口
- 必须将接口的域名添加到信任列表中
- 域名不能使用 IP 地址(小程序的局域网 IP 除外)或 localhost;
- 域名必须经过 ICP 备案;
- 不支持配置父域名,使用子域名
- 服务器域名一个月内最多可申请 5 次修改
可以通过以下步骤将接口的域名添加到信任列表中:
登录微信小程序管理后台 -> 开发 -> 开发管理 -> 开发设置 -> 服务器域名 -> 修改 request 合法域名
修改后可在:
跳过 request 合法域名校验
如果后端程序员仅仅提供了 http 协议的接口、暂时没有提供 https 协议的接口。
此时为了不耽误开发的进度,我们可以在微信开发者工具中,临时开启开发环境不校验请求域名、TLS 版本及 HTTPS 证书
选项,跳过 request 合法域名的校验。
注意
:跳过 request 合法域名校验的选项,仅限在开发与调试阶段使用!
wx.request
wx.request
用于发起 HTTPS 网络请求。
示例
:发起get请求
wx.request({
url: 'https://www.escook.cn/api/get',
method:"GET",
data:{
name:'zs',
age:20
},
success:res=>{
console.log(res);
}
})
注意事项
跨域问题只存在于基于浏览器的 Web 开发中。由于小程序的宿主环境不是浏览器,而是微信客户端,所以小程序中不存在跨域的问题。
Ajax 技术的核心是依赖于浏览器中的 XMLHttpRequest 这个对象,由于小程序的宿主环境是微信客户端,所以小程序中不能叫做“发起 Ajax 请求”,而是叫做发起网络数据请求
。
9. 页面导航
小程序中实现页面导航的两种方式
(1) 声明式导航
- 在页面上声明一个
<navigator>
导航组件 - 通过点击
<navigator>
组件实现页面跳转
(2)编程式导航
- 调用小程序的导航 API,实现页面的跳转
声明式导航
tabBar 页面指的是被配置为 tabBar 的页面。
1、导航到 tabBar 页面
在使用<navigator>
组件跳转到指定的 tabBar 页面时,需要指定 url 属性和 open-type 属性,其中:
url
表示要跳转的页面的地址open-type
表示跳转的方式,必须为switchTab
<navigator url="/pages/message/message" open-type="switchTab">导航到消息页面</navigator>
2、导航到非tabBar 页面
在使用 <navigator>
组件跳转到普通的非 tabBar 页面
时,则需要指定 url 属性和 open-type 属性,其中:
url
表示要跳转的页面的地址open-type
表示跳转的方式,必须为navigate
。默认值本身就是navigate,所以该属性可以不写。
<navigator url="/pages/info/info" open-type="navigate">导航到info页面</navigator>
<navigator url="/pages/info/info">导航到info页面</navigator>
3、后退导航
如果要后退到上一页面或多级页面,则需要指定 open-type 属性和 delta 属性,其中:
open-type
的值必须是 navigateBack,表示要进行后退导航delta
的值必须是数字,表示要后退的层级
<navigator open-type="navigateBack" delta="1" >返回上一页</navigator>
注意
:为了简便,如果只是后退到上一页面,则可以省略 delta 属性,因为其默认值就是 1。
4、声明式导航传参
navigator 组件的 url 属性用来指定将要跳转到的页面的路径。同时,路径的后面还可以携带参数:
参数与路径之间使用
?
分隔,参数键与参数值用=
相连,不同参数用&
分隔
<navigator url="/pages/info/info?name=zs&age=20" open-type="navigate">导航到info页面</navigator>
编程式导航
1、导航到 tabBar 页面
wx.switchTab(Object object)
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
url | string | 是 | 需要跳转的 tabBar 页面的路径 (代码包路径)(需在 app.json 的 tabBar 字段定义的页面),路径后不能带参数。 | |
success | function | 否 | 接口调用成功的回调函数 | |
fail | function | 否 | 接口调用失败的回调函数 | |
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
示例
:
<button bindtap="gotoMessage">跳转到消息界面</button>
gotoMessage(){
wx.switchTab({
url: '/pages/message/message',
})
},
2、导航到非 tabBar 页面
wx.navigateTo(Object object)
保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。
使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
url | string | 是 | 需要跳转的应用内非 tabBar 的页面的路径 (代码包路径), 路径后可以带参数。参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔;如 ‘path?key=value&key2=value2’ | |
events | Object | 否 | 页面间通信接口,用于监听被打开页面发送到当前页面的数据。基础库 2.7.3 开始支持。 | |
success | function | 否 | 接口调用成功的回调函数 | |
fail | function | 否 | 接口调用失败的回调函数 | |
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
示例
:
<button bindtap="gotoInfo">跳转到信息界面</button>
gotoInfo(){
wx.navigateTo({
url: '/pages/info/info',
})
},
3、 后退导航
wx.navigateBack(Object object)
关闭当前页面,返回上一页面或多级页面。
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
delta | number | 1 | 否 | 返回的页面数,如果 delta 大于现有页面数,则返回到首页。 |
success | function | 否 | 接口调用成功的回调函数 | |
fail | function | 否 | 接口调用失败的回调函数 | |
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
示例
:
<button bindtap="goBack">后退</button>
goBack(){
wx.navigateBack()
},
onLoad(Object query)
onLoad(Object query)
在页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打开当前页面路径中的参数。
<navigator url="/pages/info/info?name=zs&age=20" open-type="navigate">导航到info页面</navigator>
一般我们会在data中定义一个query变量,然后通过this.setData
赋值给该变量,这样其他函数就可以使用该参数了。
onLoad(options) {
console.log(options);
this.setData({
query:options
})
},
10. 页面事件
onPullDownRefresh
在app.json
的window选项中或页面配置中将enablePullDownRefresh
设置为true
就可以启动下拉刷新。
在实际开发中,推荐使用第 2 种方式,为需要的页面单独开启下拉刷新的效果。
在页面的.js
文件中,通过 onPullDownRefresh()
函数即可监听当前页面的下拉刷新事件。
示例
:
<view>count的值为:{{count}}</view>
<button bindtap="addCount">加一</button>
addCount(){
this.setData({
count:this.data.count+1
})
},
onPullDownRefresh() {
this.setData({
count:0
})
},
stopPullDownRefresh
当处理完下拉刷新后,下拉刷新的 loading 效果会一直显示,不会主动消失,所以需要手动隐藏下拉刷新的loading 效果。
而调用 wx.stopPullDownRefresh()
可以自动停止当前页面的下拉刷新。
onPullDownRefresh() {
this.setData({
count:0
})
wx.stopPullDownRefresh();
},
onReachBottom
上拉触底是移动端的专有名词,通过手指在屏幕上的上拉滑动操作,从而加载更多数据的行为
在页面的 .js
文件中,通过 onReachBottom()
函数即可监听当前页面的上拉触底事件。
- 可以在
app.json
的window
选项中或页面配置中设置触发距离onReachBottomDistance
。 - 在触发距离内滑动期间,本事件只会被触发一次。
onReachBottom() {
console.log('触发了上拉触底事件');
},
案例
滑动页面快到达底部时触发onReachBottom事件,在 onReachBottom事件中请求数据
<view wx:for="{{colorList}}" wx:key="index" class="num-item" style="background-color: rgb({{item}});">{{item}}</view>
/* pages/contact/contact.wxss */
.num-item{
border: 1rpx solid #efefef;
border-radius: 8rpx;
line-height: 200rpx;
margin: 15px;
text-align: center;
box-shadow: 1rpx,1rpx,6rpx,#aaa;
}
data: {
colorList:[]
},
getColors(){
wx.showLoading({
title: '数据加载中...',
mask:true
})
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.hideLoading()
}
})
},
onLoad(options) {
this.getColors()
},
onReachBottom() {
this.getColors()
},
11. 生命周期
APP
包含如下三个生命周期函数,onLaunch
只运行一次,而onShow
、onHide
在小程序的生命周期中会运行多次
App({
//当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
onLaunch: function () {
console.log('onLaunch')
},
// 也可以使用 wx.onAppShow 绑定监听
//当小程序启动,或从后台进入前台显示,会触发 onShow
onShow: function (options) {
console.log('onShow');
},
// 也可以使用 wx.onAppHide 绑定监听
// 当小程序从前台进入后台,会触发 onHide
onHide: function () {
console.log('onHide');
},
})
注意
:Object wx.getLaunchOptionsSync()
可以获取小程序启动时的参数。
Page
注意
:对界面内容进行设置的 API 如wx.setNavigationBarTitle
,请在onReady之后进行。
函数 | 类型 | 说明 |
---|---|---|
onLoad | function | 监听页面加载,一个页面只调用一次 |
onShow | function | 监听页面显示 ,切换到前台 |
onReady | function | 监听页面初次渲染完成,一个页面只调用一次 |
onHide | function | 监听页面隐藏 |
onUnload | function | 监听页面卸载,一个页面只调用一次 |
12. WXS
WXS(WeiXin Script)
是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。
- WXS 与 JavaScript 是不同的语言,有自己的语法,并不和 JavaScript 一致。
- WXS 的运行环境和其他 JavaScript 代码是隔离的,WXS 中不能调用其他 JavaScript 文件中定义的函数,也不能调用小程序提供的API。
- WXS 函数不能作为组件的事件回调。
- 由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异
<!-- 错误 -->
<button bindtap="m2.toLower">按钮</button>
wxs 不支持类似于 ES6 及以上的语法形式:
不支持
:let、const、解构赋值、展开运算符、箭头函数、对象属性简写、etc…支持
:var 定义变量、普通 function 函数等类似于 ES5 的语法
wxs 遵循 CommonJS 规范:
module 对象
:每个 wxs 模块均有一个内置的 module 对象
module.exports
:通过该属性,可以对外共享本模块的私有变量与函数。
require() 函数
:在.wxs模块中引用其他 wxs 文件模块,可以使用 require 函数。
(1)只能引用 .wxs 文件模块,且必须使用相对路径。
(2)wxs 模块均为单例,wxs 模块在第一次被引用时,会自动初始化为单例对象。多个页面,多个地方,多次引用,使用的都是同一个 wxs 模块对象。
(3)如果一个 wxs 模块在定义之后,一直没有被引用,则该模块不会被解析与运行。
WXS 代码可以编写在 wxml 文件中的<wxs>
标签内,或以.wxs
为后缀名的文件内
每一个
.wxs
文件和<wxs>
标签都是一个单独的模块。每个模块都有自己独立的作用域。即在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见。一个模块要想对外暴露其内部的私有变量与函数,只能通过module.exports
实现
内嵌WXS脚本
wxs 代码可以编写在 wxml 文件中的 <wxs>
标签内,就像 Javascript 代码可以编写在 html 文件中的<script>
标签内一样。
wxs标签
的参数有:
module
:当前<wxs>
标签的模块名(必填字段)。src
:引用.wxs
文件的相对路径。仅当本标签为单闭合标签或标签的内容为空时有效。
内联式 WXS如下:
<view>{{m1.toUpper(username)}}</view>
<view>{{m1.msg}}</view>
<wxs module='m1'>
function toUpper(str){
return str.toUpperCase();
}
var msg='success';
// 不能使用对象的简写形式
module.exports={
toUpper:toUpper,
msg:msg
}
</wxs>
外联WXS脚本
wxs 代码还可以编写在以 .wxs
为后缀名的文件内,就像 javascript 代码可以编写在以.js
为后缀名的文件中一样
tools.js
function toLower(str){
return str.toLowerCase()
}
module.exports={
toLower:toLower
}
引入并使用
<!-- <wxs src="../../utils/tools.wxs" module="m2"></wxs> -->
<wxs src="../../utils/tools.wxs" module="m2"/>
<view>{{m2.toLower(username)}}</view>
13. 组件
自定义组件
1、创建组件
- 在项目的根目录中,鼠标右键,创建 components -> test 文件夹
- 在新建的 components -> test 文件夹上,鼠标右键,点击“新建 Component”
- 键入组件的名称之后回车,会自动生成组件对应的 4 个文件,后缀名分别为
.js
,.json
,.wxml
和.wxss
。
2、引用组件
- 局部引用:组件只能在当前被引用的页面内使用。在页面的
.json
配置文件中引用组件的方式,叫做局部引用
{
"usingComponents": {
"my-test1":"/components/test/test"
}
}
- 全局引用:组件可以在每个小程序页面中使用。在
app.json
全局配置文件中引用组件的方式,叫做全局引用
。
"usingComponents": {
"my-test2":"./components/test/test"
},
3、组件和页面的区别
从表面来看,组件和页面都是由 .js、.json、.wxml 和 .wxss 这四个文件组成的。但是,组件和页面的 .js
与.json
文件有明显的不同:
- 组件的
.json
文件中需要声明"component": true
属性 - 组件的
.js
文件中调用的是Component()
函数 - 组件的事件处理函数需要定义到
methods
节点中
4、组件样式隔离
默认情况下,自定义组件的样式只受到自定义组件 wxss 的影响。除非以下两种情况:
(1)app.wxss
或页面的wxss
中使用了标签名选择器
(id 选择器、属性选择器或一些其他特殊选择器)来直接指定样式,这些选择器会影响到页面和全部组件。
(2)指定特殊的样式隔离选项 styleIsolation
。
// .js文件
Component({
options: {
styleIsolation: 'isolated'
}
})
// 或在.json 文件
"styleIsolation":"shared"
styleIsolation
选项从基础库版本 2.6.5 开始支持。它支持以下取值:
isolated
表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(默认值);apply-shared
表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面;shared
表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。(这个选项在插件中不可用。)
methon
在小程序组件中,事件处理函数和自定义方法需要定义到 methods 节点中,建议自定义方法以_开头(如_showCount
),用于区分自定义方法和事件处理函数。
properties
在小程序组件中,properties 是组件的对外属性,用来接收外界传递到组件中的数据
properties: {
max1:{
type:Number,
value:10
},
max2:Number
},
<my-test2 max1="20" max2="30">hhh</my-test2>
执行如下代码,发现data和properties指向同一个对象
console.log(this.data===this.properties); //true
console.log(this.data);
console.log(this.properties);
properties
属性的值也可以用于页面渲染,或使用 setData 为 properties 中的属性重新赋值
数据监听
数据监听器可以用于监听和响应任何属性和数据字段的变化。
数据监听器监听的是 setData 涉及到的数据字段,即使这些数据字段的值没有发生变化,数据监听器依然会被触发。
如果在数据监听器函数中使用 setData 设置本身监听的数据字段,可能会导致死循环。
observers: {
'numberA, numberB': function(numberA, numberB) {
// 在 numberA 或者 numberB 被设置时,执行这个函数
this.setData({
sum: numberA + numberB
})
}
}
注意
:如果监听的是对象,当对象的属性发生变化时,监听事件不会被触发。
数据监听器支持监听属性或内部数据的变化,可以同时监听多个
Component({
observers: {
'some.subfield': function(subfield) {
// 使用 setData 设置 this.data.some.subfield 时触发
// (除此以外,使用 setData 设置 this.data.some 也会触发)
subfield === this.data.some.subfield
},
'arr[12]': function(arr12) {
// 使用 setData 设置 this.data.arr[12] 时触发
// (除此以外,使用 setData 设置 this.data.arr 也会触发)
arr12 === this.data.arr[12]
},
}
})
如果需要监听所有子数据字段的变化,可以使用通配符**
。
observers: {
'some.field.**': function(field) {
// 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发
// (除此以外,使用 setData 设置 this.data.some 也会触发)
field === this.data.some.field
},
},
仅使用通配符 **
可以监听全部 setData 。
observers: {
'**': function() {
// 每次 setData 都触发
},
}
纯数据字段
有些情况下,某些 data 中的字段(包括 setData 设置的字段)既不会展示在界面上,也不会传递给其他组件,仅仅在当前组件内部使用。此时,可以指定这样的数据字段为纯数据字段
,它们将仅仅被记录在 this.data 中,而不参与任何界面渲染过程,这样有助于提升页面更新性能。
指定
纯数据字段
的方法是在 Component 构造器的 options 定义段中指定 pureDataPattern 为一个正则表达式,字段名符合这个正则表达式的字段将成为纯数据字段。
Component({
options: {
pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
},
data: {
a: true, // 普通数据字段
_b: true, // 纯数据字段
},
properties: {
c: Boolean,
_d: Boolean
}
methods: {
myMethod() {
this.data._b // 纯数据字段可以在 this.data 中获取
this.setData({
c: true, // 普通数据字段
_d: true, // 纯数据字段
})
}
}
})
组件的生命周期
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。
最重要的生命周期是 created
、attached
、detached
,包含一个组件实例生命流程的最主要时间点。
created
:组件实例刚刚被创建好时, created 生命周期被触发。此时,组件数据 this.data 就是在 Component 构造器中定义的数据 data 。 此时还不能调用 setData 。 通常情况下,这个生命周期只应该用于给组件 this 添加一些自定义属性字段。attached
:在组件完全初始化完毕、进入页面节点树后, attached 生命周期被触发。此时, this.data 已被初始化为组件的当前值。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。detached
:在组件离开页面节点树后, detached 生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则 detached 会被触发。
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
created | 无 | 在组件实例刚刚被创建时执行 | 1.6.3 |
attached | 无 | 在组件实例进入页面节点树时执行 | 1.6.3 |
ready | 无 | 在组件在视图层布局完成后执行 | 1.6.3 |
moved | 无 | 在组件实例被移动到节点树另一个位置时执行 | 1.6.3 |
detached | 无 | 在组件实例被从页面节点树移除时执行 | 1.6.3 |
error | Object Error | 每当组件方法抛出错误时执行 | 2.4.1 |
在小程序组件中,生命周期函数可以直接定义在 Component 构造器的第一级参数中,可以在 lifetimes
字段内进行声明(这是推荐的方式,其优先级最高)。示例代码如下:
Component({
lifetimes: {
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
},
// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
// ...
})
有时,自定义组件的行为依赖于页面状态的变化,此时就需要用到组件所在页面的生命周期。组件所在页面的生命周期在 pageLifetimes
定义段中定义。
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
show | 无 | 组件所在的页面被展示时执行 | 2.2.3 |
hide | 无 | 组件所在的页面被隐藏时执行 | 2.2.3 |
resize | Object Size | 组件所在的页面尺寸变化时执行 | 2.4.0 |
Component({
pageLifetimes: {
show: function() {
// 页面被展示
},
hide: function() {
// 页面被隐藏
},
resize: function(size) {
// 页面尺寸变化
}
}
})
behaviors
behaviors
是用于组件间代码共享的特性,类似于一些编程语言中的 mixins
。
每个 behavior 可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。
每个组件可以引用多个 behavior ,behavior 也可以引用其它 behavior
// my-component.js
var myBehavior = require('my-behavior')
Component({
behaviors: [myBehavior],
properties: {
myProperty: {
type: String
}
},
data: {
myData: 'my-component-data'
},
created: function () {
console.log('[my-component] created')
},
attached: function () {
console.log('[my-component] attached')
},
ready: function () {
console.log('[my-component] ready')
},
methods: {
myMethod: function () {
console.log('[my-component] log by myMethod')
},
}
})
而 my-behavior 结构为:
// my-behavior.js
module.exports = Behavior({
behaviors: [],
properties: {
myBehaviorProperty: {
type: String
}
},
data: {
myBehaviorData: {}
},
methods: {
myBehaviorMethod: function(){}
}
})
生命周期函数:attached、created、ready
这将使 my-component 最终结构为:
属性:myBehaviorProperty、myProperty
数据字段:myBehaviorData、myData
方法:myBehaviorMethod、myMethod
生命周期函数:attached、created、ready
当组件触发生命周期时,上例生命周期函数执行顺序为:
[my-behavior] created
[my-component] created
[my-behavior] attached
[my-component] attached
[my-behavior] ready
[my-component] ready
如果同一个 behavior 被一个组件多次引用,它定义的生命周期函数只会被执行一次
内置 behaviors: 自定义组件可以通过引用内置的 behavior 来获得内置组件的一些行为。
Component({
// 它使得这个自定义组件有类似于表单控件的行为
behaviors: ['wx://form-field']
})
其他内置behaviors 可查看官方文档
slot
在自定义组件的 wxml 结构中,可以提供一个 <slot>
节点(插槽),用于承载组件使用者提供的 wxml 结构。一个插槽里可以放多个标签
<!-- 组件模板 -->
<view class="wrapper">
<view>这里是组件的内部节点</view>
<slot></slot>
</view>
<!-- 引用组件的页面模板 -->
<view>
<component-tag-name>
<!-- 这部分内容将被放置在组件 <slot> 的位置上 -->
<view>这里是插入到组件 slot 中的内容</view>
</component-tag-name>
</view>
默认情况下,一个组件的 wxml 中只能有一个 slot
。需要使用多 slot 时,可以在组件 js 中声明启用。
Component({
options: {
multipleSlots: true // 在组件定义时的选项中启用多 slot 支持
},
properties: { /* ... */ },
methods: { /* ... */ }
})
在这个组件的 wxml 中使用多个 slot ,以不同的 name 来区分。
<!-- 组件模板 -->
<view class="wrapper">
<slot name="before"></slot>
<view>这里是组件的内部细节</view>
<slot name="after"></slot>
</view>
使用时,用 slot 属性来将节点插入到不同的 slot 上。
<!-- 引用组件的页面模板 -->
<view>
<component-tag-name>
<!-- 这部分内容将被放置在组件 <slot name="before"> 的位置上 -->
<view slot="before">这里是插入到组件slot name="before"中的内容</view>
<!-- 这部分内容将被放置在组件 <slot name="after"> 的位置上 -->
<view slot="after">这里是插入到组件slot name="after"中的内容</view>
</component-tag-name>
</view>
组件间通信
属性绑定
:用于父组件向子组件的指定属性设置数据,仅能设置 JSON 兼容的数据事件绑定
:用于子组件向父组件传递数据,可以传递任意数据。获取组件实例
:父组件还可以通过this.selectComponent
方法获取子组件实例对象,这样就可以直接访问组件的任意数据和方法。
属性绑定
具体使用可查看13大点中的 properties
事件绑定
home.wxml
在父组件的 wxml 中,通过自定义事件的形式,将函数引用传递给子组件
<my-test4 bind:sync="syncCount"></my-test4>
home.js
syncCount(e){
console.log(e);
},
test4.wxml
<button bindtap="onTap">111</button>
test4.js
在子组件的 js 中,通过调用 this.triggerEvent('自定义事件名称', obj)
,将数据发送到父组件
onTap(){
var q={
student:'xxx'
}
this.triggerEvent('sync',q)
}
输出如下:
在父组件的 js 中,通过 e.detail
获取到子组件传递过来的数据
获取组件实例
可在父组件里调用 this.selectComponent
,获取子组件的实例对象。调用时需要传入一个匹配选择器 selector,如:this.selectComponent(".my-component")
。
<my-test4 class="test4"></my-test4>
<button bindtap="onTap">222</button>
onTap(){
const child = this.selectComponent('.test4')
console.log(child);
},