实现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实现的简单折叠菜单(折叠面板)效果代码
Sep 16 Javascript
用户代理字符串userAgent可实现的四个识别
Sep 20 Javascript
JS判断当前页面是否在微信浏览器打开的方法
Dec 08 Javascript
JavaScript弹窗基础篇
Apr 27 Javascript
js实现楼层导航功能
Feb 23 Javascript
Mongoose实现虚拟字段查询的方法详解
Aug 15 Javascript
bootstrap multiselect下拉列表功能
Aug 22 Javascript
微信小程序 按钮滑动的实现方法
Sep 27 Javascript
前端必备插件之纯原生JS的瀑布流插件Macy.js
Nov 22 Javascript
详解在不使用ssr的情况下解决Vue单页面SEO问题
Nov 08 Javascript
vue-cli3 项目优化之通过 node 自动生成组件模板 generate View、Component
Apr 30 Javascript
Vue实现渲染数据后控制滚动条位置(推荐)
Dec 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
地摊中国 - 珍藏老照片
2020/08/18 杂记
php 定义404页面的实现代码
2012/11/19 PHP
PHP操作MySQL的mysql_fetch_* 函数的常见用法教程
2015/12/25 PHP
php编程每天必学之验证码
2016/03/03 PHP
js操作CheckBoxList实现全选/反选(在客服端完成)
2013/02/02 Javascript
jquery cookie的用法总结
2013/11/18 Javascript
让table变成exls的示例代码
2014/03/24 Javascript
JavaScript中匿名函数用法实例
2015/03/23 Javascript
jquery实现select下拉框美化特效代码分享
2015/08/18 Javascript
JS变量及其作用域
2017/03/29 Javascript
Angular2 自定义表单验证器的实现方法
2018/12/14 Javascript
详解JavaScript的变量
2019/04/04 Javascript
vue视图不更新情况详解
2019/05/16 Javascript
python实现的简单猜数字游戏
2015/04/04 Python
Python实现类似jQuery使用中的链式调用的示例
2016/06/16 Python
python组合无重复三位数的实例
2018/11/13 Python
python3使用pandas获取股票数据的方法
2018/12/22 Python
python如何解析配置文件并应用到项目中
2019/06/27 Python
python编写猜数字小游戏
2019/10/06 Python
Python Tkinter模块 GUI 可视化实例
2019/11/20 Python
python中numpy.empty()函数实例讲解
2021/02/05 Python
使用 css3 transform 属性来变换背景图的方法
2019/05/07 HTML / CSS
HTML5 Canvas——用路径描画线条实例介绍
2013/06/09 HTML / CSS
俄罗斯厨房产品购物网站:COOK HOUSE
2021/03/15 全球购物
高中生毕业学习总结的自我评价
2013/11/14 职场文书
求职信范文怎么写
2014/01/29 职场文书
文案策划专业自荐信
2014/07/07 职场文书
社区党建工作汇报材料
2014/08/14 职场文书
2015年党性分析材料
2014/12/19 职场文书
党校党性分析材料
2014/12/19 职场文书
清洁工岗位职责
2015/02/13 职场文书
军训通讯稿范文
2015/07/18 职场文书
小学生安全教育心得体会
2016/01/15 职场文书
话题作文之关于呼唤
2019/11/29 职场文书
如何利用golang运用mysql数据库
2022/03/13 Golang
Win11怎么修改电源模式?Win11修改电源模式的方法
2022/04/05 数码科技