vue 简单实现vuex原理

2023-11-05

效果图如下:

在这里插入图片描述

1. 准备好环境

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

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

yarn add vuex安装vuex创建一个store文件夹并使用:
在这里插入图片描述

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:
在这里插入图片描述

白银版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:
在这里插入图片描述

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>
...
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue 简单实现vuex原理 的相关文章

  • 拓展:vue 父组件调用子组件方法ref(且父组件可通过ref调用的方法传值给子组件)

    1 ref被用来给元素或子组件注册引用信息 引用信息将会注册在父组件的 refs对象上 一 ref被用来给元素或子组件注册引用信息 引用信息将会注册在父组件的 refs对象上 div class formBtn fl 111 div div
  • Vuex getter 未更新

    我有以下吸气剂 withEarmarks state gt var count 0 for let l of state laptops if l earmarks length gt 0 count return count 在组件中 这
  • 在自定义指令中模拟 v-if 指令

    我需要销毁 v if 等自定义指令中的元素 如果条件失败 则禁止创建项目 我尝试这个 export const moduleDirective DirectiveOptions DirectiveFunction el binding vn
  • Vuex 存储在 NUXT 中间件中未定义

    我正在练习 NUXT 从教程来看它运行良好 我的在进入NUXT中间件时失败 逻辑是 如果页面重定向到其他页面 它将进入中间件并使用 axios 获取结果 中间件 search js import axios from axios expor
  • vue的组件

    在Vue中 组件是可复用的代码块 用于构建用户界面 Vue的组件系统允许您将界面拆分为独立的 可重复使用的部件 提供了更好的代码组织和复用性 以下是在Vue中创建组件的基本步骤 创建一个组件实例 可以使用Vue extend 方法创建一个V
  • 如何在vue js中使div可拖动?

    我在 vue 组件中有一个 div 我想让该组件可拖动 我检查了许多 vue 可拖动插件 但它们有一个单独的拖动组件 而不是像在角度可拖动中那样作为指令添加 请在这件事上给予我帮助 您需要将 vuedraggable 添加到节点模块中 纱线
  • Vue DOM 对计算属性没有反应

    我有一个按钮 如果计算属性的有效属性为 false 则该按钮设置为禁用 如果为 true 则应启用该按钮并允许用户移至当前流程中的下一步 我的 currentStep 计算属性正在根据当前步骤输入的更改完美更新 但按钮 disabled c
  • 在 Vuex Store 中分页时维护状态

    我正在对来自 Vuex 商店的数据进行分页 我能够成功完成此操作 但在将数据添加到购物车时遇到问题 我只能将一项添加到购物车中 添加第二项时出现 无法读取未定义的属性 id 错误 我已经改用 Vuex 状态映射 它可以工作 但我仍然收到错误
  • 使用 Vuex 突变更新对象引用的正确方法是什么?

    当对象引用传递到 Vue 子组件时 并且我想更新对象属性之一的值 使用 Vuex 最简单的方法是将对象引用和新值传递给突变 然后 突变只是更新传递对象的属性 这是合法的吗 这似乎有点太简单了 而且接近冗余 因为我可以在组件本身中进行重新分配
  • 使用 Vue 3 Composition API 创建全局商店

    我正在尝试仅使用 Vue 3 Composition API 创建一个全局商店 到目前为止 我一直在做实验 并且阅读了很多如何使用 Composition API 但知道我不知道如何使用provide和inject 我所知道的是provid
  • 访问嵌套对象时 Vue 发出警告

    我不知道为什么在访问嵌套对象时会收到 Vue 警告 user area name Vue warn 渲染错误 TypeError 无法读取未定义的属性 名称 类型错误 无法读取未定义的属性 名称 仅访问该对象没有任何警告 user name
  • Nuxt.js - API 调用的最佳场所

    我是 Vue js Nuxt 和所有前端东西的新手 我有一个关于 API 调用的问题 我不确定什么是正确的方法 这里的最佳实践是什么 我有一家商店 在该商店中 我有调用我的 API 并设置状态的操作 例如 async fetchArticl
  • 如何防止 Vuex 干扰我的类实例?

    我试图在 Vuex 中存储一个类的实例 EditorState https prosemirror net docs ref state EditorState来自散文镜 这个类从外部来看或多或少是不可变的 这意味着每当我想对其进行更改时
  • 无法访问 Axios 拦截器内的 Vuex 存储突变

    EDIT 这个问题非常混乱 所以我基本上用相同的代码示例和相同的场景重写它 当服务器发送 401 错误响应时 我试图 commit从拦截器到我的 vuex 存储 import axios from axios import store fr
  • 数据变量没有从 Vue.js 中使用 Vuex 的计算属性的观察者更新

    Fiddle https jsfiddle net mjvu6bn7 https jsfiddle net mjvu6bn7 我有一个计算属性的观察者 它依赖于 Vuex 存储变量 该变量是异步设置的 当这个计算属性发生变化时 我试图设置
  • 类型错误:无法读取未定义的属性“getters”

    我正在尝试测试一个引用 Vuex 商店的基本 Vue 组件 我以为我遵循了 Vue 的例子 https vue test utils vuejs org guides using with vuex html mocking getters
  • 如果用户在 Laravel 中经过身份验证,如何检查 Vue 组件?

    正如标题所述 我有点困惑如何根据用户是否登录并使用 Laravel 的 Auth 外观进行身份验证 使用 if else 语句处理 Vue 组件中的方法 我正在发出各种 Axios 请求 我需要根据用户是否登录来允许 禁止这些请求 我有 V
  • 构建 Vue 微前端应用程序(带有路由和 vuex 存储)

    我需要帮助配置使用 Vuex Vue Router 和 Vue i18n 的微前端应用程序的构建 分发 TL DR 我在构建将导入到现有系统中的微前端应用程序时遇到问题 我们的团队尝试通过 vue cli service 和 vue web
  • Web 扩展中共享 vuex 状态(死对象问题)

    我正在尝试在网络扩展中使用共享的 vue js 状态 状态存储在后台脚本的 DOM 中并呈现在弹出页面中 第一次尝试 我的第一次尝试是使用一个没有 vuex 的简单商店 背景 js var store count 0 popup js br
  • 不使用Vue可以使用Vuex吗? (Vuex 服务器端?)

    Vuex 抱怨如果不调用 Vue use Vuex 就无法创建新的 store 实例 虽然这通常没问题 但我正在摆弄使用同一商店编写后端 前端的想法 有人知道答案吗 Thanks TL DR 你可以在 Node 中完美使用 Vuex 无需浏

随机推荐

  • 90道渗透测试面试题(附答案)

    2023年已经快过去一半了 不知道小伙伴们有没有找到自己心仪的工作呀 最近后台收到不少小伙伴说要我整理一些渗透测试的面试题 今天它来了 觉得对你有帮助的话记得点个赞再走哦 1 什么是渗透测试 渗透测试是一种评估计算机系统 网络或应用程序的安
  • 四.javascript对象

    目录 一 对象的介绍 1 对象的概念 2 对象的属性 3 对象的方法 二 创建对象 1 使用构造函数创建内置对象 2 直接创建自定义对象 3 使用自定义构造函数创建对象 三 对象的属性 1 设置对象的属性 2 存取对象属性 3 属性的枚举
  • 使用gpt和mindshow快速制作PPT

    目录 准备工具 PPT制作大体流程 工具 步骤 获取PPT大纲 注意 要markdown格式 编辑 打开MindShow 找不到的可以私信我 编辑 创建ppt 编辑 选择ppt基本样式 编辑 点击下载 不过要提前登录一下就好 编辑 添加动画
  • Qt(c++)调用python一直报错slot、hypot等

    最近在Qt里调用python代码 参考教程 https blog csdn net a137748099 article details 119217197 引入python的include libs之后 在c 里写了简单的调用python
  • 各种通信方式对比

    各种通信方式对比 2011年11月09日 16 58 25 horatio2010 阅读数 444 通信名称 连接端 通信方式 传输顺序 通信速度 I2C scl sda 2 串行 高位 低位 标准模式速度100kbit s 快速模式
  • 前后端常见的几种鉴权方式

    本文链接 https blog csdn net wang839305939 article details 78713124 最近在重构公司以前产品的前端代码 摈弃了以前的session cookie鉴权方式 采用token鉴权 忙里偷闲
  • C#深拷贝和浅拷贝的区别

    先上代码 后解释 public class Person public int Age public DateTime BirthDate public string Name public IdInfo IdInfo
  • C++ Templates:实例化

    延迟实例化 当隐式实例化类模板时 同时也实例化了该模板的每个成员声明 但并没有实例化相应的定义 然而 存在例外 1 如果类模板包含了一个匿名的union 那么该union定义的成员同时也被实例化了 2 作为实例化类模板的结果 虚函数的定义可
  • react ref和组件API

    介绍 昨天学习到了生命周期 今天我们接着昨天的知识点继续学习 今天学习一下state setState以及ref和组件API 大家感兴趣的话可以跟随文章进行学习呦 state和setState state 组件自身状态 setState u
  • 【100%通过率 】【华为OD机试真题】模拟商场优惠打折(一)【2022 Q4

    华为OD机试 题目列表 2023Q1 点这里 2023华为OD机试 刷题指南 点这里 题目描述 模拟商场优惠打折 有三种优惠券可以用 满减券 打折券和无门槛券 满减券 满100减10 满200减20 满300减30 满400减40 以此类推
  • 辛普森悖论

    本系列主要为大家带来一整套的博弈论问题 广义 因为在面试的过程中 除了常规的算法题目 我们经常也会被问到一些趣味题型来考察思维 而这类问题中 很多都有博弈论的影子存在 这些公司里以FLAG Facebook LinkedIn Amazon
  • webpack5.x性能优化之 代码分包 配置文件分离 多入口 SplitChunks cacheGroups runtimeChunk dynamic import(动态导入) 懒加载 魔法注释

    webpack优化 文章目录 webpack优化 代码分离 认识代码分离 多入口起点 Entry Dependencies 入口依赖 SplitChunks chunks 其他的splitChunks属性 很少手动配置 minSize和ma
  • java多线程---C++没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序的设计。

    多线程 Java 的特点之一就是内置对多线程的支持 多线程允许同时完成多个任务 实际上多线程使人产生多个任务在同时执行的错觉 因为目前的计算机的处理器在同一时刻只能执行一个线程 但处理器可以在不同的线程之间快速地切换 由于处理器速度非常快
  • uni-app 和 spring boot 实现通知栏消息推送 (第二版)

    背景 上次第一版打包上线后 无法使用推送失效 第一版使用的是 websocket h5puls 原因 估计是云打包后对这个做了一些编译处理 导致失效 解决方案 用官网的教程 走个推服务器 取消后端自己的websocket实现 虽然麻烦 但是
  • 深度学习入门(四):经典网络架构(Alexnet、Vgg、Resnet)

    一 经典网络架构 Alexnet 2012年ImageNet竞赛冠军 8层神经网络 5层卷积层 3层全连接 二 经典网络架构 Vgg 2014 年ImageNet 竞赛冠军 VGG 最大的特点就是它在之前的网络模型上 通过比较彻底地采用 3
  • Excutor线程池原理详解

    目录 一 线程池的创建以及参数 二 任务提交的方法 三 线程池参数解释 四 线程池原理 五 线程池原理图 六 execute方法执行流程图 一 线程池的创建以及参数 public ThreadPoolExecutor int corePoo
  • vue3.0版本给对象新增属性

    对象新增属性 Reflect set 目标对象 属性名 值 Reflect set val middle middle
  • Spring Cloud Alibaba 2021.0.1.0 版本发布啦

    01 什么是 Spring Cloud Alibaba Aliware Spring Cloud Alibaba 是由阿里巴巴 后文简称 阿里 中间件团队于 2018 年 7 月开源 为业界提供的一套基于阿里内部分布式技术的一站式微服务构建
  • JavaWeb学习-Servlet处理解析JSON文件导出Excel实例

    文章目录 前言 一 实例要求 二 主要问题点 1 保存请求中的文件 2 JSON的简单处理 3 Servlet共享数据 实现勾选信息导出为excel 三 源码 总结 前言 这里是javaweb小白第一次尝试写博客 主要是想记录一下自己在学习
  • vue 简单实现vuex原理

    效果图如下 1 准备好环境 使用 vue cil 初始化项目配置 npm install g vue cli 全局安装 vue cli vue create demo vue 创建项目 yarn add vuex安装vuex创建一个stor