详解几十行代码实现一个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 相关文章推荐
JavaScript继承方式实例
Oct 29 Javascript
javascript背景时钟实现方法
Jun 18 Javascript
JavaScript入门教程之引用类型
May 04 Javascript
AngularJS基础 ng-keypress 指令简单示例
Aug 02 Javascript
bootstrap table 表格中增加下拉菜单末行出现滚动条的快速解决方法
Jan 05 Javascript
原生JS改变透明度实现轮播效果
Mar 24 Javascript
作为老司机使用 React 总结的 11 个经验教训
Apr 08 Javascript
微信小程序开发之toast提示插件使用示例
Jun 08 Javascript
微信小程序调用PHP后台接口 解析纯html文本
Jun 13 Javascript
微信JSSDK调用微信扫一扫功能的方法
Jul 25 Javascript
vue通过过滤器实现数据格式化
Jul 20 Javascript
用vite搭建vue3应用的实现方法
Feb 22 Vue.js
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
跟我学小偷程序之成功偷取首页(第三天)
2006/10/09 PHP
php 获取当前访问的url文件名的方法小结
2010/02/08 PHP
PHP 全角转半角实现代码
2010/05/16 PHP
ThinkPHP 表单自动验证运用示例
2014/10/13 PHP
老生常谈PHP数组函数array_merge(必看篇)
2017/05/25 PHP
PHP实现表单提交数据的验证处理功能【防SQL注入和XSS攻击等】
2017/07/21 PHP
PHP后台实现微信小程序登录
2018/08/03 PHP
eclipse导入jquery包后报错的解决方法
2014/02/17 Javascript
SyntaxHighlighter 3.0.83使用笔记
2015/01/26 Javascript
JS+CSS实现的蓝色table选项卡效果
2015/10/08 Javascript
精通JavaScript的this关键字
2020/05/28 Javascript
不能不知道的10个angularjs英文学习网站
2016/03/23 Javascript
Bootstrap的Carousel配合dropload.js实现移动端滑动切换图片
2017/03/10 Javascript
JavaScript实现审核流程状态的动态显示进度条
2017/03/15 Javascript
ES6 Promise对象概念与用法分析
2017/04/01 Javascript
JS利用正则表达式实现简单的密码强弱判断实例
2017/06/16 Javascript
jQuery remove()过滤被删除的元素(推荐)
2017/07/18 jQuery
解决vue项目nginx部署到非根目录下刷新空白的问题
2018/09/27 Javascript
JavaScript深入V8引擎以及编写优化代码的5个技巧
2019/06/24 Javascript
微信小程序webview 脚手架使用详解
2019/07/22 Javascript
Vue 自定义指令实现一键 Copy功能
2019/09/16 Javascript
通过实例了解Nodejs模块系统及require机制
2020/07/16 NodeJs
vue动画—通过钩子函数实现半场动画操作
2020/08/09 Javascript
python实现文本文件合并
2015/12/29 Python
Python实现字典的遍历与排序功能示例
2017/12/23 Python
Python中捕获键盘的方式详解
2019/03/28 Python
pandas的qcut()方法详解
2019/07/06 Python
Pytorch实现LSTM和GRU示例
2020/01/14 Python
Python项目跨域问题解决方案
2020/06/22 Python
美国最大的旗帜经销商:Carrot-Top
2018/02/26 全球购物
荷兰在线啤酒店:Beerwulf
2019/08/26 全球购物
开会迟到检讨书
2014/01/08 职场文书
青年志愿者先进事迹
2014/05/06 职场文书
幼儿园安全教育月活动总结
2015/05/08 职场文书
邓小平文选读书笔记
2015/06/29 职场文书
nginx配置proxy_pass中url末尾带/与不带/的区别详解
2021/03/31 Servers