详解几十行代码实现一个vue的状态管理


Posted in Javascript onJanuary 28, 2019

介绍

采用集中式存储管理应用的所有组件的状态, 就能实现组件间数据共享

实现

逻辑图

详解几十行代码实现一个vue的状态管理

从图上有两条线: Vue.use(vuec), 与 new Vuec.center(options)

第一条线Vue.use(vuec)安装插件

使用Vue.use(vuec)时, 会执行vuec的install方法,会注入参数Vue 所以vuec是这样的,

// index.js
import {Center, install} from './center'
export default {Center, install}

Center对象将实例化成center(下面再说),我们先看看install方法

// center.js
let Vue // 全局变量, 保存install里的Vue
export function install (_Vue) {
 if (!Vue) {
  _Vue.mixin({
   beforeCreate: applyMixin // 在beforeCreate钩子上混入applyMixin函数
  })
 }
 Vue = _Vue
}

install在Vue原型的beforeCreate混入applyMixin函数, 也就是说在生成每个Vue组件时,在它的生命周期beforeCreate钩子上就会执行applyMixin方法

第二条线 new Vuec.center(options)实例化Center对象

先看看用户传入的options, 下面例子

export default new Vuec.Center({
 state: {
  name: 'liuyang'
 },
 mutations: {
  changeName (state) {
   state.name = 'jike'
  }
 }
})

上面代码会生成center实例, 该实例上应该包括:state状态,commit方法提交变更等

// center.js
export class Center {
 constructor (options= {}) {
  let center = this
  this.mutations = options.mutations
  observeState(center, options.state)
 }
 get state () { // 代理了this.$center.state的最终访问值
  return this._vm.$data.$$state
 }
 commit (_type, _payload) {
  this.mutations[_type](this.state, _payload)
 }
}
function observeState(center, state) { // 响应式state
 center._vm = new Vue({
  data: {
   $$state: state
  }
 })
}

在执行new Vuec.Center({..})时,就是执行Center的构造函数

首先执行let center = this, 定义center保存当前实例

接着执行this.mutations = options.mutations, 在实例center上添加mutations属性, 值就是用户输入mutations,

按上面例子, this.mutations长成这样

this.mutations = {
  changeName (state) {
   state.name = 'jike'
  }
}

最后执行observeState(center, options.state), 作用:让center实例的state属性指向options.state并且是响应式的

function observeState(center, state) { // 响应式state
   center._vm = new Vue({ // 利用Vue的响应系统,将state转化成响应式
    data: {
     $$state: state
    }
   })
  }

在center实例上添加_vm属性, 值是一个Vue实例, 在该Vue实例的data下定义了$$state, 它的值是options.state用户输入的state; 结合上面的这段代码

// center.js
export class Center {
 ...省略
 get state () { // 代理了this.$center.state的最终访问值
  return this._vm.$data.$$state
 }
 ...省略
}

所以我们在组件中访问center.state其实就是访问center._vm.$data.$$state

OK, center就构建好了

创建Vue组件

用户输入

import Vue from 'vue'
import App from './App'
import router from './router'
import center from './center'

new Vue({
 el: '#app',
 router,
 center, // 构建好的center实例
 template: '<App/>',
 components: {App}
})

在beforeCreate生命周期时会触发上面混入的applyMixin函数

// mixins.js
export default function applyMixin() {
 vuecInit.call(this) // 
}

function vuecInit () {
 const options = this.$options
 // vue的实例化是从外往内, 所以父组件的$center一定是options的center
 this.$center = options.parent?options.parent.$center: options.center
}

applyMixin里会执行vuecInit.call(this), 这里的this指向当前组件的实例,

接着看vuecInit, 定义了options等于用户输入选项,因为先创建根组件, 所以根组件this.$center的值的引用就是我们在new Vue({..center})时传入的center实例, 下面所有组件都指向它

OK, 你就可以在组件里使用this.$center访问了

commit变更

// center.js
export class Center {
 ... 省略
 commit (_type, _payload) {
  this.mutations[_type](this.state, _payload)
 }
}

通常我们变更时: this.$center.commit('changeName', 'jike'), 这样的话, this.mutations[_type]就是对应方法函数, 往该函数里传入state以及payload,

举上面的例子

// this.mutations[_type] , _type = 'changeName', payload= 'jike'
this.mutations = {
  changeName (state, payload) {
   state.name = payload
  }
}

说明

上面只是一个简单的状态管理, 还有很多地方没有实现: actions异步变更,getters函数,modules模块分割, 辅助函数mapState..等

源码地址: github

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
限制文本框输入N个字符的js代码
May 13 Javascript
JS复制内容到剪切板的实例代码(兼容IE与火狐)
Nov 19 Javascript
javascript元素动态创建实现方法
May 13 Javascript
纯JavaScript基于notie.js插件实现消息提示特效
Jan 18 Javascript
JQuery控制DIV的选取实现方法
Sep 18 Javascript
JS声明式函数与赋值式函数实例分析
Dec 13 Javascript
js学习总结之dom2级事件基础知识详解
Jul 27 Javascript
jQuery访问json文件中数据的方法示例
Jan 28 jQuery
详解Vue+ElementUI从零开始搭建自己的网站(一、环境搭建)
Apr 30 Javascript
在vue中使用防抖和节流,防止重复点击或重复上拉加载实例
Nov 13 Javascript
vue实现路由不变的情况下,刷新页面操作示例
Feb 02 Javascript
Vue使用自定义指令实现拖拽行为实例分析
Jun 06 Javascript
vue.js仿hover效果的实现方法示例
Jan 28 #Javascript
vue-for循环嵌套操作示例
Jan 28 #Javascript
使用pm2自动化部署node项目的方法步骤
Jan 28 #Javascript
jQuery访问json文件中数据的方法示例
Jan 28 #jQuery
JS实现的点击按钮图片上下滚动效果示例
Jan 28 #Javascript
vue-cli3 项目从搭建优化到docker部署的方法
Jan 28 #Javascript
JavaScript 判断iPhone X Series机型的方法
Jan 28 #Javascript
You might like
PHP4在Windows2000下的安装
2006/10/09 PHP
对squid中refresh_pattern的一些理解和建议
2009/04/17 PHP
php 搜索框提示(自动完成)实例代码
2012/02/05 PHP
php开发工具有哪五款
2015/11/09 PHP
php中__toString()方法用法示例
2016/12/07 PHP
PHP执行shell脚本运行程序不产生core文件的方法
2016/12/28 PHP
php+ajax实现异步上传文件或图片功能
2017/07/18 PHP
使用PHPUnit进行单元测试并生成代码覆盖率报告的方法
2019/03/08 PHP
laravel自定义分页的实现案例offset()和limit()
2019/10/15 PHP
javascript 不间断的图片滚动并可点击
2010/01/15 Javascript
jQuery 获取对象 基本选择与层级
2010/05/31 Javascript
在Javascript中 声明时用&quot;var&quot;与不用&quot;var&quot;的区别
2013/04/15 Javascript
Jquery模仿Baidu、Google搜索时自动补充搜索结果提示
2013/12/26 Javascript
使用ajaxfileupload.js实现ajax上传文件php版
2014/06/26 Javascript
jQuery的观察者模式详解
2014/12/22 Javascript
AngularJS包括详解及示例代码
2016/08/17 Javascript
微信小程序wx.uploadfile 本地文件转base64的实现代码
2018/06/28 Javascript
vue cli3 配置proxy代理无效的解决
2019/10/30 Javascript
微信小程序自定义弹出模态框禁止底部滚动功能
2020/03/09 Javascript
javascript+css实现俄罗斯方块小游戏
2020/06/28 Javascript
vue 实现click同时传入事件对象和自定义参数
2021/01/29 Vue.js
[07:49]2014DOTA2国际邀请赛 Newbee夺冠后采访xiao8坦言奖金会上交
2014/07/23 DOTA
Python实现的生成自我描述脚本分享(很有意思的程序)
2014/07/18 Python
python反编译学习之字节码详解
2019/05/19 Python
运行tensorflow python程序,限制对GPU和CPU的占用操作
2020/02/06 Python
解决pytorch 保存模型遇到的问题
2021/03/03 Python
纯CSS3制作漂亮带动画效果的主机价格表
2015/04/25 HTML / CSS
Lime Crime官网:美国一家主打梦幻精灵系的彩妆品牌
2019/03/22 全球购物
印尼购物网站:iLOTTE
2019/10/16 全球购物
英国自行车商店:AW Cycles
2021/02/24 全球购物
党支部承诺书范文
2014/03/28 职场文书
博士生导师推荐信
2014/07/08 职场文书
公司员工安全协议书
2014/11/21 职场文书
家长给老师的感谢信
2015/01/20 职场文书
2015年学校党建工作总结
2015/05/19 职场文书
新员工入职感言范文!
2019/07/04 职场文书