1.1 mobx-miniprogram 介绍
目前已经学习了 6 种小程序页面、组件间的数据通信方案,分别是:
- 数据绑定:
properties
- 获取组件实例:
this.selectComponent()
- 事件绑定:
this.triggerEvent()
- 获取应用实例:
getApp()
- 页面间通信:
EventChannel
- 事件总线:
pubsub-js
在中小型项目中,使用这些数据通信方式已经能够满足我们项目的需求。
但是随着项目的业务逻辑越来越复杂,组件和页面间通信就会变的非常复杂。例如:有些状态需要在多个页面间进行同步使用,一个地方发生变更,所有使用的地方都需要发生改变,这时候如果使用前面的数据通信方案进行传递数据,给管理和维护将存在很大的问题。
为了方便进行页面、组件之间数据的传递,小程序官方提供了一个扩展工具库: mobx-miniprogram
mobx-miniprogram
是针对微信小程序开发的一个简单、高效、轻量级状态管理库,它基于Mobx
状态管理框架实现。
使用 mobx-miniprogram
定义管理的状态是响应式的,当状态一旦它改变,所有关联组件都会自动更新相对应的数据
通过该扩展工具库,开发者可以很方便地在小程序中全局共享的状态,并自动更新视图组件,从而提升小程序的开发效率
需要注意:在使用 mobx-miniprogram
需要安装两个包:mobx-miniprogram
和 mobx-miniprogram-bindings
-
mobx-miniprogram
的作用:创建Store
对象,用于存储应用的数据 -
mobx-miniprogram-bindings
的作用:将状态和组件、页面进行绑定关联,从而在组件和页面中操作数据
npm install mobx-miniprogram mobx-miniprogram-bindings
官方文档:
-
mobx-miniprogram 官方文档
-
mobx-miniprogram-bindings 官方文档
1.2 创建 Store 对象
如果需要创建 Store 对象需要使用 mobx-miniprogram
,因此需要先熟悉 mobx-miniprogram
三个核心概念:
-
observable
:用于创建一个被监测的对象,对象的属性就是应用的状态(state),这些状态会被转换成响应式数据。 -
action
:用于修改状态(state)的方法,需要使用 action 函数显式的声明创建。 -
computed
:根据已有状态(state)生成的新值。计算属性是一个方法,在方法前面必须加上get
修饰符
mobx-miniprogram
详细的使用步骤如下:
-
在项目的根目录下创建
store
文件夹,然后在该文件夹下新建index.js
-
在
/store/index.js
导入observable
、action
方法import { observable, action } from 'mobx-miniprogram'
-
使用
observable
方法需要接受一个store
对象,存储应用的状态// observable:用于创建一个被监测的对象,对象的属性就是应用的状态(state),这些状态会被转换成响应式数据。 // action:用于显式的声明创建更新 state 状态的方法 import { observable, action } from 'mobx-miniprogram' // 使用 observable 创建一个被监测的对象 export const numStore = observable({ // 创建应用状态 numA: 1, numB: 2, // 使用 action 更新 numA 以及 numB update: action(function () { this.numA+=1 this.numB+=1 }), // 计算属性,使用 get 修饰符, get sum() { return this.numA + this.numB; } })
1.3 在组件中使用数据
如果需要 Page
或者Component
中对共享的数据进行读取、更新操作,需要使用 mobx-miniprogram-bindings
mobx-miniprogram-bindings
的作用就是将 Store
和 页面或组件进行绑定关联
如果需要在组件中使用状态,需要 mobx-miniprogram-bindings
库中导入 ComponentWithStore
方法
在使用时:需要将 Component
方法替换成 ComponentWithStore
方法 ,原本组件配置项也需要写到该方法中
在替换以后,就会新增一个 storeBindings
配置项,配置项常用的属性有以下三个:
-
store
: 指定要绑定的Store
对象 -
fields
: 指定需要绑定的data
字段 -
actions
: 指定需要映射的actions
方法
???? 注意事项:
导入的数据会同步到组件的 data 中
导入的方法会同步到组件的 methods 中
// components/custom01/custom01.js
import { ComponentWithStore } from 'mobx-miniprogram-bindings'
import { numStore } from '../../stores/numstore'
ComponentWithStore({
data: {
someData: '...'
},
storeBindings: {
store: numStore,
fields: ['numA', 'numB', 'sum'],
actions: ['update']
}
})
1.4 在页面中使用数据-方式1
Component 方法用于创建自定义组件。
小程序的页面也可以视为自定义组件,因此页面也可以使用 Component 方法进行构建,从而实现复杂的页面逻辑开发。
如果我们使用了 Component 方法来构建页面,那么页面中如果想使用 Store
中的数据,使用方式和组件的使用方式是一样的
- 从
mobx-miniprogram-bindings
库中导入ComponentWithStore
方法 - 将
Component
方法替换成ComponentWithStore
方法 - 然后配置
storeBindings
从Store
中映射数据和方法即可
// index/index.js
import { ComponentWithStore } from 'mobx-miniprogram-bindings'
import { numStore } from '../../stores/numstore'
ComponentWithStore({
data: {
someData: '...'
},
storeBindings: {
store: numStore,
fields: ['numA', 'numB', 'sum'],
actions: ['update']
}
})
1.5 在页面中使用数据-方式2
在上一节,我们使用了 Component 方法构建页面,然后使用 ComponentWithStore
方法让页面和 Store
建立了关联
如果不想使用 Component 方法构建页面。这时候需要使用 mobx-miniprogram-bindings
提供的 BehaviorWithStore
方法来和 Store
建立关联。
小程序的 behavior 方法是一种代码复用的方式,可以将一些通用的逻辑和方法提取出来,然后在多个组件中复用,从而减少代码冗余,提高代码的可维护性。在页面中也可以使用 behaviors
配置项
使用方式如下:
- 新建
behavior
文件,从mobx-miniprogram-bindings
库中导入BehaviorWithStore
方法 - 在
BehaviorWithStore
方法中配置storeBindings
配置项从Store
中映射数据和方法 - 在
Page
方法中导入创建的behavior
,然后配置behavior
属性,并使用导入的behavior
// behavior.js
import { BehaviorWithStore } from 'mobx-miniprogram-bindings'
import { numStore } from '../../stores/numstore'
export const indexBehavior = BehaviorWithStore({
storeBindings: {
store: numStore,
fields: ['numA', 'numB', 'sum'],
actions: ['update'],
}
})
// index.js
import { indexBehavior } from './behavior'
Page({
behaviors: [indexBehavior]
// 其他配置项
})
1.6 fields、actions 对象写法
fields
、actions
有两种写法:数组 或者 对象。
如果 fields
写成对象方式,有两种写法:
-
映射形式:指定 data 中哪些字段来源于
store
以及它们在store
中对应的名字。- 例如
{ a: 'numA', b: 'numB' }
- 例如
-
函数形式:指定 data 中每个字段的计算方法
- 例如
{ a: () => store.numA, b: () => anotherStore.numB }
- 例如
如果 actions
写成对象方式,只有两种写法:
- 映射形式:指定模板中调用的哪些方法来源于
store
以及它们在store
中对应的名字。- 例如
{ buttonTap: 'update' }
- 例如
import { ComponentWithStore } from 'mobx-miniprogram-bindings'
import { numStore } from '../../stores/numstore'
ComponentWithStore({
data: {
someData: '...'
},
storeBindings: {
store: numStore,
fields: {
// 使用函数方式获取 Store 中的数据
a: () => store.numA,
b: () => store.numB,
// 使用映射形式获取 Store 中的数据,值为数据在 store 中对应的名字
total: 'sub'
},
// 使用映射形式获取 Store 中的 action 名字
actions: {
// key 自定义,为当前组件中调用的方法
// 值为 store 中对应的 action 名字
buttonTap: 'update'
}
}
})
1.7 绑定多个 store 以及命名空间
在实际开发中,一个页面或者组件可能会绑定多个 Store
,这时候我们可以将 storeBindings
改造成数组。数组每一项就是一个个要绑定的 Store
。
如果多个 Store
中存在相同的数据,显示会出现异常。还可以通过 namespace
属性给当前 Store
开启命名空间,在开启命名空间以后,访问数据的时候,需要加上 namespace
的名字才可以。
// behavior.js
import { BehaviorWithStore } from 'mobx-miniprogram-bindings'
import { numStore } from '../../stores/numstore'
export const indexBehavior = BehaviorWithStore({
storeBindings: [
{
namespace: 'numStore',
store: numStore,
fields: ['numA', 'numB', 'sum'],
actions: ['update'],
}
]
})
// index/index.wxml
<view>{{ numStore.numA }} + {{ numStore.numB }} = {{numStore.sum}}</view>
02. miniprogram-computed
小程序框架没有提供计算属性相关的 api ,但是官方为开发者提供了拓展工具库 miniprogram-computed。
该工具库提供了两个功能:
- 计算属性
computed
- 监听器
watch
2.1 计算属性 computed
知识点:
如果需要在组件中使用计算属性功能,需要 miniprogram-computed
库中导入 ComponentWithComputed
方法
在使用时:需要将 Component
方法替换成 ComponentWithComputed
方法 ,原本组件配置项也需要写到该方法中
在替换以后,就可以新增 computed
以及 watch
配置项。
安装 miniprogram-computed
, 在安装以后,需要点击 构建 npm
,进行本地构建
npm install miniprogram-computed
???? 注意事项:
computed
函数中不能访问 this ,但是提供了形参,代表data
对象 计算属性函数的返回值会被设置到 this.data.sum 字段中
官方文档:miniprogram-computed
落地代码:
计算属性 computed
的使用
// component.js
// 引入 miniprogram-computed
import { ComponentWithComputed } from 'miniprogram-computed'
ComponentWithComputed({
data: {
a: 1,
b: 1
},
computed: {
total(data) {
// 注意:
// computed 函数中不能访问 this ,只有 data 对象可供访问
// 这个函数的返回值会被设置到 this.data.sum 字段中
// 计算属性具有缓存,计算属性使用多次,但是计算属性方法只会执行一次
console.log('~~~~~')
return data.a + data.b
}
}
})
2.2 监听器 watch
在使用时:需要将 Component
方法替换成 ComponentWithComputed
方法 ,原本组件配置项也需要写到该方法中
在替换以后,就可以新增 computed
以及 watch
配置项。
// 引入 miniprogram-computed
import { ComponentWithComputed } from 'miniprogram-computed'
ComponentWithComputed({
data: {
a: 1,
b: 1
},
computed: {
total(data) {
// 注意:
// computed 函数中不能访问 this ,只有 data 对象可供访问
// 这个函数的返回值会被设置到 this.data.sum 字段中
return data.a + data.b
}
}
watch: {
// 同时对 a 和 b 进行监听
'a, b': function (a, b) {
this.setData({
total: a + b
})
}
},
methods: {
updateData() {
this.setData({
a: this.data.a + 1,
b: this.data.b + 1
})
}
}
})
拓展:Mobx 与 Computed 结合使用
两个框架扩展提供的 ComponentWithStore
与 ComponentWithComputed
方法无法结合使用。
如果需要在一个组件中既想使用 mobx-miniprogram-bindings
又想使用 miniprogram-computed
解决方案是:
-
使用旧版
API
-
自定义组件仍然使用
Component
方法构建组件,将两个扩展依赖包的使用全部改为旧版API
-
mobx-miniprogram-bindings 官方文档
-
miniprogram-computed 官方文档
-
-
使用兼容写法
-
即要么使用
ComponentWithStore
方法构建组件,要么使用ComponentWithComputed
方法构建组件 -
如果使用了
ComponentWithStore
方法构建组件,计算属性写法使用旧版API
-
如果使用了
ComponentWithComputed
方法构建组件,Mobx写法使用旧版API
-
我们演示使用兼容写法:
-
如果使用了
ComponentWithStore
方法构建组件,计算属性写法使用旧版API
import { ComponentWithComputed } from 'miniprogram-computed' // component.js const computedBehavior = require('miniprogram-computed').behavior ComponentWithStore({ behaviors: [computedBehavior], data: { a: 1, b: 1, sum: 2 }, watch: { 'a, b': function (a, b) { this.setData({ total: a + b }) } }, computed: { total(data) { // 注意: computed 函数中不能访问 this ,只有 data 对象可供访问 // 这个函数的返回值会被设置到 this.data.sum 字段中 return data.a + data.b + data.sum // data.c 为自定义 behavior 数据段 } }, // 实现组件和 Store 的关联 storeBindings: { store: numStore, // fields 和 actions 有两种写法:数组写法 和 对象写法 // 数组写法 fields: ['numA', 'numB', 'sum'], actions: ['update'] } })
-
使用了
ComponentWithComputed
方法构建组件,Mobx写法使用旧版API
import { ComponentWithComputed } from 'miniprogram-computed' // 导入 storeBindingsBehavior 方法实现组件和 Store 的关联 import { storeBindingsBehavior } from "mobx-miniprogram-bindings" // 导入 Store import { numStore } from '../../stores/numstore' ComponentWithComputed({ behaviors: [storeBindingsBehavior], data: { a: 1, b: 1, sum: 2 }, watch: { 'a, b': function (a, b) { this.setData({ total: a + b }) } }, computed: { total(data) { // 注意: computed 函数中不能访问 this ,只有 data 对象可供访问 // 这个函数的返回值会被设置到 this.data.sum 字段中 return data.a + data.b + data.sum // data.c 为自定义 behavior 数据段 } }, // 实现组件和 Store 的关联 storeBindings: { store: numStore, // fields 和 actions 有两种写法:数组写法 和 对象写法 // 数组写法 fields: ['numA', 'numB', 'sum'], actions: ['update'] } })