详解几十行代码实现一个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 相关文章推荐
javascript html 静态页面传参数
Apr 10 Javascript
JS如何将数字类型转化为没3个一个逗号的金钱格式
Jan 27 Javascript
js实现局部页面打印预览原理及示例代码
Jul 03 Javascript
浅谈JSON.parse()和JSON.stringify()
Jul 14 Javascript
JavaScript数据结构与算法之栈与队列
Jan 29 Javascript
jQuery使用deferreds串行多个ajax请求
Aug 22 Javascript
JavaScript之事件委托实例(附原生js和jQuery代码)
Jul 22 jQuery
深入理解Node module模块
Mar 26 Javascript
原生JS实现动态添加新元素、删除元素方法
May 05 Javascript
js实现图片上传即时显示效果
Sep 30 Javascript
JavaScript计算出两个数的差值
Mar 19 Javascript
Element Dropdown下拉菜单的使用方法
Jul 26 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
php通过COM类调用组件的实现代码
2012/01/11 PHP
ThinkPHP写第一个模块应用
2012/02/20 PHP
php将字符串转换成16进制的方法
2015/03/17 PHP
php实现格式化多行文本为Js可用格式
2015/04/15 PHP
php实现文本数据导入SQL SERVER
2015/05/17 PHP
PHP实现过滤各种HTML标签
2015/05/17 PHP
php文件上传类完整实例
2016/05/14 PHP
PHP清除缓存的几种方法总结
2017/09/12 PHP
Laravel框架处理用户的请求操作详解
2019/12/20 PHP
用roll.js实现的图片自动滚动+鼠标触动的特效
2007/03/18 Javascript
对JavaScript的eval()中使用函数的进一步讨论
2008/07/26 Javascript
WordPress 照片lightbox效果的运用几点
2009/06/22 Javascript
JavaScript中Object和Function的关系小结
2009/09/26 Javascript
有关于JS辅助函数inherit()的问题
2013/04/07 Javascript
jquery 操作两个select实现值之间的互相传递
2014/03/07 Javascript
微信小程序实现简单input正则表达式验证功能示例
2017/11/30 Javascript
React从react-router路由上做登陆验证控制的方法
2018/05/10 Javascript
webstorm中配置Eslint的两种方式及差异比较详解
2018/10/19 Javascript
vue.js this.$router.push获取不到params参数问题
2020/03/03 Javascript
webpack+express实现文件精确缓存的示例代码
2020/06/11 Javascript
javascript 数组(list)添加/删除的实现
2020/12/17 Javascript
Python装饰器原理与用法分析
2018/04/30 Python
Python包和模块的分发详细介绍
2020/06/19 Python
传统HTML页面实现模块化加载的方法
2018/10/15 HTML / CSS
高清屏下canvas重置尺寸引发的问题的解决
2019/10/14 HTML / CSS
Java基础类库面试题
2013/09/04 面试题
化学专业毕业生自荐信
2013/11/15 职场文书
优秀交警事迹材料
2014/01/26 职场文书
讲座主持词
2014/03/20 职场文书
美食节策划方案
2014/05/26 职场文书
三严三实对照检查材料
2014/08/25 职场文书
领导班子四风对照检查材料
2014/09/23 职场文书
小学五一劳动节活动总结
2015/02/09 职场文书
详解nodejs内置模块
2021/05/06 NodeJs
python开发实时可视化仪表盘的示例
2021/05/07 Python
NoSQL优缺点与MongoDB数据库简介
2022/06/05 MongoDB