详解几十行代码实现一个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 相关文章推荐
js用拖动滑块来控制图片大小的方法
Feb 27 Javascript
JS实现网页上随机产生超链接地址的方法
Nov 09 Javascript
Bootstrap三种表单布局的使用方法
Jun 21 Javascript
微信小程序 wxapp地图 map详解
Oct 31 Javascript
jQuery学习笔记——jqGrid的使用记录(实现分页、搜索功能)
Nov 09 Javascript
使用Vue.js创建一个时间跟踪的单页应用
Nov 28 Javascript
使用openSpeDiv方法实现Ecshop登录弹窗框效果
Mar 13 Javascript
js简单实现网页换肤功能
Apr 07 Javascript
JavaScript反弹动画效果的实现代码
Jul 13 Javascript
Vue的elementUI实现自定义主题方法
Feb 23 Javascript
vscode配置vue下的es6规范自动格式化详解
Mar 20 Javascript
inquirer.js一个用户与命令行交互的工具详解
May 18 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 页面执行时间计算代码
2008/12/04 PHP
php入门学习知识点二 PHP简单的分页过程与原理
2011/07/14 PHP
PHP中基于ts与nts版本- vc6和vc9编译版本的区别详解
2013/04/26 PHP
PHP用mb_string函数库处理与windows相关中文字符及Win环境下开启PHP Mb_String方法
2015/11/11 PHP
PHP数组实例详解
2016/06/26 PHP
PHP中用Trait封装单例模式的实现
2019/12/18 PHP
JavaScript使用cookie
2007/02/02 Javascript
给Javascript数组插入一条记录的代码
2007/08/30 Javascript
jquery 仿QQ校友的DIV模拟窗口效果源码
2010/03/24 Javascript
用jquery与css打造个性化的单选框和复选框
2010/10/20 Javascript
JavaScript 学习历程和心得分享
2010/12/12 Javascript
jQuery 对Select的操作备忘记录
2011/07/04 Javascript
远离JS灾难css灾难之 js私有函数和css选择器作为容器
2011/12/11 Javascript
JQuery设置时间段下拉选择实例
2014/12/30 Javascript
jQuery获取元素父节点的方法
2016/06/21 Javascript
使用纯JS代码判断字符串中有多少汉字的实现方法(超简单实用)
2016/11/12 Javascript
实例分析浏览器中“JavaScript解析器”的工作原理
2016/12/12 Javascript
彻底弄懂 JavaScript 执行机制
2018/10/23 Javascript
JavaScript中的 new 命令
2019/05/22 Javascript
JavaScript this指向相关原理及实例解析
2020/07/10 Javascript
vue element 关闭当前tab 跳转到上一路由操作
2020/07/22 Javascript
js实现鼠标滑动到某个div禁止滚动
2020/09/17 Javascript
Python中的探索性数据分析(功能式)
2017/12/22 Python
python与sqlite3实现解密chrome cookie实例代码
2018/01/20 Python
详解Django的CSRF认证实现
2018/10/09 Python
python对文件目录的操作方法实例总结
2019/06/24 Python
python logging日志模块原理及操作解析
2019/10/12 Python
Python json模块与jsonpath模块区别详解
2020/03/05 Python
Pycharm及python安装详细步骤及PyCharm配置整理(推荐)
2020/07/31 Python
python中 _、__、__xx__()区别及使用场景
2020/06/30 Python
世界上最悠久的自行车制造商:Ribble Cycles
2017/03/18 全球购物
C/C++ 笔试、面试题目大汇总
2015/11/21 面试题
青年文明号事迹材料
2014/01/18 职场文书
工程售后服务承诺书
2014/05/21 职场文书
人与自然观后感
2015/06/16 职场文书
Redis IP地址的绑定的实现
2021/05/08 Redis