详解几十行代码实现一个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+ajax 购物车框架(入门篇)
Oct 29 Javascript
jQuery教程 $()包装函数来实现数组元素分页效果
Aug 13 Javascript
随鼠标移动的时钟非常漂亮遗憾的是只支持IE
Aug 12 Javascript
node.js中的fs.realpath方法使用说明
Dec 16 Javascript
javascript跨域原因以及解决方案分享
Apr 08 Javascript
mvvm双向绑定机制的原理和实现代码(推荐)
Jun 07 Javascript
Three.js学习之正交投影照相机
Aug 01 Javascript
CSS3 3D 技术手把手教你玩转
Sep 02 Javascript
vue插件vue-resource的使用笔记(小结)
Aug 04 Javascript
Node.js搭建小程序后台服务
Jan 03 Javascript
express+vue+mongodb+session 实现注册登录功能
Dec 06 Javascript
2分钟实现一个Vue实时直播系统的示例代码
Jun 05 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
一个域名查询的程序
2006/10/09 PHP
一个SQL管理员的web接口
2006/10/09 PHP
10条PHP高级技巧[修正版]
2011/08/02 PHP
php实现mysql数据库分表分段备份
2015/06/18 PHP
PHP编写登录验证码功能 附调用方法
2016/05/19 PHP
php实现获取农历(阴历)、节日、节气的类与用法示例
2017/11/20 PHP
php菜单/评论数据递归分级算法的实现方法
2019/08/01 PHP
jquery 全局AJAX事件使用代码
2010/11/05 Javascript
javascript 窗口加载蒙板 内嵌网页内容
2010/11/19 Javascript
新鲜出炉的js tips提示效果
2011/04/03 Javascript
Safari5中alert的无限循环BUG
2011/04/07 Javascript
Javascript获取HTML静态页面参数传递值示例
2013/08/18 Javascript
jQuery取得select选择的文本与值的示例
2013/12/09 Javascript
js/jquery判断浏览器的方法小结
2014/09/02 Javascript
Jqgrid之强大的表格插件应用
2015/12/02 Javascript
AngularJS实现树形结构(ztree)菜单示例代码
2016/09/18 Javascript
JavaWeb表单及时验证功能在输入后立即验证(含用户类型,性别,爱好...的验证)
2017/06/09 Javascript
vue实现全选和反选功能
2017/08/31 Javascript
bootstrap-Treeview实现级联勾选
2017/11/23 Javascript
vue.js $refs和$emit 父子组件交互的方法
2017/12/20 Javascript
Mint-UI时间组件起始时间问题及时间插件使用
2018/08/20 Javascript
JS实现匀速与减速缓慢运动的动画效果封装示例
2018/08/27 Javascript
Ant Design moment对象和字符串之间的相互转化教程
2020/10/27 Javascript
matplotlib 纵坐标轴显示数据值的实例
2018/05/25 Python
python保存数据到本地文件的方法
2018/06/23 Python
让Python脚本暂停执行的几种方法(小结)
2019/07/11 Python
大学生最常用的自我评价
2013/12/07 职场文书
一年级家长会邀请函
2014/01/25 职场文书
机关单位动员会主持词
2014/03/20 职场文书
赔偿协议书范本
2014/04/15 职场文书
5.12护士节演讲稿
2014/04/30 职场文书
出资证明书范本(标准版)
2014/09/24 职场文书
乡镇群众路线专项整治方案
2014/11/03 职场文书
2015年中学元旦晚会活动方案
2014/12/09 职场文书
研究生导师评语
2014/12/31 职场文书
尼克胡哲观后感
2015/06/08 职场文书