详解几十行代码实现一个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 相关文章推荐
让iframe框架网页在任何浏览器下自动伸缩
Aug 18 Javascript
使用jsonp完美解决跨域问题
Nov 27 Javascript
js表单提交和submit提交的区别实例分析
Dec 10 Javascript
js针对ip地址、子网掩码、网关的逻辑性判断
Jan 06 Javascript
javascript中mouseenter与mouseover的异同
Jun 06 Javascript
JavaScript事件处理程序详解
Sep 19 Javascript
原生JS+CSS实现炫酷重力模拟弹跳系统的登录页面
Nov 01 Javascript
jQuery创建及操作xml格式数据示例
May 26 jQuery
Vue.set() this.$set()引发的视图更新思考及注意事项
Aug 30 Javascript
在vue中更换字体,本地存储字体非引用在线字体库的方法
Sep 28 Javascript
微信小程序中的店铺评分组件及vue中用svg实现的评分显示组件
Nov 16 Javascript
JavaScript前端开发时数值运算的小技巧
Jul 28 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 中dirname(_file_)讲解
2007/03/18 PHP
PHP下几种删除目录的方法总结
2007/08/19 PHP
PHP获取当前页面完整URL的实现代码
2013/06/10 PHP
php网站判断用户是否是手机访问的方法
2013/11/01 PHP
一个php生成16位随机数的代码(两种方法)
2014/09/16 PHP
CI框架中数据库操作函数$this-&gt;db-&gt;where()相关用法总结
2016/05/17 PHP
php提交表单时保留多个空格及换行的文本样式的方法
2017/06/20 PHP
PHP应用跨时区功能的实现方法
2019/03/21 PHP
Laravel自定义 封装便捷返回Json数据格式的引用方法
2019/09/29 PHP
基于PHP实现短信验证码发送次数限制
2020/07/11 PHP
javascript网页关闭时提醒效果脚本
2008/10/22 Javascript
jQuery创建自己的插件(自定义插件)的方法
2010/06/10 Javascript
在js(jquery)中获得文本框焦点和失去焦点的方法
2012/12/04 Javascript
javascript删除数组元素并且数组长度减小的简单实例
2014/02/14 Javascript
jquery Deferred 快速解决异步回调的问题
2016/04/05 Javascript
全面解析Bootstrap中tab(选项卡)的使用方法
2016/06/06 Javascript
如何以Angular的姿势打开Font-Awesome详解
2018/04/22 Javascript
老生常谈JS中的继承及实现代码
2018/07/06 Javascript
Vue实现美团app的影院推荐选座功能【推荐】
2018/08/29 Javascript
vue+swiper实现左右滑动的测试题功能
2020/10/30 Javascript
Python中跳台阶、变态跳台阶与矩形覆盖问题的解决方法
2018/05/19 Python
详解Django解决ajax跨域访问问题
2018/08/24 Python
python实现简单的单变量线性回归方法
2018/11/08 Python
用Python实现校园通知更新提醒功能
2019/11/23 Python
python 已知一个字符,在一个list中找出近似值或相似值实现模糊匹配
2020/02/29 Python
Python 如何创建一个线程池
2020/07/28 Python
PyCharm2020.1.2社区版安装,配置及使用教程详解(Windows)
2020/08/07 Python
css3实现3D文本悬停改变效果的示例代码
2019/01/16 HTML / CSS
德国旅游网站:weg.de
2018/06/03 全球购物
英国在线药房和在线药剂师:Chemist 4 U
2020/01/05 全球购物
大学生职业生涯规划书范文
2014/01/14 职场文书
法学专业毕业生自荐信
2014/06/11 职场文书
银行优秀员工推荐信
2015/03/24 职场文书
傲慢与偏见电影观后感
2015/06/10 职场文书
工作简报格式范文
2015/07/21 职场文书
Tensorflow与RNN、双向LSTM等的踩坑记录及解决
2021/05/31 Python