实现vuex原理的示例


Posted in Javascript onOctober 21, 2020

效果图如下:

实现vuex原理的示例

1. 准备好环境

使用 vue/cil 初始化项目配置:

npm install -g @vue/cli //全局安装@vue/cli vue create demo-vue //创建项目

yarn add vuex安装vuex创建一个store文件夹并使用:

实现vuex原理的示例

2. 实现目的

stroe/index.js内容如下:(我们的目的将引入自写的vuex实现vuex基础功能)

import Vue from 'vue'
import Vuex from 'vuex' 
// import Vuex from './myvuex'   //我们实现的 青铜版vuex
// import Vuex from './myvuexplus' //我们实现的 白银版vuex

Vue.use(Vuex) //执行install方法 将new Vuex.Store挂载到this.$store

export default new Vuex.Store({
 state: {
  counter: 0,
  userData: {
   name: '时间',
   age: 18
  }
 },
 getters: {
  name(state) {
   return state.userData.name
  }
 },
 mutations: {
  add(state) {
   state.counter++
  },
  updateName(state, payload) {
   state.userData.name = payload
  }
 },
 actions: {
  add({ commit }) {
   setTimeout(() => {
    commit('add')
   }, 1000);
  }
 }
})
  • 青铜版vuexmyvuex.js代码如下:
let Vue
class Store {
 constructor(options) {
  this._vm = new Vue({
   data: {
    state: options.state
   }
  })

  let getters = options.getters
  this.getters = {}
  Object.keys(getters).forEach((val) => {
   Object.defineProperty(this.getters, val, { //getters响应式
    get: () => {
     return getters[val](this.state)
    }
   })
  })

  this._actions = Object.assign({}, options.actions)
  this._mutations = Object.assign({}, options.mutations)
 }

 // get/set state目的:防止外部直接修改state
 get state() {
  return this._vm.state
 }
 set state(value) {
  console.error('please use replaceState to reset state')
 }

 commit = (funName, params) => { //this执行问题
  // 在mutations中找到funName中对应的函数并且执行
  this._mutations[funName](this.state, params)
 }

 dispatch(funName, params) {
  this._actions[funName](this, params)
 }
}

function install(vue) {
 Vue = vue
 vue.mixin({
  beforeCreate () {
   // 将 new Store() 实例挂载到唯一的根组件 this 上
   if (this.$options?.store) {
    this.$store = this.$options.store
   } else {
    this.$store = this.$parent && this.$parent.$store
   }
  }
 })
}

export default {
 Store,
 install
}

青铜版vuex this.$stroe:

实现vuex原理的示例

  • 白银版vuexmyvuexplus.js代码如下:
let _Vue
const install = function(Vue, opts) {
 _Vue = Vue
 _Vue.mixin({ // 因为我们每个组件都有 this.$store这个东西,所以我们使用混入模式
  beforeCreate () { // 从根组件向子组件遍历赋值,这边的 this 就是每个 Vue 实例
   if (this.$options && this.$options.store) { // 这是根节点
    this.$store = this.$options.store
   } else {
    this.$store = this.$parent && this.$parent.$store
   }
  }
 })
}

class ModuleCollection {
 constructor(opts) {
  this.root = this.register(opts)
 }

 register(module) {
  let newModule = {
   _raw: module,
   _state: module.state || {},
   _children: {}
  }
  Object.keys(module.modules || {}).forEach(moduleName => {
   newModule._children[moduleName] = this.register(module.modules[moduleName])
  })
  return newModule
 }
}

class Store {
 constructor(opts) {
  this.vm = new _Vue({
   data () {
    return {
     state: opts.state // 把对象变成响应式的,这样才能更新视图
    }
   }
  })

  this.getters = {}
  this.mutations = {}
  this.actions = {}

  // 先格式化传进来的 modules 数据
  // 嵌套模块的 mutation 和 getters 都需要放到 this 中
  this.modules = new ModuleCollection(opts)
  console.log(this.modules)

  Store.installModules(this, [], this.modules.root)
 }

 commit = (mutationName, value) => { // 这个地方 this 指向会有问题,这其实是挂载在实例上
  this.mutations[mutationName].forEach(f => f(value))
 }

 dispatch(actionName, value) {
  this.actions[actionName].forEach(f => f(value))
 }

 get state() {
  return this.vm.state
 }
}
Store.installModules = function(store, path, curModule) {
 let getters = curModule._raw.getters || {}
 let mutations = curModule._raw.mutations || {}
 let actions = curModule._raw.actions || {}
 let state = curModule._state || {}

 // 把子模块的状态挂载到父模块上,其他直接挂载到根 store 上即可
 if (path.length) {
  let parent = path.slice(0, -1).reduce((pre, cur) => {
   return pre[cur]
  }, store.state)
  _Vue.set(parent, path[path.length - 1], state)
 }

 Object.keys(getters).forEach(getterName => {
  Object.defineProperty(store.getters, getterName, {
   get: () => {
    return getters[getterName](state)
   }
  })
 })

 Object.keys(mutations).forEach(mutationName => {
  if (!(store.mutations && store.mutations[mutationName])) store.mutations[mutationName] = []
  store.mutations[mutationName].push(value => {
   mutations[mutationName].call(store, state, value)
  })
 })

 Object.keys(actions).forEach(actionName => {
  if (!(store.actions && store.actions[actionName])) store.actions[actionName] = []
  store.actions[actionName].push(value => {
   actions[actionName].call(store, store, value)
  })
 })

 Object.keys(curModule._children || {}).forEach(module => {
  Store.installModules(store, path.concat(module), curModule._children[module])
 })


}

// computed: mapState(['name'])
// 相当于 name(){ return this.$store.state.name }
const mapState = list => { // 因为最后要在 computed 中调用
 let obj = {}
 list.forEach(stateName => {
  obj[stateName] = () => this.$store.state[stateName]
 })
 return obj
}

const mapGetters = list => { // 因为最后要在 computed 中调用
 let obj = {}
 list.forEach(getterName => {
  obj[getterName] = () => this.$store.getters[getterName]
 })
 return obj
}

const mapMutations = list => {
 let obj = {}
 list.forEach(mutationName => {
  obj[mutationName] = (value) => {
   this.$store.commit(mutationName, value)
  }
 })
 return obj
}

const mapActions = list => {
 let obj = {}
 list.forEach(actionName => {
  obj[actionName] = (value) => {
   this.$store.dispatch(actionName, value)
  }
 })
 return obj
}

export default {
 install,
 Store,
 mapState,
 mapGetters,
 mapMutations,
 mapActions
}

白银版vuex this.$stroe:

实现vuex原理的示例

3. App.vue 内使用自写的vuex:

<template>
 <div id="app">
  <button @click="$store.commit('add')">$store.commit('add'): {{$store.state.counter}}</button>
  <br>
  <button @click="$store.commit('updateName', new Date().toLocaleString())">$store.commit('updateName', Date): {{$store.getters.name}}</button>
  <br>
  <button @click="$store.dispatch('add')">async $store.dispatch('add'): {{$store.state.counter}}</button>
 </div>
</template>
<script>
...

以上就是实现vuex原理的示例的详细内容,更多关于实现vuex原理的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
发两个小东西,ASP/PHP 学习工具。 用JavaScript写的
Apr 12 Javascript
js判读浏览器是否支持html5的canvas的代码
Nov 18 Javascript
AngularJS入门教程之表格实例详解
Jul 27 Javascript
jQuery实现的tab标签切换效果示例
Sep 05 Javascript
jQuery插件zTree实现获取当前选中节点在同级节点中序号的方法
Mar 08 Javascript
详谈javascript精度问题与调整
Jul 08 Javascript
一个Js文件函数中调用另一个Js文件函数的方法演示
Aug 14 Javascript
微信禁止下拉查看URL的处理方法
Sep 28 Javascript
vue富文本编辑器组件vue-quill-edit使用教程
Sep 21 Javascript
浅谈Node 异步IO和事件循环
May 05 Javascript
前端开发基础javaScript的六大作用
Aug 06 Javascript
Vue OpenLayer测距功能的实现
Apr 20 Vue.js
详解JavaScript类型判断的四种方法
Oct 21 #Javascript
node.js如何根据URL返回指定的图片详解
Oct 21 #Javascript
vue中template的三种写法示例
Oct 21 #Javascript
Vue使用v-viewer实现图片预览
Oct 21 #Javascript
UEditor 自定义图片视频尺寸校验功能的实现代码
Oct 20 #Javascript
Vue+axios封装请求实现前后端分离
Oct 23 #Javascript
构建一个JavaScript插件系统
Oct 20 #Javascript
You might like
PHP函数strip_tags的一个bug浅析
2014/05/22 PHP
php实现多城市切换特效
2015/08/09 PHP
PHP+MySQL存储数据常见中文乱码问题小结
2016/06/13 PHP
PHP实现原生态图片上传封装类方法
2016/11/08 PHP
php7 参数、整形及字符串处理机制修改实例分析
2020/05/25 PHP
动态表格Table类的实现
2009/08/26 Javascript
flash 得到自身url参数的代码
2009/11/15 Javascript
GreyBox技术总结(转)
2010/11/23 Javascript
js 在定义的时候立即执行的函数表达式(function)写法
2013/01/16 Javascript
BootStrapTable服务器分页实例解析
2016/12/20 Javascript
vue.js提交按钮时进行简单的if判断表达式详解
2018/08/08 Javascript
node.js之基础加密算法模块crypto详解
2018/09/11 Javascript
在Vue中获取组件声明时的name属性方法
2018/09/12 Javascript
vue实现抖音时间转盘
2019/09/08 Javascript
[06:30]DOTA2英雄梦之声_第15期_死亡先知
2014/06/21 DOTA
python搭建微信公众平台
2016/02/09 Python
Python内置函数OCT详解
2016/11/09 Python
Python 数据结构之旋转链表
2017/02/25 Python
Python 对象中的数据类型
2017/05/13 Python
Python简单计算数组元素平均值的方法示例
2017/12/26 Python
python numpy 显示图像阵列的实例
2018/07/02 Python
python3通过selenium爬虫获取到dj商品的实例代码
2019/04/25 Python
常用python爬虫库介绍与简要说明
2020/01/25 Python
基于Python3.6中的OpenCV实现图片色彩空间的转换
2020/02/03 Python
python 安装教程之Pycharm安装及配置字体主题,换行,自动更新
2020/03/13 Python
深入了解NumPy 高级索引
2020/07/24 Python
详解python中的异常捕获
2020/12/15 Python
详解用 python-docx 创建浮动图片
2021/01/24 Python
HTML5 Canvas API中drawImage()方法的使用实例
2016/03/25 HTML / CSS
SEPHORA丝芙兰德国官方购物网站:化妆品、护肤品和香水
2020/01/21 全球购物
英国现代、当代和设计师家具店:Furntastic
2020/07/18 全球购物
学校门卫管理制度
2014/01/30 职场文书
前厅收银主管岗位职责
2014/02/04 职场文书
秋季运动会活动方案
2014/02/05 职场文书
《木笛》教学反思
2014/03/01 职场文书
2014年人事专员工作总结
2014/11/19 职场文书