目录
什么是生命周期函数
WXS脚本
编辑
与 JavaScript 不同
纯数据字段
组件生命周期
定义生命周期方法
代码示例
组件所在页面的生命周期
代码示例
插槽
什么是插槽
启用多插槽
编辑 定义多插槽
组件通信
组件间通信
监听事件
触发事件
获取组件实例
自定义的组件实例获取结果
Behaviors
使用npm包
Vant组件库
使用 Vant 组件
API Promise化
全局数据共享
Store中的成员绑定到页面中:
Store中的成员绑定到组件中:
在组件中使用Store中的成员
分包
什么是分包
分包的好处
生命周期函数:是由小程序框架提供的内置函数,会伴随着生命周期,自动按次序执行。
生命周期函数的作用:允许程序员在特定的时间点,执行某些特定的操作。例如,页面刚加载的时候,可以在 onLoad 生命周期函数中初始化页面的数据。
注意:生命周期强调的是时间段,生命周期函数强调的是时间点。
2.外联wxs脚本
为了降低 wxs(WeiXin Script)的学习成本, wxs 语言在设计时借大量鉴了 JavaScript 的语法。但是本质上, wxs 和 JavaScript 是完全不同的两种语言
不能作为组件的事件回调
wxs 典型的应用场景就是“过滤器”,经常配合 Mustache 语法进行使用, 但是,在 wxs 中定义的函数不能作为组件的事件回调函数。例如,下面的用法是错误的:
隔离性指的是 wxs 的运行环境和其他 JavaScript 代码是隔离的。体现在如下两方面:
① wxs 不能调用 js 中定义的函数
② wxs 不能调用小程序提供的 API
性能好
⚫ 在 iOS 设备上,小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍
⚫ 在 android 设备上,二者的运行效率无差异
通配符监听对象的属性RGB,这里面的rgb.r,rgb.g,rgb.b都没有用于界面的渲染
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。
其中,最重要的生命周期是 created
attached
detached
,包含一个组件实例生命流程的最主要时间点。
created
生命周期被触发。此时,组件数据 this.data
就是在 Component
构造器中定义的数据 data
。 此时还不能调用 setData
。 通常情况下,这个生命周期只应该用于给组件 this
添加一些自定义属性字段。attached
生命周期被触发。此时, this.data
已被初始化为组件的当前值。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。detached
生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则 detached
会被触发。 生命周期方法可以直接定义在 Component
构造器的第一级参数中。
自小程序基础库版本 2.2.3 起,组件的的生命周期也可以在 lifetimes
字段内进行声明(这是推荐的方式,其优先级最高)。
Component({
lifetimes: {
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
},
// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
// ...
})
在 behaviors 中也可以编写生命周期方法,同时不会与其他 behaviors 中的同名生命周期相互覆盖。但要注意,如果一个组件多次直接或间接引用同一个 behavior ,这个 behavior 中的生命周期函数在一个执行时机内只会执行一次。
可用的全部生命周期如下表所示。
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
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 |
还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes
定义段中定义。其中可用的生命周期包括:
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
show | 无 | 组件所在的页面被展示时执行 | 2.2.3 |
hide | 无 | 组件所在的页面被隐藏时执行 | 2.2.3 |
resize | Object Size |
组件所在的页面尺寸变化时执行 | 2.4.0 |
routeDone | 无 | 组件所在页面路由动画完成时执行 | 2.31.2 |
注意:自定义 tabBar 的 pageLifetime 不会触发。
Component({
pageLifetimes: {
show: function() {
// 页面被展示
},
hide: function() {
// 页面被隐藏
},
resize: function(size) {
// 页面尺寸变化
}
}
})
组件间的基本通信方式有以下几种。
this.selectComponent
方法获取子组件实例对象,这样就可以直接访问组件的任意数据和方法。事件系统是组件间通信的主要方式之一。自定义组件可以触发任意的事件,引用组件的页面可以监听这些事件。关于事件的基本概念和用法,参见 事件 。
监听自定义组件事件的方法与监听基础组件事件的方法完全一致:
代码示例:
Page({
onMyEvent: function(e){
e.detail // 自定义组件触发事件时提供的detail对象
}
})
自定义组件触发事件时,需要使用 triggerEvent
方法,指定事件名、detail对象和事件选项:
代码示例:
在开发者工具中预览效果
Component({
properties: {},
methods: {
onTap: function(){
var myEventDetail = {} // detail对象,提供给事件监听函数
var myEventOption = {} // 触发事件的选项
this.triggerEvent('myevent', myEventDetail, myEventOption)
}
}
})
触发事件的选项包括:
选项名 | 类型 | 是否必填 | 默认值 | 描述 |
---|---|---|---|---|
bubbles | Boolean | 否 | false | 事件是否冒泡 |
composed | Boolean | 否 | false | 事件是否可以穿越组件边界,为false时,事件将只能在引用组件的节点树上触发,不进入其他任何组件内部 |
capturePhase | Boolean | 否 | false | 事件是否拥有捕获阶段 |
关于冒泡和捕获阶段的概念,请阅读 事件 章节中的相关说明。
代码示例:
在开发者工具中预览效果
// 页面 page.wxml
// 组件 another-component.wxml
// 组件 my-component.wxml
// 组件 my-component.js
Component({
methods: {
onTap: function(){
this.triggerEvent('customevent', {}) // 只会触发 pageEventListener2
this.triggerEvent('customevent', {}, { bubbles: true }) // 会依次触发 pageEventListener2 、 pageEventListener1
this.triggerEvent('customevent', {}, { bubbles: true, composed: true }) // 会依次触发 pageEventListener2 、 anotherEventListener 、 pageEventListener1
}
}
})
可在父组件里调用 this.selectComponent
,获取子组件的实例对象。
调用时需要传入一个匹配选择器 selector
,如:this.selectComponent(".my-component")
。
selector
详细语法可查看 selector 语法参考文档。
代码示例:
在开发者工具中预览效果
// 父组件
Page({
data: {},
getChildComponent: function () {
const child = this.selectComponent('.my-component');
console.log(child)
}
})
在上例中,父组件将会获取 class
为 my-component
的子组件实例对象,即子组件的 this
。
注意 :默认情况下,小程序与插件之间、不同插件之间的组件将无法通过 selectComponent
得到组件实例(将返回 null
)。如果想让一个组件在上述条件下依然能被 selectComponent
返回,可以自定义其返回结果(见下)。
若需要自定义 selectComponent
返回的数据,可使用内置 behavior
: wx://component-export
从基础库版本 2.2.3 开始提供支持。
使用该 behavior 时,自定义组件中的 export
定义段将用于指定组件被 selectComponent
调用时的返回值。
代码示例:
在开发者工具中预览效果
// 自定义组件 my-component 内部
Component({
behaviors: ['wx://component-export'],
export() {
return { myField: 'myValue' }
}
})
// 父组件调用
const child = this.selectComponent('#the-id') // 等于 { myField: 'myValue' }
在上例中,父组件获取 id
为 the-id
的子组件实例的时候,得到的是对象 { myField: 'myValue' }
。
子组件的‘sync’事件
behaviors
是用于组件间代码共享的特性,类似于一些编程语言中的 “mixins” 或 “traits”。
每个 behavior
可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。 每个组件可以引用多个 behavior
,behavior
也可以引用其它 behavior
。
Vant Weapp - 轻量、可靠的小程序 UI 组件库
安装完 Vant 组件库之后,可以在 app.json 的 usingComponents 节点中引入需要的组件,即可在 wxml 中 直接使用组件。
Vant Weapp 使用 CSS 变量来实现定制主题。 关于 CSS 变量的基本用法,请参考 MDN 文档: https://developer.mozilla.org/zh-CN/docs/Web/CSS/Using_CSS_custom_properties
默认情况下,小程序官方提供的异步 API 都是基于回调函数实现的,例如,网络请求的 API 需要按照如下的方 式调用:
缺点:容易造成回调地狱的问题,代码的可读性、维护性差!
async getInfo() {
const {data: res} = await wx.p.request({
method: 'GET',
url: 'https://applet-base-api-t.itheima.net/get',
data: {
name: 'zs',
age: 20
}
})
console.log(res)
},
1. 安装 MobX 相关的包
在项目中运行如下的命令,安装 MobX 相关的包: 注意:MobX 相关的包安装完毕之后,记得删除 miniprogram_npm 目录后,重新构建 npm。
// 在这个 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 中数据的值
updateNum1: action(function (step) {
this.numA += step
}),
updateNum2: action(function (step) {
this.numB += step
}),
updateActiveTabBarIndex: action(function(index) {
this.activeTabBarIndex = index
})
})
// pages/message/message.js
import { createStoreBindings } from 'mobx-miniprogram-bindings'
import { store } from '../../store/store'
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.storeBindings = createStoreBindings(this, {
store,
fields: ['numA', 'numB', 'sum'],
actions: ['updateNum1']
})
},
btnHandler1(e) {
// console.log(e)
this.updateNum1(e.target.dataset.step)
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
this.storeBindings.detroyStoreBindings()
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
{{numA}} + {{numB}} = {{sum}}
numA + 1
numA - 1
~~~~~~
// components/numbers/numbers.js
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
import { store } from '../../store/store'
Component({
behaviors: [storeBindingsBehavior],
storeBindings: {
// 数据源
store,
fields: {
numA: 'numA',
numB: 'numB',
sum: 'sum'
},
actions: {
updateNum2: 'updateNum2'
}
},
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
btnHandler2(e) {
this.updateNum2(e.target.dataset.step)
}
}
})
{{numA}} + {{numB}} = {{sum}}
numB + 1
numB - 1
分包指的是把一个完整的小程序项目,按照需求划分为不同的子包,在构建时打包成不同的分包,用户在使用 时按需进行加载
对小程序进行分包的好处主要有以下两点:
⚫ 可以优化小程序首次启动的下载时间
⚫ 在多团队共同开发时可以更好的解耦协
分包预下载指的是:在进入小程序的某个页面时,由框架自动预下载可能需要的分包,从而提升进入后续分包 页面时的启动速度
"preloadRule": {
"pages/contact/contact": {
"packages": [
"p1"
],
"network": "wifi" //指定网络(all是所有网路模式)
}
}