详解几十行代码实现一个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中继承的几种用法总结(apply,call,prototype)
Dec 26 Javascript
JavaScript表格常用操作方法汇总
Apr 15 Javascript
jQuery实现有动画淡出效果的二级折叠菜单代码
Oct 17 Javascript
JS中绑定事件顺序(事件冒泡与事件捕获区别)
Jan 24 Javascript
JS仿QQ好友列表展开、收缩功能(第二篇)
Jul 07 Javascript
基于require.js的使用(实例讲解)
Sep 07 Javascript
微信小程序 循环及嵌套循环的使用总结
Sep 26 Javascript
vue项目总结之文件夹结构配置详解
Dec 13 Javascript
LayerClose弹窗关闭刷新方法
Aug 17 Javascript
Bootstrap 实现表格样式、表单布局的实例代码
Dec 09 Javascript
JavaScript判断数组类型的方法
Oct 23 Javascript
vue之a-table中实现清空选中的数据
Nov 07 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中实现Javascript的escape()函数代码
2010/08/08 PHP
PHP 杂谈《重构-改善既有代码的设计》之四 简化条件表达式
2012/04/09 PHP
利用phpexcel把excel导入数据库和数据库导出excel实现
2014/01/09 PHP
PHP人民币金额转大写实例代码
2015/10/02 PHP
PHP批量删除jQuery操作
2017/07/23 PHP
php工具型代码之印章抠图
2018/07/18 PHP
javaScript - 如何引入js代码
2021/03/09 Javascript
JS 自动安装exe程序
2008/11/30 Javascript
php+js实现倒计时功能
2014/06/02 Javascript
js实现浏览器窗口大小被改变时触发事件的方法
2015/02/02 Javascript
javascript中callee与caller的区别分析
2015/04/20 Javascript
angularjs封装bootstrap时间插件datetimepicker
2016/06/20 Javascript
网页爬虫之cookie自动获取及过期自动更新的实现方法
2018/03/06 Javascript
vue地区选择组件教程详解
2018/05/04 Javascript
Vue CLI3移动端适配(px2rem或postcss-plugin-px2rem)
2020/04/27 Javascript
Vue-cli assets SubDirectory及PublicPath区别详解
2020/08/18 Javascript
python实现获取客户机上指定文件并传输到服务器的方法
2015/03/16 Python
python读取与写入csv格式文件的示例代码
2017/12/16 Python
Python实现控制台中的进度条功能代码
2017/12/22 Python
python opencv 直方图反向投影的方法
2018/02/24 Python
Python获取二维矩阵每列最大值的方法
2018/04/03 Python
一篇文章弄懂Python中所有数组数据类型
2019/06/23 Python
python调用支付宝支付接口流程
2019/08/15 Python
Python warning警告出现的原因及忽略方法
2020/01/31 Python
css3 给页面加个半圆形导航条主要利用旋转和倾斜样式
2014/02/10 HTML / CSS
体育教育毕业生自荐信
2013/11/21 职场文书
优质护理服务演讲稿
2014/05/07 职场文书
酒店优秀员工事迹材料
2014/06/02 职场文书
邀请函范文
2015/02/02 职场文书
宾馆客房管理制度
2015/08/06 职场文书
唱歌比赛拉拉队口号
2015/12/25 职场文书
八年级作文之友谊
2019/12/02 职场文书
Python编写nmap扫描工具
2021/07/21 Python
手写实现JS中的new
2021/11/07 Javascript
Python内置的数据类型及使用方法
2022/04/13 Python
Win11安装升级时提示“该电脑必须支持安全启动”
2022/04/19 数码科技