实现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 相关文章推荐
原生JS实现加入收藏夹的代码
Oct 24 Javascript
JS中的log对象获取以及debug的写法介绍
Mar 03 Javascript
JavaScript获取文本框内选中文本的方法
Feb 20 Javascript
分享一些常用的jQuery动画事件和动画函数
Nov 27 Javascript
Angularjs处理页面闪烁的解决方法
Mar 09 Javascript
ES6新特性之变量和字符串用法示例
Apr 01 Javascript
原生JS实现圆环拖拽效果
Apr 07 Javascript
详解vue2父组件传递props异步数据到子组件的问题
Jun 29 Javascript
webuploader分片上传的实现代码(前后端分离)
Sep 10 Javascript
微信小程序调用微信支付接口的实现方法
Apr 29 Javascript
vue实现pdf文档在线预览功能
Nov 26 Javascript
js实现轮播图效果 纯js实现图片自动切换
Aug 09 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
php记录日志的实现代码
2011/08/08 PHP
php实例分享之mysql数据备份
2014/05/19 PHP
PHP模拟post提交数据方法汇总
2016/02/16 PHP
使用PHPExcel实现数据批量导出为excel表格的方法(必看)
2017/06/09 PHP
基于 Swoole 的微信扫码登录功能实现代码
2018/01/15 PHP
javascript 强制刷新页面的实现代码
2009/12/13 Javascript
jQuery 处理表单元素的代码
2010/02/15 Javascript
JS下高效拼装字符串的几种方法比较与测试代码
2010/04/15 Javascript
jQuery监控文本框事件并作相应处理的方法
2015/04/16 Javascript
JavaScript中的lastIndexOf()方法使用详解
2015/06/06 Javascript
JS根据生日月份和日期计算星座的简单实现方法
2016/11/24 Javascript
jQuery插件FusionCharts实现的Marimekko图效果示例【附demo源码】
2017/03/24 jQuery
vue2+el-menu实现路由跳转及当前项的设置方法实例
2017/11/07 Javascript
JS数组扁平化(flat)方法总结详解
2019/06/24 Javascript
Servlet返回的数据js解析2种方法
2019/12/12 Javascript
Ant Design的可编辑Tree的实现操作
2020/10/31 Javascript
[56:47]Ti4 循环赛第三日 iG vs Liquid
2014/07/12 DOTA
再谈Python中的字符串与字符编码(推荐)
2016/12/14 Python
python中执行shell的两种方法总结
2017/01/10 Python
python中子类调用父类函数的方法示例
2017/08/18 Python
基于Python os模块常用命令介绍
2017/11/03 Python
Python 单元测试(unittest)的使用小结
2018/11/14 Python
解决Tensorboard 不显示计算图graph的问题
2020/02/15 Python
django在开发中取消外键约束的实现
2020/05/20 Python
Python 列表反转显示的四种方法
2020/11/16 Python
CSS3 实现图形下落动画效果
2020/11/13 HTML / CSS
澳大利亚新奇小玩意网站:Yellow Octopus
2017/12/28 全球购物
有机童装:Toby Tiger
2018/05/23 全球购物
武汉东之林科技有限公司机试
2013/09/17 面试题
信息管理应届生求职信
2014/03/07 职场文书
文明班级建设方案
2014/05/15 职场文书
离婚协议书范本(2014版)
2014/09/28 职场文书
党员廉洁自律个人总结
2015/02/13 职场文书
培训师岗位职责
2015/02/14 职场文书
小学数学国培研修日志
2015/11/13 职场文书
基于Golang 高并发问题的解决方案
2021/05/08 Golang