实现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 相关文章推荐
javaScript让文本框内的最后一个文字的后面获得焦点实现代码
Jan 06 Javascript
IE6下拉框图层问题探讨及解决
Jan 03 Javascript
13 款最热门的 jQuery 图像 360 度旋转插件推荐
Dec 09 Javascript
jquery实现点击label的同时触发文本框点击事件的方法
Jun 05 Javascript
微信小程序 循环及嵌套循环的使用总结
Sep 26 Javascript
React根据宽度自适应高度的示例代码
Oct 11 Javascript
vue+vuex+axios+echarts画一个动态更新的中国地图的方法
Dec 19 Javascript
原生JS实现的自动轮播图功能详解
Dec 28 Javascript
Vue.js路由实现选项卡简单实例
Jul 24 Javascript
微信小程序一周时间表功能实现
Oct 17 Javascript
Js参数RSA加密传输之jsencrypt.js的使用
Feb 07 Javascript
Javascript设计模式之原型模式详细
Oct 05 Javascript
详解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
WordPress中重置文章循环的rewind_posts()函数讲解
2016/01/11 PHP
tp5 sum某个字段相加得到总数的例子
2019/10/18 PHP
Javascript 通过json自动生成Dom的代码
2010/04/01 Javascript
JQuery实现点击div以外的位置隐藏该div窗口
2013/09/13 Javascript
NodeJS学习笔记之Http模块
2015/01/13 NodeJs
javascript实现简单计算器效果【推荐】
2016/04/19 Javascript
jQuery控制li上下循环滚动插件用法实例(附demo源码下载)
2016/05/28 Javascript
深入解析JavaScript中的arguments对象
2016/06/12 Javascript
全面了解JavaScript对象进阶
2016/07/19 Javascript
浅谈JS中的bind方法与函数柯里化
2016/08/10 Javascript
angular-ngSanitize模块-$sanitize服务详解
2017/06/13 Javascript
理解 javascript 中的函数表达式与函数声明
2017/07/07 Javascript
JavaScript函数中的this四种绑定形式
2017/08/15 Javascript
JS实现简易换图时钟功能分析
2018/01/04 Javascript
nodejs基础之多进程实例详解
2018/12/27 NodeJs
微信小程序在ios下Echarts图表不能滑动的问题解决
2019/07/10 Javascript
js canvas实现俄罗斯方块
2020/10/11 Javascript
vant-ui组件调用Dialog弹窗异步关闭操作
2020/11/04 Javascript
[01:00:53]2018DOTA2亚洲邀请赛3月29日 小组赛B组 iG VS Secret
2018/03/30 DOTA
Django中处理出错页面的方法
2015/07/15 Python
无法使用pip命令安装python第三方库的原因及解决方法
2018/06/12 Python
Python判断字符串是否为字母或者数字(浮点数)的多种方法
2018/08/03 Python
Selenium鼠标与键盘事件常用操作方法示例
2018/08/13 Python
Python标准库使用OrderedDict类的实例讲解
2019/02/14 Python
python读取目录下所有的jpg文件,并显示第一张图片的示例
2019/06/13 Python
Python秒算24点实现及原理详解
2019/07/29 Python
python实现猜数字游戏
2020/03/25 Python
基于Python批量生成指定尺寸缩略图代码实例
2019/11/20 Python
Python 实现平台类游戏添加跳跃功能
2020/03/27 Python
西雅图的买手店:Totokaelo
2019/10/19 全球购物
电气专业推荐信范文
2013/11/18 职场文书
思想政治教育专业个人求职信范文
2013/12/20 职场文书
项目副经理岗位职责
2013/12/30 职场文书
《金色的脚印》教后反思
2014/04/23 职场文书
普通党员对照检查材料
2014/08/28 职场文书
民间借贷纠纷起诉书
2015/08/03 职场文书