E企盈营销工具技术服务商 热线:4006-838-530

小程序全局状态管理

E企盈直播平台营销卖货系统

小程序全局状态管理缘由使用vue的朋友可能用过vuex,使用react的朋友可能用redux,好处自然不用多说,用过的都说好。微信小程序,我去年就曾接触过,那时候小程序连组件的概念都没有,现在小程序似乎更火了,也增加了很多新概念,包括自定义组件。小程序的入口文件app.js里会调用App()方法创建一个应用程序实例,有一些公共的、全局的数据可以保存在app.globalData属性里,但是globalData并不具备响应式功能,数据变化时,不会自动更新视图。多个页面或者组件共享同一状态时,处理起来也是相当麻烦的。所以,我花了一点时间,简单实现了一个适用于小程序的状态管理。demoapp.js//app.jsimport store from ‘./store/index’;// 创建appApp(store.createApp({  globalData: {    userInfo: {},    todos: [{      name: ‘刷牙’,      done: true    }, {      name: ‘吃饭’,      done: false    }]  }  // …其他}))复制代码pages/index/index.wxml<view class=”container”>  <view>    {{title}}  </view>  <view class=”info”>    <view>      姓名:{{userInfo.name}}    </view>    <view>      年龄:{{userInfo.age}}    </view>  </view>  <button type=”button” bindtap=”addTodo”>增加todo</button>  <!– todos组件 –>  <todos /></view>复制代码pages/index/index.js//index.jsimport store from ‘../../store/index’;// 创建页面Page(store.createPage({  data: {    title: ‘用户信息页’  },  // 依赖的全局状态属性 这些状态会被绑定到data上  globalData: [‘userInfo’, ‘todos’],  // 这里可以定义需要监听的状态,做一些额外的操作,this指向了当前页面实例  watch: {    userInfo(val) {      console.log(‘userInfo更新了’, val, this);    }  },  onLoad() {    this.getUserInfo().then(userInfo => {      // 通过dispatch更新globalData数据      store.dispatch(‘userInfo’, userInfo);    })  },  // 模拟从服务端获取用户信息  getUserInfo() {    return new Promise((resolve, reject) => {      setTimeout(() => {        resolve({          name: ‘小明’,          age: 20        })      }, 100)    })  },  // 增加todo  addTodo() {    // 注意:这里从this.data上获取todos而不是globalData    const todos = […this.data.todos, {      name: ‘学习’,      donw: false    }];    store.dispatch(‘todos’, todos);  }  // 其他…}))复制代码components/todos/index.wxml<view class=”container”>    <view class=”todos”>        <view wx:for=”{{todos}}” wx:key=”{{index}}”>            <view>{{item.name}}</view>            <view>{{item.done?’已完成’:’未完成’}}</view>        </view>    </view></view>复制代码components/todos/index.jsimport store from ‘../../store/index’;// 创建组件Component(store.createComponent({    // 依赖的全局状态属性    globalData: [‘todos’],    // 这里可以定义需要监听的状态,做一些额外的操作,this指向了当前组件实例    watch: {        todos(val) {            console.log(‘todos更新了’, val, this);            // 做其他事。。。        }    }    // 其他…}))复制代码点击”增加todo”之前点击”增加todo”之后实现原理是不是很神奇,全是代码中那个store的功劳。原理其实非常简单,实现起来也就100+行代码。主要就是使用观察者模式(或者说是订阅/分发模式),通过dispatch方法更新数据时,执行回调,内部调用this.setData方法更新视图。不多说,直接贴一下源码。codestore/observer.jsconst events = Symbol(‘events’);class Observer {    constructor() {        this[events] = {};    }    on(eventName, callback) {        this[events][eventName] = this[events][eventName] || [];        this[events][eventName].push(callback);    }    emit(eventName, param) {        if (this[events][eventName]) {            this[events][eventName].forEach((value, index) => {                value(param);            })        }    }    clear(eventName) {        this[events][eventName] = [];    }    off(eventName, callback) {        this[events][eventName] = this[events][eventName] || [];        this[events][eventName].forEach((item, index) => {            if (item === callback) {                this[events][eventName].splice(index, 1);            }        })    }    one(eventName, callback) {        this[events][eventName] = [callback];    }}const observer = new Observer();export {    Observer,    observer}复制代码store/index.jsimport {    Observer} from ‘./observer’const bindWatcher = Symbol(‘bindWatcher’);const unbindWatcher = Symbol(‘unbindWatcher’);class Store extends Observer {    constructor() {        super();        this.app = null;    }    // 创建app    createApp(options) {        const {            onLaunch        } = options;        const store = this;        options.onLaunch = function (…params) {            store.app = this;            if (typeof onLaunch === ‘function’) {                onLaunch.apply(this, params);            }        }        return options;    }    // 创建页面    createPage(options) {        const {            globalData = [],                watch = {},                onLoad,                onUnload        } = options;        const store = this;        // 保存globalData更新回调的引用        const globalDataWatcher = {};        // 保存watch监听回调的引用        const watcher = {};        // 劫持onLoad        options.onLoad = function (…params) {            store[bindWatcher](globalData, watch, globalDataWatcher, watcher, this);            if (typeof onLoad === ‘function’) {                onLoad.apply(this, params);            }        }        // 劫持onUnload        options.onUnload = function () {            store[unbindWatcher](watcher, globalDataWatcher);            if (typeof onUnload === ‘function’) {                onUnload.apply(this);            }        }        delete options.globalData;        delete options.watch;        return options;    }    // 创建组件    createComponent(options) {        const {            globalData = [],                watch = {},                attached,                detached        } = options;        const store = this;        // 保存globalData更新回调的引用        const globalDataWatcher = {};        // 保存watch监听回调的引用        const watcher = {};        // 劫持attached        options.attached = function (…params) {            store[bindWatcher](globalData, watch, globalDataWatcher, watcher, this);            if (typeof attached === ‘function’) {                attached.apply(this, params);            }        }        // 劫持detached        options.detached = function () {            store[unbindWatcher](watcher, globalDataWatcher);            if (typeof detached === ‘function’) {                detached.apply(this);            }        }        delete options.globalData;        delete options.watch;        return options;    }    // 派发一个action更新状态    dispatch(action, payload) {        this.app.globalData[action] = payload;        this.emit(action, payload);    }    /**     * 1. 初始化页面关联的globalData并且监听更新     * 2. 绑定watcher     * @param {Array} globalData     * @param {Object} watch     * @param {Object} globalDataWatcher     * @param {Object} watcher     * @param {Object} instance 页面实例     */    [bindWatcher](globalData, watch, globalDataWatcher, watcher, instance) {        const instanceData = {};        for (let prop of globalData) {            instanceData[prop] = this.app.globalData[prop];            globalDataWatcher[prop] = payload => {                instance.setData({                    [prop]: payload                })            }            this.on(prop, globalDataWatcher[prop]);        }        for (let prop in watch) {            watcher[prop] = payload => {                watch[prop].call(instance, payload);            }            this.on(prop, watcher[prop])        }        instance.setData(instanceData);    }    /**     * 解绑watcher与globalDataWatcher     * @param {Object} watcher     * @param {Object} globalDataWatcher      */    [unbindWatcher](watcher, globalDataWatcher) {        // 页面卸载前 解绑对应的回调 释放内存        for (let prop in watcher) {            this.off(prop, watcher[prop]);        }        for (let prop in globalDataWatcher) {            this.off(prop, globalDataWatcher[prop])        }    }}export default new Store()复制代码具体的代码就不解释了,源码里也有基本的注释。目前实现的功能不算多,基本上能用了,如果业务上需求更高了,再进行拓展。以上,希望能给一些朋友一点点启发,顺便点个赞哦,嘻嘻!

赞(0) 打赏
未经允许不得转载:E企盈小程序开发-热线:4006-838-530 » 小程序全局状态管理
分享到: 更多 (0)
E企盈小程序直播营销卖货系统
E企盈直播平台营销卖货系统

评论 抢沙发

E企盈小程序开发

联系我们联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏