1.mobx-miniprogram介绍
小程序页面,组件之间的数据通信方案分别有以下几种
- 数据绑定: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
2.创建 Store对象
如果需要创建Store对象需要使用mobx-miniprogram,因此需要先熟悉mobx-miniprogram单个核心概念:
- observable:用于创建一个被检测的对象,对象的属性就是应用的状态(state),这些状态会被转换成响应式数据.
- action:用于修改(state)的方法,需要使用action函数显式的声明创建.
- computed:根据已有状态(state)生成的新值.计算属性是一个方法,在方法前面必须加上get修饰符
2.1.mobx-miniprogram详细的使用步骤如下:
- 在项目的根目录下创建Store文件夹,然后在该文件夹下面新建index.js
- 在 /store/index.js 导入observable ,action方法
//observable:用于创建一个被检测的对象,对象的属性就是应用的状态(state),这些状态会被转化成响应式数据. //action:函数是用来显示的定义action方法, action方法是用来修改,更新状态 import {observable ,action} form "mobx-miniprogram"
- 使用observable方法需要接受一个store对象,存储应用的状态
//开始创建Store对象 export const numStore = observable({ //对象的属性就是应用的状态 numA:1, numB:2, //定义action方法,用来修饰状态 update:action(function(){ //在方法中如果需要获取状态,可以使用this进行获取. this.numA +=1, this.numB +=1 }) //计算属性 computed //是根据已有的状态产生新的状态 //计算属性前面需要使用get修饰符进行修饰 get sum(){ //计算属性内部必须要有返回值 return this.numA + this.numB } })
2.2.在组件中使用数据
如果使用Page或者Component 中对共享的数据进行读取,更新操作,需要使用mobx-miniprogram-bindings ,而mobx-miniprogram-bindings 的作用就是将Store和页面或组件进行绑定关联.
如果需要在组件中使用状态,需要mobx-miniprogram-bindings 库中导入ComponentWithStore方法.在使用时:需要将Component方法替换成ComponentWithStore方法,原本组件配置项也需要写到该方法中.
在替换以后,就会新增一个storeBingings配置项,配置项常用的属性有以下三个:
1.store:指定要绑定的store对象
2.fields:指定需要绑定的data字段
3.actions:指定需要映射的actions方法
注意事项:
导入的数据会同步到组件的data中
导入的方法会同步到组件的methods中
//1.创建一个组件
//如果需要在组件中使用Store中的数据以及方法
//需要从mobx-miniprogram-bindings里面引入ComponentWithStore方法
import { ComponentWithStore } form "../"
//导入当前组件需要使用的Store对象
import { numstore } form "../../stores/numstore"
2.需要将组件原有的Component直接替换成ComponentWithStore
ComponentWithStore({
//组件的属性列表
properties:{
}
//用来配置当前组件需要与那些Store进行关联
//注意事项:在从Store对象中引入数据和方法以后,如果是数据,属性会被注入到data对象中(也就相当于在data{}直接拥有了这个属性,如果在html中使用的话,可以直接使用了,不需要单独在data{}再写一次了),
如果是方法,会被注入到methods对象中(方法同属性)
storeBindings:{
//需要和那个进行关联
store: numstore,
//当前组件需要使用numstore中的那些数据
fields:["numA","numB","sum"]
//numstore对象中来映射引入那些方法
actions:["update"]
}
})
2.3.在页面中使用数据-方式1
Component方法用于创建自定义的组件.
小程序的页面也可以视为自定义组件,因此页面也可以使用Component方法进行构建,从而实现复杂的页面逻辑开发.
如果我们使用Component方法来构建页面,那个页面中如果想使用 Store中的数据,使用方式和组件的使用方式是一样的
1.从mobx-miniprogram-bindings库中导入ComponentWithStore方法;
2.将Component方法替换成ComponentWithStore方法;
3.然后配置storeBingings从Store中映射数据和方法即可.
2.4.在页面中使用数据-方式2
如果不想使用Component方法构建页面.这时候需要使用mobx-miniprogram-bindings 提供BehaviorWithStore 方法来和Store 建立关联.
小程序的behavior 方法是一种代码复用的方式,可以将一些通用的逻辑和方法提取出来,然后在多个组件中复用,从而减少代码冗余,提高代码的可维护性.在页面中可以使用Behaviors配置.
使用方式如下:
- 新建behavior文件,从mobx-miniprogram-bindings库中导入BehaviorWithStore方法
- 在BehaviorWithStore 方法中配置storeBingings配置项从Store中映射数据和方法
- 在page方法中导入创建的behavior,然后配置behavior属性,并使用导入的behavior
//新建behavior.js文件
//小程序如果想使用Store对象中的数据或者方法,就必须先导入
//需要从mobx-miniprogram-bindings导入BehaviorWithStore方法
import { BehaviorWithStore } from "mobx-miniprogram-bindings"
//调用
//BehaviorWithStore方法的作用:让页面和Store对象建立关联
export const cartBehavior = BehaviorWithStore({
storeBindings:{
store: numstore,//当前页面需要跟那个store对象进行关联
//当前页面需要从numstore中导入那些数据
fields:["numA","numB","sum"]
//numstore对象中来映射引入那些方法
actions:["update"]
}
})
//在页面的js文件中如何使用创建的behavior
import {carBehavior} form "./behavior"
Page({
//使用behavior配置项注册提取的behavior
//同样的carBehavior的属性和方法就已经被注册进了data{}方法里面
behaviors:[carBehavior]
})
2.5.fields,actions对象写法
fields,actions有两种写法:数组或者对象.
如果fields写成对象方式,有两种写法:
1.映射形式:指定daya中那些字段来源于store以及他们在store中对应的名字.
例如{a:"numA",b:"numB"}
2.函数形式:指定data中每个字段的计算方法
例如{ a:()=>store.numA, b:()=>anotherStore.numB }
如果actions写成对象方式,只有两种写法:
1.映射形式:指定模块中调用的那些方法来源于store以及他们在store中对应的名字.
例如:{buttonTap:"update"}
2.6.绑定多个store以及命名空间
在实际开发中,一个页面或者组件可能会绑定多个store,这时候我们可以将storeBingings 改造成数组.数组中每一项就是要一个个绑定的store.
如果多个store中存在相同的数据,显示会出现异常.还可以通过namespace属性给当前store开启命名空间,在开启命名空间以后,访问数据的时候,需要加上namespace的名字才可以.
//新建behavior.js文件
//小程序如果想使用Store对象中的数据或者方法,就必须先导入
//需要从mobx-miniprogram-bindings导入BehaviorWithStore方法
import { BehaviorWithStore } from "mobx-miniprogram-bindings"
import { numStore } from "../../stores/numstore"
import { cloneStore } from "../../stores/clonestore"
//调用
//BehaviorWithStore方法的作用:让页面和Store对象建立关联
export const cartBehavior = BehaviorWithStore({
//如果一个组件或者页面需要绑定多个store对象,需要将storeBindings配置项改成一个数组
//数组每一项是一个个要绑定的store对象
storeBindings:[
{
store: numstore,//当前页面需要跟那个store对象进行关联
//当前页面需要从numstore中导入那些数据
fields:["numA","numB","sum"]
//numstore对象中来映射引入那些方法
actions:["update"]
},
//如果一个组件或者页面需要绑定多个store对象
//从store对象中引入了相同的数据或者方法
//这时候代码就会出现异常
{
store: cloneStore,
//第一中解决方案:将fields以及actions改成对象方式
//fields:["numA","numB","sum"]
//actions:["update"]
fields:{
a:"numA",
b:"numB",
total:"sum"
},
actions:{
updateDate:"update"
},
//第二中解决方案:添加命名空间
//如果是数据存在冲突(存在相同的数据或者方法),添加命名空间没有问题的
//但是如果是方法冲突(存在相同的数据或者方法),依然需要使用对象的方式来改造
//在添加命名空间以后,如果需要访问数据,需要加上命名空间的名字才可以
//cloneStore. numA
namespace:"cloneStore",
fields:["numA","numB","sum"]
actions:{
updateDate:"update"
},
}
]
})
3.miniprogram-computed
小程序框架没有提供计算属性相关的api,但是官方为开发者提供了拓展工具库miniprogram-computed
该工具库提供了两个功能:1.计算属性 computed 2.监听器 watch
3.1.计算属性 computed
如果需要在组件中使用计算属性功能,需要miniprogram-computed 库中导入ComponentWithComputed方法.在使用时:需要将Component方法替换成ComponentWithComputed方法,原本组件配置项也需要写到该方法中
在替换以后,就可以新增Computed以及watch配置项.
安装ComponentWithComputed,在安装以后,需要单击构建npm,进行本地构建
npm install miniprogram-computed
//在js文件中
//如果需要在组件中使用计算属性功能,需要导入ComponentWithComputed方法
import {ComponentWithComputed} from "miniprogram-computed"
//对组件进行替换,需要使用导入的方法ComponentWithComputed替换Component方法
ComponentWithComputed({
//计算属性:基于已有的数据产生新的数据
//在使用ComponentWithComputed方法构建以后,这个时候,就可以新增两个配置项Computed以及watch配置项
//组件的初始数据
data:{
a:1,
b:2
},
//组件的方法列表
methods:{
},
//组件的方法列表
computed:{
total(data){
//计算属性必须有返回值,在计算属性内不能使用this来获取data中数据
//如果想获取data中数据,需要使用形参
//计算属性只执行一次,后续在使用的时候,返回的值是第一次执行的结果.
//只要依赖的数据没有发生改变,返回的值始终之是第一次执行的结果
return data.a + data.b
},
}
})
3.2.监听器 watch
在使用时:需要将Component方法替换成ComponentWithComputed方法,原本组件配置项也需要写到该方法中.在替换后,就可以新增 computed 以及 watch配置项.
//在js文件中
//如果需要在组件中使用计算属性功能,需要导入ComponentWithComputed方法
import {ComponentWithComputed} from "miniprogram-computed"
//对组件进行替换,需要使用导入的方法ComponentWithComputed替换Component方法
ComponentWithComputed({
//计算属性:基于已有的数据产生新的数据
//在使用ComponentWithComputed方法构建以后,这个时候,就可以新增两个配置项Computed以及watch配置项
//组件的初始数据
data:{
a:1,
b:2
},
//组件的方法列表
methods:{
},
//组件的方法列表
computed:{
total(data){
//计算属性必须有返回值,在计算属性内不能使用this来获取data中数据
//如果想获取data中数据,需要使用形参
//计算属性只执行一次,后续在使用的时候,返回的值是第一次执行的结果.
//只要依赖的数据没有发生改变,返回的值始终之是第一次执行的结果
//只要计算属性依赖的数据发生了变化,计算属性就会重新执行
return data.a + data.b
},
},
//watch 数据监听器,用来监听数据是否发生了变化,在数据变化以后执行相应的逻辑
watch:{
//key:需要监听的数据
//value:是回调函数,回调函数有一个形参,形参是最新的,改变以后得数据
a:function(a){
},
//同时监听多个数据,数据与数据之间需要使用逗号隔开
"a,b":function(a,b){
//在watch内部监听到数据变化以后,就可以来执行相应的逻辑
},
}
})