详解几十行代码实现一个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 相关文章推荐
跟随鼠标旋转的文字
Nov 30 Javascript
js检测网络是否具体连接功能的代码
May 23 Javascript
javascript中clipboardData对象用法详解
May 13 Javascript
jquery.validate表单验证插件使用方法解析
Nov 07 Javascript
使用JavaScript解决网页图片拉伸问题(推荐)
Nov 25 Javascript
Bootstrap列表组学习使用
Feb 09 Javascript
微信小程序中input标签详解及简单实例
May 18 Javascript
AngularJS 打开新的标签页实现代码
Sep 07 Javascript
vue router-link传参以及参数的使用实例
Nov 10 Javascript
Javascript之高级数组API的使用实例
Mar 08 Javascript
JS实现点击生成UUID的方法完整实例【基于jQuery】
Jun 12 jQuery
vue3如何优雅的实现移动端登录注册模块
Mar 29 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
PHP在Web开发领域的优势
2006/10/09 PHP
在IIS上安装PHP4.0正式版
2006/10/09 PHP
PHP开发中常用的8个小技巧
2008/08/27 PHP
php断点续传之如何分割合并文件
2014/03/22 PHP
php中的动态调用实例分析
2015/01/07 PHP
PHP会话控制实例分析
2016/12/24 PHP
php实现socket推送技术的示例
2017/12/20 PHP
jQuery向上遍历DOM树之parents(),parent(),closest()之间的区别
2013/12/02 Javascript
JavaScript中0和&quot;&quot;比较引发的问题
2016/05/26 Javascript
jQuery实现的模拟弹出窗口功能示例
2016/11/24 Javascript
详解数组Array.sort()排序的方法
2020/05/09 Javascript
jQuery插件FusionCharts实现的2D柱状图效果示例【附demo源码下载】
2017/03/06 Javascript
JavaScript 数据类型详解
2017/03/13 Javascript
jQuery获取table表中的td标签(实例讲解)
2017/07/28 jQuery
详解Vue 多级组件透传新方法provide/inject
2018/05/09 Javascript
用Nodejs实现在终端中炒股的实现
2020/10/18 NodeJs
vue 插槽简介及使用示例
2020/11/19 Vue.js
Python Web框架Flask信号机制(signals)介绍
2015/01/01 Python
Python操作MySQL简单实现方法
2015/01/26 Python
Python自动化部署工具Fabric的简单上手指南
2016/04/19 Python
Python基础篇之初识Python必看攻略
2016/06/23 Python
bluepy 一款python封装的BLE利器简单介绍
2019/06/25 Python
使用Python函数进行模块化的实现
2019/11/15 Python
浅析python内置模块collections
2019/11/15 Python
python 非线性规划方式(scipy.optimize.minimize)
2020/02/11 Python
python模拟点击网页按钮实现方法
2020/02/25 Python
Abe’s of Maine:自1979以来销售相机和电子产品
2016/11/21 全球购物
美国宠物美容和宠物用品购物网站:Cherrybrook
2018/12/07 全球购物
EJB与JAVA BEAN的区别
2016/08/29 面试题
什么是抽象
2015/12/13 面试题
爱心捐助倡议书
2014/05/19 职场文书
作风建设演讲稿
2014/05/23 职场文书
2015届本科毕业生自我鉴定
2014/09/27 职场文书
联村联户简报
2015/07/21 职场文书
详解Python生成器和基于生成器的协程
2021/06/03 Python
Win11 Build 22000.51版本文件资源管理器“命令栏”和上下文菜单有什么新变化?
2021/11/21 数码科技