详解几十行代码实现一个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 相关文章推荐
Prototype使用指南之array.js
Jan 10 Javascript
斜45度寻路实现函数
Aug 20 Javascript
初试jQuery EasyUI 使用介绍
Apr 01 Javascript
通过js简单实现将一个文本内容转译成加密文本
Oct 22 Javascript
手写的一个兼容各种浏览器的javascript getStyle函数(获取元素的样式)
Jun 06 Javascript
js delete 用法(删除对象属性及变量)
Aug 24 Javascript
jQuery基础知识小结
Dec 22 Javascript
jQuery实现的多级下拉菜单效果代码
Aug 24 Javascript
BootStrap 智能表单实战系列(十)自动完成组件的支持
Jun 13 Javascript
完美解决JS文件页面加载时的阻塞问题
Dec 18 Javascript
js 输入框 正则表达式(菜鸟必看教程)
Feb 19 Javascript
JavaScript实现弹窗效果代码分析
Mar 09 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 管理系统程序中的后门
2009/08/05 PHP
php数据库连接时容易出错的特殊符号问题
2010/09/01 PHP
PHP中empty,isset,is_null用法和区别
2017/02/19 PHP
php微信公众号开发之二级菜单
2018/10/20 PHP
showModelessDialog()使用详解
2006/09/21 Javascript
情人节专属 纯js脚本1k大小的3D玫瑰效果
2012/02/11 Javascript
JQuery插件iScroll实现下拉刷新,滚动翻页特效
2014/06/22 Javascript
初始Nodejs
2014/11/08 NodeJs
浅谈js的setInterval事件
2014/12/05 Javascript
JavaScript中的this关键字使用详解
2015/08/14 Javascript
JavaScript学习总结之JS、AJAX应用
2016/01/29 Javascript
jQuery animate easing使用方法图文详解
2016/06/17 Javascript
解决vue router使用 history 模式刷新后404问题
2017/07/19 Javascript
微信小程序webview实现长按点击识别二维码功能示例
2019/01/24 Javascript
详解Vue中的基本语法和常用指令
2019/07/23 Javascript
JS实现单张或多张图片持续无缝滚动的示例代码
2020/05/10 Javascript
Node 使用express-http-proxy 做api网关的实现
2020/10/15 Javascript
Windows系统配置python脚本开机启动的3种方法分享
2015/03/10 Python
python写入中英文字符串到文件的方法
2015/05/06 Python
详解pyenv下使用python matplotlib模块的问题解决
2018/11/29 Python
Python 做曲线拟合和求积分的方法
2018/12/29 Python
Python实现滑动平均(Moving Average)的例子
2019/08/24 Python
Matplotlib使用Cursor实现UI定位的示例代码
2020/03/12 Python
python 连续不等式语法糖实例
2020/04/15 Python
Python错误的处理方法
2020/06/23 Python
详解PyQt5中textBrowser显示print语句输出的简单方法
2020/08/07 Python
梵蒂冈和罗马卡:Omnia Card Pass
2018/02/10 全球购物
英国领先的瓷砖专家:Walls and Floors
2018/04/27 全球购物
正宗的日本零食和糖果订阅盒:Bokksu
2019/11/21 全球购物
关于递归的一道.NET面试题
2013/05/12 面试题
创联软件面试题笔试题
2012/10/07 面试题
公务员的自我鉴定
2013/10/26 职场文书
培训通知书模板
2015/04/17 职场文书
2016优秀员工先进事迹材料
2016/02/25 职场文书
2016年综治和平安建设宣传月活动总结
2016/04/01 职场文书
一行代码python实现文件共享服务器
2021/04/22 Python