详解几十行代码实现一个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 相关文章推荐
jQuery 1.0.2
Oct 11 Javascript
List Installed Hot Fixes
Jun 12 Javascript
isArray()函数(JavaScript中对象类型判断的几种方法)
Nov 26 Javascript
修改好的jquery滚动字幕效果实现代码
Jun 22 Javascript
JavaScript常用验证函数实例汇总
Nov 25 Javascript
跟我学习javascript的异步脚本加载
Nov 20 Javascript
谈谈AngularJs中的隐藏和显示
Dec 09 Javascript
jQuery阻止移动端遮罩层后页面滚动
Mar 15 Javascript
JS实现动态添加DOM节点和事件的方法示例
Apr 28 Javascript
详解React 的几种条件渲染以及选择
Oct 23 Javascript
原生JS使用Canvas实现拖拽式绘图功能
Jun 05 Javascript
通过js示例讲解时间复杂度与空间复杂度
Aug 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实现扎金花游戏之大小比赛的方法
2015/03/10 PHP
判断、添加和删除WordPress置顶文章的相关PHP函数小结
2015/12/10 PHP
编写PHP脚本清除WordPress头部冗余代码的方法讲解
2016/03/01 PHP
php使用ftp远程上传文件类(完美解决主从文件同步问题的方法)
2016/09/23 PHP
php用户密码加密算法分析【Discuz加密算法】
2016/10/12 PHP
Javascript-Mozilla和IE中的一个函数直接量的问题
2007/01/09 Javascript
这些年、我收集的JQuery代码小结
2012/08/01 Javascript
jquery增加时编辑jqGrid(实例代码)
2013/11/08 Javascript
javascript不同类型数据之间的运算的转换方法
2014/02/13 Javascript
nodejs获取本机内网和外网ip地址的实现代码
2014/06/01 NodeJs
javascript制作sql转换为stringBuffer的小工具
2015/04/03 Javascript
JS实现跟随鼠标立体翻转图片的方法
2015/05/04 Javascript
JavaScript箭头函数_动力节点Java学院整理
2017/06/28 Javascript
微信小程序 本地图片按照屏幕尺寸处理
2017/08/04 Javascript
实现jquery放大镜的两种方法
2018/02/22 jQuery
vue把输入框的内容添加到页面的实例讲解
2019/11/11 Javascript
es6 for循环中let和var区别详解
2020/01/12 Javascript
vue 防止页面加载时看到花括号的解决操作
2020/11/09 Javascript
[36:52]DOTA2真视界:基辅特锦赛总决赛
2017/05/21 DOTA
在RedHat系Linux上部署Python的Celery框架的教程
2015/04/07 Python
Python实现一个简单的验证码程序
2017/11/03 Python
利用Python如何将数据写到CSV文件中
2018/06/05 Python
Python基于mysql实现学生管理系统
2019/02/21 Python
Python动态赋值的陷阱知识点总结
2019/03/17 Python
利用python实现汉字转拼音的2种方法
2019/08/12 Python
pycharm 实现光标快速移动到括号外或行尾的操作
2021/02/05 Python
pyx文件 生成pyd 文件用于 cython调用的实现
2021/03/04 Python
css3和jquery实现的可折叠导航菜单适合放在手机网页的导航菜单
2014/09/02 HTML / CSS
学校经典推荐信
2013/10/30 职场文书
制定岗位职责的原则
2013/11/08 职场文书
职业道德模范事迹材料
2014/08/24 职场文书
初级党校心得体会
2014/09/11 职场文书
自习课吵闹检讨书范文
2014/09/26 职场文书
从事会计工作年限证明
2015/06/23 职场文书
使用Selenium实现微博爬虫(预登录、展开全文、翻页)
2021/04/13 Python
入门学习Go的基本语法
2021/07/07 Golang