详解几十行代码实现一个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 相关文章推荐
firefox和IE系列的相关区别整理 以备后用
Dec 28 Javascript
javascript算法题 求任意一个1-9位不重复的N位数在该组合中的大小排列序号
Jul 21 Javascript
js 跳出页面的frameset框架示例介绍
Dec 23 Javascript
node.js中的buffer.length方法使用说明
Dec 14 Javascript
Javascript无参数和有参数类继承问题解决方法
Mar 02 Javascript
javascript中offset、client、scroll的属性总结
Aug 13 Javascript
javascript判断复选框是否选中的方法
Oct 16 Javascript
javascript设计模式之module(模块)模式
Aug 19 Javascript
jQuery使用JSONP实现跨域获取数据的三种方法详解
May 04 jQuery
jQuery自定义多选下拉框效果
Jun 19 jQuery
jQuery Ajax实现Select多级关联动态绑定数据的实例代码
Oct 26 jQuery
ES6 async、await的基本使用方法示例
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
PHP curl CURLOPT_RETURNTRANSFER参数的作用使用实例
2015/02/07 PHP
mysql_connect localhost和127.0.0.1的区别(网络层阐述)
2015/03/26 PHP
PHP-FPM之Chroot执行环境详解
2015/08/03 PHP
php生成Android客户端扫描可登录的二维码
2016/05/13 PHP
php校验公钥是否可用的实例方法
2019/09/17 PHP
css把超出的部分显示为省略号的方法兼容火狐
2008/07/23 Javascript
用Javascript同时提交多个Web表单的方法
2009/12/26 Javascript
js中将具有数字属性名的对象转换为数组
2011/03/06 Javascript
在线一元二次方程计算器实例(方程计算器在线计算)
2013/12/22 Javascript
JavaScript实现带缓冲效果的随屏滚动漂浮广告代码
2015/11/06 Javascript
Bootstrap3 input输入框插入glyphicon图标的方法
2016/05/16 Javascript
基于AngularJS实现iOS8自带的计算器
2016/09/12 Javascript
Vue结合SignalR实现前后端实时消息同步
2017/09/19 Javascript
AnglarJs中的上拉加载实现代码
2018/02/08 Javascript
Node.js 利用cheerio制作简单的网页爬虫示例
2018/03/01 Javascript
swiper实现异形轮播效果
2019/11/28 Javascript
python中lambda与def用法对比实例分析
2015/04/30 Python
Python内置数据结构与操作符的练习题集锦
2016/07/01 Python
【python】matplotlib动态显示详解
2019/04/11 Python
django之状态保持-使用redis存储session的例子
2019/07/28 Python
Python利用requests模块下载图片实例代码
2019/08/12 Python
pandas 缺失值与空值处理的实现方法
2019/10/12 Python
解决torch.autograd.backward中的参数问题
2020/01/07 Python
Python3打包exe代码2种方法实例解析
2020/02/17 Python
基于Html5实现的语音搜索功能
2019/05/13 HTML / CSS
Trina Turk官网:美国时装和泳装品牌
2018/06/10 全球购物
墨尔本最受欢迎的复古风格品牌:Princess Highway
2018/12/21 全球购物
乌克兰最大的家用电器和电子产品连锁店:Eldorado
2019/10/02 全球购物
新奥尔良珠宝:Mignon Faget
2020/11/23 全球购物
C#如何调用Word并打开一个Word文档
2013/05/08 面试题
军神教学反思
2014/02/04 职场文书
公司合作意向书范文
2014/07/30 职场文书
食品委托检验协议书范本
2014/09/12 职场文书
2015年关爱留守儿童工作总结
2015/05/22 职场文书
民事二审代理词
2015/05/25 职场文书
python3 实现mysql数据库连接池的示例代码
2021/04/17 Python