微信小程序第四天
1. 目标
- 能够知道如何自定义小程序组件
- 能够知道小程序组件中
behaviors的作用
2. 组件的创建和引用
2.1 创建自定义组件
创建组件
- 在项目的根目录中,鼠标右键,创建
components->test文件夹 - 在新建的
components->test文件夹上,鼠标右键,点击新建 Component - 键入组件的名称之后回车,会自动生成组件对应的 4 个文件,后缀名分别为
.js,.json,.wxml和.wxss - 注意:为了保证目录结构的清晰,建议把不同的组件,存放到单独目录中

- 在项目的根目录中,鼠标右键,创建
2.2 局部引用组件
组件的引用方式
- 组件的引用方式分为
局部引用和全局引用局部引用:组件只能在当前被引用的页面内使用全局引用:组件可以在每个小程序页面中使用
- 组件的引用方式分为
局部引用组件
- 在
页面的 .json配置文件中引用组件的方式,叫做局部引用
- 在

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

2.5 全局引用和局部引用的区别
- 根据组件的
使用频率和范围,来选择合适的引用方式:- 如果某组件
在多个页面中经常被用到,建议进行全局引用 - 如果某组件只
在特定的页面中被用到,建议进行局部引用
- 如果某组件
2.6 组件和页面的区别
- 从表面来看,组件和页面都是由
.js、.json、.wxml和.wxss这四个文件组成的。但是,组件和 页面的.js与.json文件有明显的不同:- 组件的 .json 文件中需要声明
"component": true属性 - 组件的 .js 文件中调用的是
Component()函数- 整个程序启动调用的是
App() - 某个页面的渲染调用的是
Page() - 某个组件的渲染调用的是
Component()
- 整个程序启动调用的是
- 组件的事件处理函数需要定义到
methods节点中
- 组件的 .json 文件中需要声明
3. 组件的数据、方法和属性
3.1 定义 data 私有数据
在小程序组件中,用于组件模板渲染的私有数据,需要定义到
data节点中
3.2 methods 方法
在小程序组件中,事件处理函数和自定义方法需要定义到
methods节点中
3.3 定义 properties 属性
在小程序组件中,
properties是组件的对外属性,用来接收外界(父组件)传递到组件中的数据
3.4 data 和 properties 的区别
- 在小程序的组件中,
properties属性和data数据的用法相同,它们都是可读可写的,只不过:data更倾向于存储组件的私有数据properties更倾向于存储外界传递到组件中的数据- 所以, 也不太建议修改
properties数据,如果要修改properties的数据, 最好通过子组件通信给父组件的方式实现

3.5 使用 setData 修改 properties 的值
- 由于
data数据和properties属性在本质上没有任何区别,因此properties属性的值也可以用于页面渲染,或使用setData为properties中的属性重新赋值

4. 数据监听器
4.1 什么是数据监听器以及其基础语法
什么是数据监听器
数据监听器用于监听和响应任何属性和数据字段的变化,从而执行特定的操作。它的作用类似于
vue中的watch侦听器。在小程序组件中,数据监听器的基本语法格式如下
4.2 数据监听器的基本用法
组件结构

组件的
js代码
完整代码
<view> {{ num1 }} + {{ num2 }} = {{ sum }} </view> <button type="warn" bindtap="addNum1">Num + 1</button> <button type="warn" bindtap="addNum2">Num + 2</button>// components/test/test.js Component({ /** * 组件的初始数据 */ data: { num1: 0, num2: 0, sum: 0 }, // 数据侦听器 observers: { 'num1, num2': function (newNum1, newNum2) { this.setData({ sum: newNum1 + newNum2 }) } }, /** * 组件的方法列表 */ methods: { addNum1 () { this.setData({ num1: this.data.num1 + 1 }) }, addNum2 () { this.setData({ num2: this.data.num2 + 1 }) } } })
4.3 监听对象属性的变化
数据监听器支持监听对象中单个或多个属性的变化

<button type="warn" bindtap="changeObj">监听对象的属性</button>
<view>{{ obj.name }}</view>
// components/test/test.js
Component({
// 组件的初始数据
data: {
obj: {
name: 'tom'
}
},
// 数据侦听器
observers: {
'obj.name': function (newName) {
console.log(newName)
}
},
// 方法列表
methods: {
changeObj() {
this.setData({
'obj.name': 'jerry'
})
}
}
})
5. 组件的生命周期
5.1 组件全部的生命周期函数
| 生命周期 | 参数 | 描述 |
|---|---|---|
created | 无 | 在组件实例刚刚被创建时执行 |
attached | 无 | 在组件实例进入页面节点树时执行 |
| ready | 无 | 在组件在视图层布局完成后执行 |
| moved | 无 | 在组件实例被移动到节点树另一个位置时执行 |
detached | 无 | 在组件实例被从页面节点树移除时执行 |
| error | Object Error | 每当组件方法抛出错误时执行 |
5.2 组件主要的生命周期函数
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。
最重要的生命周期是
created,attached,detached,包含一个组件实例生命流程的最主要时间点。组件实例刚刚被创建好时,
created生命周期被触发- 此时还不能调用
setData - 通常情况下,这个生命周期只应该用于给组件 this 添加一些自定义属性字段
- 此时还不能调用
在组件完全初始化完毕、进入页面节点树后,
attached生命周期被触发this.data已被初始化完毕- 这个生命周期很有用,绝大多数初始化工作可以在这个时机进行
在组件离开页面节点树后,
detached生命周期被触发- 退出一个页面时,会触发页面内每个自定义组件的
detached生命周期被触发 - 如果组件还在页面节点树中,则
detached会被触发。 - 此时适合做一些清理性质的工作
- 退出一个页面时,会触发页面内每个自定义组件的
5.3 lifetime 节点
- 生命周期方法可以直接定义在
Component构造器的第一级参数中,组件的的生命周期也可以在lifetimes字段内进行声明(这是推荐的方式,其优先级最高)

lifetimes: {
attached () {
console.log('在组件实例进入页面节点树')
},
detached () {
console.log('在组件实例被从页面节点树移除')
}
},
attached () {
console.log('~~~~~在组件实例进入页面节点树')
},
detached () {
console.log('~~~~~在组件实例被从页面节点树移除')
},
/**
* 组件的初始数据
*/
data: {
// rgb 的颜色值对象
_rgb: {
r: 0,
g: 0,
b: 0
},
// 根据 rgb 对象的三个属性,动态计算 fullColor 的值
fullColor: '0, 0, 0'
}
6. 组件所在页面的生命周期
6.1 什么是组件所在页面的生命周期
有时,自定义组件的行为依赖于页面状态的变化,此时就需要用到组件所在页面的生命周期
- 例如:每当触发页面的
show生命周期函数的时候,我们希望能够重新生成一个随机的RGB颜色值。在自定义组件中,组件所在页面的生命周期函数有如下 3 个,分别是
- 例如:每当触发页面的
| 生命周期 | 参数 | 描述 |
|---|---|---|
| show | 无 | 组件所在的页面被展示时执行 |
| hide | 无 | 组件所在的页面被隐藏时执行 |
| resize | Object Size | 组件所在的页面尺寸变化时执行 |
6.2 pageLifetimes 节点
组件所在页面的生命周期函数,需要定义在
pageLifetimes节点中
6.3 生成随机的 RGB 颜色值


Component({
// 在组件的methods节点中,定义一个随机颜色的方法
methods: {
_randomColor() {
// 设置data中的数据
this.setData({
_rgb: {
r: Math.floor(Math.random() * 256),
g: Math.floor(Math.random() * 256),
b: Math.floor(Math.random() * 256)
}
})
}
},
// 在组件内部的pageLifetimes节点中,监听组件在页面的生命周期函数
pageLifetimes: {
// 在页面被展示的时候,调用该方法
show() {
this._randomColor()
},
hide() { }, // 页面被隐藏
resize() { } // 页面尺寸变化
}
})
7. 插槽
7.1 什么是插槽
- 在自定义组件的
wxml结构中,可以提供一个 节点(插槽),用于承载组件使用者提供的wxml结构

- 其实插槽, 说的通俗一些, 就是
子组件挖坑,父组件填坑的过程。由父组件在使用子组件的时候, 决定子组件内部的某一些布局展示- 子组件通过挖坑
- 父组件通过组件标签中间的内容来填坑
7.2 单个插槽
- 在小程序中,默认每个自定义组件中只允许使用一个
slot占位,这种个数上的限制叫做单个插槽- 默认情况下,一个组件的
wxml中只能有一个slot - 需要使用多
slot时,可以在组件js中声明启用 - 注意:小程序中目前只有默认插槽和多个插槽,暂不支持作用域插槽
- 默认情况下,一个组件的

7.3 启动多个插槽
在小程序的自定义组件中,需要使用多 插槽时,可以在组件的 .js 文件中

7.4 定义多个插槽
可以在组件的 .wxml 中使用多个 标签,以不同的 name 来区分不同的插槽

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

- 接收数据
- 子组件在 properties 节点中声明对应的属性并使用

8.3 实现子组件的 count 属性自增 + 1
data: {
count: 0
}
addCount() {
this.setData({
count: this.data.count + 1
})
}
8.4 了解事件绑定的 4 个核心实现步骤
- 事件绑定用于实现子向父传值,可以传递任何类型的数据。使用步骤如下:
- 在
父组件的js中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件 - 在
父组件的wxml中,通过自定义事件的形式,将步骤 1 中定义的函数引用,传递给子组件 - 在
子组件的js中,通过调用this.triggerEvent('自定义事件名称', {/* 参数对象 */}),将数据发送到父组件 - 在父组件的
js中,通过e.detail获取到子组件传递过来的数据
- 在
8.5 了解事件绑定的核心实现代码
步骤 1: 在父组件的
js中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件
步骤 2:在父组件的
wxml中,通过自定义事件的形式,将 步骤 1 中定义的函数引用,传递给子组件
步骤 3:在
子组件的js中,通过调用this.triggerEvent('自定义事件名称', {/* 参数对象 */}),将数据发送到父组件
步骤 4:在父组件的
js中,通过e.detail获取到子组件传递过来的数据

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

9. 使用 npm
9.1 小程序对 npm 的支持和限制
目前,小程序中已经支持使用 npm 安装第三方包,从而来提高小程序的开发效率。但是,在小程序中使用 npm 包有如下 3 个限制:
不支持依赖于 Node.js 内置库的包
- 不支持依赖于 Node 核心模块的包
- fs Node 文件系统模块 – 不支持
- path Node 路径模块 – 不支持
不支持依赖于浏览器内置对象的包
- 小程序的宿主环境是微信,不存在 DOM 和 DOM
- 所以依赖于内置对象的包,也不能够使用
不支持依赖于 C++ 插件的包
总结:虽然 npm 上的包有千千万,但是能供小程序使用的包却“为数不多”
9.2 了解什么是 vant Weapp
Vant是有赞前端团队开源的移动端组件库,于 2016 年开源,已持续维护 4 年时间。Vant对内承载了有赞所有核心业务,对外服务十多万开发者,是业界主流的移动端组件库之一- 采用
MIT开源许可协议,对商业使用比较友好 - 扫描下方小程序二维码,体验组件库示例

9.3 安装 Vant 组件库
在小程序项目中,安装 Vant 组件库主要分为如下几步
通过
npm安装- 注意:项目目录不能存在中文!不能存在中文!不能存在中文!否则会报错 !
npm init -ynpm i @vant/weapp@1.3.3 -S --production构建
npm包功能如果提示构建失败,可以将微信开发者工具重启,重启以后,运行小程序项目,查看是否还报错
- 建议先点击
微信开发者工具-->详情-->本地设置-->使用 npm 模块 - 然后点击
微信开发者工具-->菜单栏-->工具-->构建npm - 提示
构建成功,耗时 xxx 秒且控制台没有任何的错误,说明包构建成功,可以进行使用- 否则就需要把
node_modules、miniprogram_npm删除 - 删除以后,重新安装包,并点击
工具-->构建npm,进行重新构建
- 否则就需要把
- 建议先点击
修改
app.json- 将
styles: v2进行移除,防止小程序本身的 UI 样式和 Vant 的组件样式库 冲突
- 将
详细的操作地址:安装 vant Weapp
9.4 使用 Vant 组件
安装完 Vant 组件库之后,可以在 app.json 的 usingComponents 节点中引入需要的组件,即可在 wxml 中直接使用组件

"usingComponents": {
"van-button": "@vant/weapp/button/index"
}
<van-button type="default">默认按钮</van-button>
<van-button type="primary">主要按钮</van-button>
<van-button type="info">信息按钮</van-button>
<van-button type="warning">警告按钮</van-button>
<van-button type="danger">危险按钮</van-button>
9.5 定义和使用 CSS 变量 (了解)
Vant Weapp使用CSS变量来实现定制主题。 关于CSS变量的基本用法,请参考MDN文档 文档地址
自定义属性(有时候也被称作CSS变量或者级联变量)是由CSS作者定义的,它包含的值可以在整个文档中重复使用由自定义属性标记设定值
声明一个自定义属性,属性名需要以两个减号(
--)开始,属性值则可以是任何有效的CSS值比如:
--main-color: black;
由var()函数来获取值
color: var(--main-color);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS 变量</title>
<style>
/* 变量可以声明在某个父级元素中 */
/* 如果是声明在父级元素中, 定义的变量只能够父级元素内部使用 */
.box {
/* css 变量要求,需要以 -- 开头,后面跟上变量名称 */
/* 属性值是合法的 css 属性值即可 */
--main-bg-color: blue;
}
.box {
width: 200px;
height: 200px;
border: 1px solid lightcoral;
/* 如果需要使用 css 变量 */
/* 使用 var() 去调用变量 */
background-color: var(--main-bg-color);
}
.box1 {
width: 200px;
height: 200px;
border: 1px solid lightcoral;
background-color: var(--main-bg-color);
}
</style>
</head>
<body>
<div class="box"></div>
<div class="box1"></div>
</body>
</html>
9.6 使用 CSS 变量定制 Vant 的主题样式 (了解)
在 app.wxss 中,写入 CSS 变量,即可对全局生效

所有可用的颜色变量,请参考 Vant 官方提供的配置文件
9.7 什么是小程序 API 的 Promise 化
基于回调函数的异步
API的缺点默认情况下,小程序官方提供的异步 API 都是基于回调函数实现的,例如,网络请求的 API 需要按照如下的方式调用
这种代码的缺点是显而易见的, 容易造成回调地狱的问题,代码的可读性、维护性差!而我们就想将这种类型的代码使用
API Promise化进行改造
什么是
API Promise化API Promise化,指的是通过额外的配置,将官方提供的、基于回调函数的异步API,升级改造为基于Promise的异步API,从而提高代码的可读性、维护性,避免回调地狱的问题
9.8 安装并构建 miniprogram-api-promise
在小程序中,实现
API Promise化主要依赖于miniprogram-api-promise这个第三方的npm包npm i --save miniprogram-api-promise@1.0.4下载完成,我们不能直接使用这个包,而是需要再次重新构建npm包
- 建议在构建前先删除原有的
miniprogram_npm - 然后再点击工具,构建
npm
- 建议在构建前先删除原有的
如果删除了
miniprogram_npm目录,构建还是失败- 需要把
node_modules、miniprogram_npm删除 - 删除以后,重新安装包,重新安装以后,再次进行构建
- 需要把
9.9 三个步骤实现 API 的 Promise 化

在小程序入口文件中调用一次
promisifyAll()方法import { promisifyAll } from 'miniprogram-api-promise'声明一个常量,为一个空对象
const wxp = wx.p = {}调用
promisifyAll()方法promisifyAll(wx, wxp)上述代码是什么含义呢 ?
promisifyAll: 做的事就是将wx拥有的属性方法都copy并改造了一份给了wxp这个对象- 然而,
wxp只是当前js文件的一个常量,只能在当前文件使用 - 因此:我们在
wx上挂载一个属性p让他和wxp指向同一个空对象 - 在其他页面或者组件就可以通过全局对象
wx点出p来访问到wxp - 此时
wx.p发起异步的请求时,得到的是一个promise对象 - 那么我们就可以使用
async/await简化Promise语法
// 1、导入 promisifyAll 这个方法
import { promisifyAll } from 'miniprogram-api-promise'
// 2、声明一个空对象 wxp
// wxp 只是一个单纯的变量,只能够在当前 js 中使用,外部不能使用
// wx 是微信小程序最顶级的对象
// 只需要往 wx 上去挂载一个对象即可
// 挂载好,以后 wxp 和 wx.p 指定的是同一个内存空间
// 也就是说 wxp 拷贝得到的 wx 的属性和方法
// wx.p 同样也是拥有的
// 调用方式: wx.p.xxxxx 即 wx.p.request({})
const wxp = wx.p = {}
// 3、promisifyAll 作用就是将 wx 内部的方法和属性深拷贝一份给 wxp 这个对象
promisifyAll(wx, wxp)
9.10 调用 Promise 化之后的异步 API

<van-button type="warning" bindtap="getInfo">警告按钮</van-button>
async getInfo () {
const { data: res } = await wx.p.request({
url: 'https://www.escook.cn/api/get',
method: 'GET',
data: {
name: 'zs',
age: 19
}
})
console.log(res)
}
- 此时
wx.p发起异步的请求时,得到的是一个promise对象 - 那么我们就可以使用
async/await简化Promise语法
// 1、导入 promisifyAll 这个方法
import { promisifyAll } from 'miniprogram-api-promise'
// 2、声明一个空对象 wxp
// wxp 只是一个单纯的变量,只能够在当前 js 中使用,外部不能使用
// wx 是微信小程序最顶级的对象
// 只需要往 wx 上去挂载一个对象即可
// 挂载好,以后 wxp 和 wx.p 指定的是同一个内存空间
// 也就是说 wxp 拷贝得到的 wx 的属性和方法
// wx.p 同样也是拥有的
// 调用方式: wx.p.xxxxx 即 wx.p.request({})
const wxp = wx.p = {}
// 3、promisifyAll 作用就是将 wx 内部的方法和属性深拷贝一份给 wxp 这个对象
promisifyAll(wx, wxp)
如有不足,请多指教,
未完待续,持续更新!
大家一起进步!