实现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 相关文章推荐
基于jquery的一个图片hover的插件
Apr 24 Javascript
读jQuery之二(两种扩展)
Jun 11 Javascript
javascript算法题 求任意一个1-9位不重复的N位数在该组合中的大小排列序号
Jul 21 Javascript
JS限制Textarea文本域字符个数的具体实现
Aug 02 Javascript
详解JavaScript对象和数组
Dec 03 Javascript
详解JavaScript中的事件流和事件处理程序
May 20 Javascript
浅谈JavaScript中数组的增删改查
Jun 20 Javascript
js 提交form表单和设置form表单请求路径的实现方法
Oct 25 Javascript
vue中设置height:100%无效的问题及解决方法
Jul 27 Javascript
React注册倒计时功能的实现
Sep 06 Javascript
详解Vue、element-ui、axios实现省市区三级联动
May 07 Javascript
原生JS实现列表内容自动向上滚动效果
May 22 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 读取文件的正确方法
2009/04/29 PHP
通过php添加xml文档内容的方法
2015/01/23 PHP
php版微信数据统计接口用法示例
2016/10/12 PHP
PHP输出XML格式数据的方法总结
2017/02/08 PHP
ThinkPHP3.2框架自定义配置和加载用法示例
2018/06/14 PHP
js的with语句使用方法
2007/09/21 Javascript
关于B/S判断浏览器断开的问题讨论
2008/10/29 Javascript
JQuery插件fancybox无法在弹出层使用左右键的解决办法
2013/12/25 Javascript
jquery控制display属性为none或block
2014/03/31 Javascript
jQuery基于cookie实现的购物车实例分析
2015/12/24 Javascript
js图片延迟加载(Lazyload)三种实现方式
2017/03/01 Javascript
Vue实现购物车功能
2017/04/27 Javascript
让微信小程序支持ES6中Promise特性的方法详解
2017/06/13 Javascript
AngularJS 将再发布一个重要版本 然后进入长期支持阶段
2018/01/31 Javascript
不使用JavaScript实现菜单的打开和关闭效果demo
2018/05/01 Javascript
Vue实现本地购物车功能
2018/12/05 Javascript
基于node简单实现RSA加解密的方法步骤
2019/03/21 Javascript
使用VueCli3+TypeScript+Vuex一步步构建todoList的方法
2019/07/25 Javascript
js实现漂亮的星空背景
2019/11/01 Javascript
微信小程序使用 vant Dialog组件的正确方式
2020/02/21 Javascript
在elementui中Notification组件添加点击事件实例
2020/11/11 Javascript
[01:56]生活中的妖精之七夕特别档
2016/08/09 DOTA
python实现类的静态变量用法实例
2015/05/08 Python
使用Django的模版来配合字符串翻译工作
2015/07/27 Python
python爬虫之xpath的基本使用详解
2018/04/18 Python
python使用循环打印所有三位数水仙花数的实例
2018/11/13 Python
使用turtle绘制五角星、分形树
2019/10/06 Python
Python实现从N个数中找到最大的K个数
2020/04/02 Python
CSS3模拟动画下拉菜单效果
2017/04/12 HTML / CSS
综合办公室个人的自我评价
2013/12/22 职场文书
搞笑婚前保证书
2015/02/28 职场文书
电工生产实习心得体会
2016/01/22 职场文书
幼儿园2016年感恩节活动总结
2016/04/01 职场文书
导游词之青城山景区
2019/09/27 职场文书
MySQL数据库 安全管理
2022/05/06 MySQL
Docker安装MySql8并远程访问的实现
2022/07/07 Servers