详解几十行代码实现一个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 相关文章推荐
apycom出品的jQuery精美菜单破解方法
Feb 18 Javascript
js indexOf()定义和用法
Oct 21 Javascript
JavaScript中的Web worker多线程API研究
Dec 06 Javascript
jquery实现Slide Out Navigation滑出式菜单效果代码
Sep 07 Javascript
BootStrap智能表单demo示例详解
Jun 13 Javascript
jQuery实现导航高亮的方法【附demo源码下载】
Nov 09 Javascript
微信公众号 摇一摇周边功能开发
Dec 08 Javascript
React操作真实DOM实现动态吸底部的示例
Oct 23 Javascript
Vim快速合并行及vim 将文件所有行合并到一行
Nov 27 Javascript
Vue三种常用传值示例(父传子、子传父、非父子)
Jul 24 Javascript
如何使用CSS3和JQuery easing 插件制作绚丽菜单
Jun 18 jQuery
原生js+css调节音量滑块
Jan 15 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+Mysql+jQuery实现发布微博程序 jQuery篇
2011/10/08 PHP
开启PHP Static 关键字之旅模式
2015/11/13 PHP
Javascript attachEvent传递参数的办法
2009/12/14 Javascript
浅谈javascript获取元素transform参数
2015/07/24 Javascript
JavaScript位置与大小(1)之正确理解和运用与尺寸大小相关的DOM属性
2015/12/26 Javascript
详解js中的apply与call的用法
2016/07/30 Javascript
Javascript数组循环遍历之forEach详解
2016/11/07 Javascript
jquery中用函数来设置css样式
2016/12/22 Javascript
bootstrap响应式表格实例详解
2017/05/15 Javascript
JS实现留言板功能[楼层效果展示]
2017/12/27 Javascript
JS随机数产生代码分享
2018/02/24 Javascript
vue v-for循环重复数据无法添加问题解决方法【加track-by='索引'】
2019/03/15 Javascript
Vue+Express实现登录注销功能的实例代码
2019/05/05 Javascript
学前端,css与javascript重难点浅析
2020/06/11 Javascript
design vue 表格开启列排序的操作
2020/10/28 Javascript
python sort、sorted高级排序技巧
2014/11/21 Python
python机器学习实战之K均值聚类
2017/12/20 Python
Python开发虚拟环境使用virtualenvwrapper的搭建步骤教程图解
2018/09/19 Python
numpy concatenate数组拼接方法示例介绍
2019/05/27 Python
Python计算两个矩形重合面积代码实例
2019/09/16 Python
Python数据持久化存储实现方法分析
2019/12/21 Python
pyinstaller还原python代码过程图解
2020/01/08 Python
python入门之井字棋小游戏
2020/03/05 Python
快速实现一个简单的canvas迷宫游戏的示例
2018/07/04 HTML / CSS
Sephora丝芙兰菲律宾官方网站:购买化妆品和护肤品
2017/04/05 全球购物
高中语文教学反思
2014/01/16 职场文书
日语专业个人求职信范文
2014/02/02 职场文书
《学棋》教后反思
2014/04/14 职场文书
促销活动总结报告
2014/04/26 职场文书
新法人代表任命书
2014/06/06 职场文书
2014年终个人总结报告
2015/03/09 职场文书
经典祝酒词大全
2015/08/12 职场文书
七年级英语教学反思
2016/02/15 职场文书
JS新手入门数组处理的实用方法汇总
2021/04/07 Javascript
python实现自动化群控的步骤
2021/04/11 Python
A22国内电台短波广播频率表
2022/05/10 无线电