实现vuex源码,手写
实现vuex源码,手写
Vuex 是专门为 Vue.js 应用程序开发的状态管理模式 + 库,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
第一步:定义初始化Store类
创建文件夹store/vuex.js
1.定义 Store 类:
- 创建一个名为
Store的类,它接受一个options对象作为参数。 - 在
options对象中,包含state(应用的状态)、mutations(同步更改状态的方法)、actions(异步操作或包含任意异步操作的方法)、以及getters(从 state 中派生出一些状态的方法)。
let Vue;
class Store{constructor(options) {}
}
2.初始化 Vue 实例:
- 在
Store类的构造函数中,使用new Vue({ data: { $$state: options.state } })创建一个 Vue 实例,用于响应式地存储状态。这里使用$$state作为属性的名称是为了避免与 Vue 实例自身的state属性冲突,但这不是必须的,只是一个命名约定。
let Vue;
class Store{constructor(options) {this._vm = new Vue({data:{$$state:options.state}})}
}
3.存储 mutations 和 actions:
- 将
options.mutations和options.actions分别存储在this._mutations和this._actions中。
let Vue;
class Store{constructor(options) {this._vm = new Vue({data:{$$state:options.state}})this._mutations = options.mutationsthis._actions = options.actions}
}
4.绑定 commit 和 dispatch 方法:
- 使用
Function.prototype.bind方法将commit和dispatch方法绑定到Store实例上,以确保在回调函数中this指向正确。
let Vue;
class Store{constructor(options) {this._vm = new Vue({data:{$$state:options.state}})this._mutations = options.mutationsthis._actions = options.actionsthis.commit = this.commit.bind(this)this.dispatch = this.dispatch.bind(this)}
}
5.初始化 getters:
- 创建一个空对象
this.getters用于存储 getter 方法。 - 如果
options.getters存在,则调用this.handleGetters(options.getters)方法来初始化 getters。
let Vue;
class Store{constructor(options) {this._vm = new Vue({data:{$$state:options.state}})this._mutations = options.mutationsthis._actions = options.actionsthis.commit = this.commit.bind(this)this.dispatch = this.dispatch.bind(this)this.getters = {}options.getters && this.hanleGetters(options.getters)}
}
第二步:实现 handleGetters 方法和其他 Store 方法
1.实现 handleGetters 方法:
- 在
handleGetters方法中,遍历getters对象的键。 - 使用
Object.defineProperty在this.getters对象上定义每个 getter 属性,其get方法返回getters[key](this.state)的结果。
let Vue;
class Store{constructor(options) {this._vm = new Vue({data:{$$state:options.state}})this._mutations = options.mutationsthis._actions = options.actionsthis.commit = this.commit.bind(this)this.dispatch = this.dispatch.bind(this)this.getters = {}options.getters && this.hanleGetters(options.getters)}handleGetters(getters){Object.key(getters).map((key)=>{Object.defineProperty(this.getters,key,get: () => getters[key](this.state)})})}
}
2.实现 state 的 getter 和 setter:
- 使用
get state()方法来访问 Vue 实例中存储的状态。 - 使用
set state(v)方法来防止直接修改状态(虽然在这里,setter 只是打印了一个错误消息)。
let Vue;
class Store{constructor(options) {this._vm = new Vue({data:{$$state:options.state}})this._mutations = options.mutationsthis._actions = options.actionsthis.commit = this.commit.bind(this)this.dispatch = this.dispatch.bind(this)this.getters = {}options.getters && this.hanleGetters(options.getters)}handleGetters(getters){Object.key(getters).map((key)=>{Object.defineProperty(this.getters,key,get: () => getters[key](this.state)})})}//get setget state(){return this._vm.data.$$state}set state(v) {console.error("please provide");}
}
3.实现 commit 方法:
commit方法用于触发 mutations,它接受一个type(mutation 的类型)和一个可选的payload(传递给 mutation 的数据)。- 根据
type从this._mutations中找到对应的 mutation 方法,并调用它,传入this.state和payload。
let Vue;
class Store{constructor(options) {this._vm = new Vue({data:{$$state:options.state}})this._mutations = options.mutationsthis._actions = options.actionsthis.commit = this.commit.bind(this)this.dispatch = this.dispatch.bind(this)this.getters = {}options.getters && this.hanleGetters(options.getters)}handleGetters(getters){Object.key(getters).map((key)=>{Object.defineProperty(this.getters,key,get: () => getters[key](this.state)})})}//get setget state(){return this._vm.data.$$state}set state(v) {console.error("please provide");}//commitcommit(type,value){const entry = this._mutations[type]if(!entry){console.error("please provide");}entry(this.state,value)}
}
4.实现 dispatch 方法:
dispatch方法用于触发 actions,它的工作原理与commit类似,但通常用于处理异步操作。
let Vue;
class Store{constructor(options) {this._vm = new Vue({data:{$$state:options.state}})this._mutations = options.mutationsthis._actions = options.actionsthis.commit = this.commit.bind(this)this.dispatch = this.dispatch.bind(this)this.getters = {}options.getters && this.hanleGetters(options.getters)}handleGetters(getters){Object.key(getters).map((key)=>{Object.defineProperty(this.getters,key,get: () => getters[key](this.state)})})}//get setget state(){return this._vm.data.$$state}set state(v) {console.error("unknown mutation type");}//commitcommit(type,value){const entry = this._mutations[type]if(!entry){console.error("please provide");}entry(this.state,value)}//dispatchdispatch(type,value){const entry = this._actions[type]if(!entry){console.error("unknown action type")}entry(this.state,value)}
}
第三步:安装现在自定义vuex插件,需要一个install方法
- 创建一个名为
install的函数,它接受一个 Vue 构造函数作为参数。 - 在
install函数中,将 Vue 构造函数存储在全局变量Vue中。 - 使用
Vue.mixin方法来全局注册一个 beforeCreate 钩子,该钩子会在每个 Vue 组件实例创建之前被调用。 - 在 beforeCreate 钩子中,检查
this.$options.store是否存在,如果存在,则将其赋值给Vue.prototype.$store,这样在任何 Vue 组件中都可以通过this.$store访问到 store 实例。
let Vue;
class Store{constructor(options) {this._vm = new Vue({data:{$$state:options.state}})this._mutations = options.mutationsthis._actions = options.actionsthis.commit = this.commit.bind(this)this.dispatch = this.dispatch.bind(this)this.getters = {}options.getters && this.hanleGetters(options.getters)}handleGetters(getters){Object.key(getters).map((key)=>{Object.defineProperty(this.getters,key,get: () => getters[key](this.state)})})}//get setget state(){return this._vm.data.$$state}set state(v) {console.error("unknown mutation type");}//commitcommit(type,value){const entry = this._mutations[type]if(!entry){console.error("please provide");}entry(this.state,value)}//dispatchdispatch(type,value){const entry = this._actions[type]if(!entry){console.error("unknown action type")}entry(this.state,value)}
}Store.install = (_vue)=>{Vue = _vueVue.mixin({beforeCreate(){if(this.$options.store){Vue.prototype.$store = this.$options.$store}}})
}
第四步:导出install,Store
let Vue;
class Store {constructor(options) {this._vm = new Vue({data: {$$state: options.state,},});this._mutations = options.mutations;this._actions = options.actions;this.commit = this.commit.bind(this);this.dispatch = this.dispatch.bind(this);this.getters = {};options.getters && this.handleGetters(options.getters);}handleGetters(getters) {console.log(Object.keys(getters))Object.keys(getters).map((key) => {Object.defineProperty(this.getters, key, {get: () => getters[key](this.state)});});}get state() {return this._vm._data.$$state;}set state(v) {console.error("please provide");}commit(type, payload) {console.log(type, payload)const entry = this._mutations[type];if (!entry) {console.error("unknown mutation type: " + type);}entry(this.state, payload);}dispatch(type, payload) {console.log(this._actions[type]);const entry = this._actions[type];if (!entry) {console.error("unknown mutation type: " + type);}entry(this.state, payload);}
}
const install = (_Vue) => {Vue = _Vue;Vue.mixin({beforeCreate() {if (this.$options.store) {Vue.prototype.$store = this.$options.store;}},});
};
export default {Store,install,
};
第五步:创建store/index.js
import Vue from 'vue'
// 引入自己的写的vuex,里面有一个对象{install},当你use时,会自动调用这个方法
import Vuex from './vuex.js'
Vue.use(Vuex)
//需要创建一个仓库并导出
//当new的时候,给Vuex.js中传入了一堆的东西
export default new Vuex.Store({state: {name: 1},//getters中虽然是一个方法,但是用时,可以把他当作属性getters: { // 说白了,就是vue中data中的computedpowerCount(state) {return state.name * 2},},// 改变状态:异步请求数据 事件 mutations: {add(state) {state.name++}},actions: {add(state) {setTimeout(() => {console.log(state)state.name = 30}, 1000);}}
})
第六步:在main中挂载store
/* eslint-disable vue/multi-word-component-names */
import Vue from 'vue'
import App from './App.vue'
import store from "./store.js"
Vue.config.productionTip = falsenew Vue({name:"main",store,render: h => h(App),
}).$mount('#app')
第七步:如何使用store
和vuex一样的用法,语法一样
<template><div>{{ $store.state.name }}{{ $store.getters.powerCount }}<button @click="add">123</button></div>
</template>
<script>
export default {name: "app",data() {return {}},methods:{add(){this.$store.commit('add')// this.$store.dispatch('add')console.log(this.$store.getters.powerCount)this.$store.handleGetters.powerCount}},mounted() { console.log(this.$store.state.name)}
}
</script>{{ $store.state.name }}{{ $store.getters.powerCount }}<button @click="add">123</button></div>
</template>
<script>
export default {name: "app",data() {return {}},methods:{add(){this.$store.commit('add')// this.$store.dispatch('add')console.log(this.$store.getters.powerCount)this.$store.handleGetters.powerCount}},mounted() { console.log(this.$store.state.name)}
}
</script>
相关文章:
实现vuex源码,手写
实现vuex源码,手写 Vuex 是专门为 Vue.js 应用程序开发的状态管理模式 库,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 第一步:定义初始化Store类 创建文件夹store/vuex.js 1…...
使用 Python 和 Pandas 处理 Excel 数据:合并单元格示例
引言 在数据处理过程中,我们经常会遇到需要从 Excel 文件中提取和处理数据的情况。本文将通过一个简单的示例,介绍如何使用 Python 的 Pandas 库来读取 Excel 文件,处理其中的合并单元格,并将结果输出到新的 Excel 文件中。(这里的合并是列1提取一个数据,列2提取两个数据…...
Python poetry 虚拟环境
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、Poetry是什么?二、使用步骤1.安装poetry2、初始化poetry3、创建虚拟环境 启动和退出虚拟环境poetry 常用指令总结 一、Poetry是什么? P…...
面试官:你会如何设计QQ中的网络协议?
引言 在设计QQ这道面试题时,我们需要避免进入面试误区。这意味着我们不应该盲目地开展头脑风暴,提出一些不切实际的想法,因为这些想法可能无法经受面试官的深入追问。因此,我们需要站在前人的基础上,思考如何解决这类…...
JVM—类的生命周期
目录 类的生命周期 加载阶段 连接阶段 验证阶段 准备阶段 解析阶段 初始化阶段 面试题1 面试题2 类的生命周期 类的生命周期描述了一个类加载、使用、卸载的整个过程,整体可以分为以下五个阶段。 1. 加载 2. 连接,其中又分为验证、准备、解析三…...
SELinux中的安全标记与强制访问控制
SELinux的安全标记和强制访问控制是如何实现的? SELinux(Security Enhanced Linux)是一个由美国国家安全局(NSA)开发的Linux内核模块,它实现了强制访问控制(MAC)。SELinux通过为系统…...
EasyExcel_动态表头的导入导出
文章目录 前言一、EasyExcel二、使用步骤1.引入jar包2.数据准备2.1 数据库 3.方法实例3.1 无实体的导入3.1.1 Controller3.1.2 Service3.1.3 Listener3.1.4 Utils3.1.5 无实体导入数据返回说明 3.2 无实体的导出3.2.1 无实体导出数据(这里只贴出关键代码,Service代码处理)3.2.2…...
uni-app简单模拟人脸识别
uni-app使用live-pusher简单模拟人脸识别页面样式 实现想法调起手机摄像头设置圆形 实现想法 公司的需求是模拟一个人脸识别,不用第三发插件,简单模拟样式即可。 基本思路是调起手机前置摄像头,再设置一个圆形的样式来达到一个基本样式 调起…...
华为HCIE-OpenEuler认证详解
华为HCIE认证(Huawei Certified ICT Expert)是华为提供的最高级别的专业认证,它旨在培养和认证在特定技术领域具有深厚理论知识和丰富实践经验的专家级工程师。对于华为欧拉(OpenEuler)方向的HCIE认证,即HC…...
从零开始的Go语言之旅(2 Go by Example: Values)
Go 语言有多种值类型,包括字符串、整数、浮点数、布尔值等。以下是一些基本示例。 package mainimport "fmt"func main() {fmt.Println("go" "lang")fmt.Println("11 ", 11)fmt.Println("7.0/3.0 ", 7.0/3.0)f…...
XShell 中实现免密登录 Linux 服务器的详细流程
个人主页:Jason_from_China-CSDN博客 所属栏目:Linux系统性学习_Jason_from_China的博客-CSDN博客 所属栏目:Linux知识点的补充_Jason_from_China的博客-CSDN博客 XShell 中实现免密登录 Linux 服务器的详细流程: 一、在本地生成…...
跨界创新|使用自定义YOLOv11和Ollama(Llama 3)增强OCR文本识别
《博主简介》 小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推…...
一些关于 WinCC Comfort 和 WinCC Advanced 脚本编程语言 VBS 的实用技巧
为什么一个由内部变量的 “数值更变” 事件触发的脚本不执行? 如果使用一个内部变量调用另外一个内部变量,以此,例如被调用的变量又去执行一个脚本(比如,根据变量变化),此时一个安全机制会阻止这…...
Java|乐观锁和悲观锁在自旋的时候分别有什么表现?
乐观锁和悲观锁是两种不同的并发控制策略,各自采用不同的机制来处理线程之间的资源竞争。 乐观锁 1. 定义 乐观锁是一种假设冲突不会发生的并发控制策略,通常不对资源进行加锁,而是在操作前不加锁,操作后再进行验证。乐观锁通常…...
Linux定时器定时任务清理log日志文件
首先,创建xx.sh文件,内容如下 #!/bin/bash sfecho "" > /var/lib/docker/containers/12379e809ea1294eea9b117368181cff1dd3915fdb1611f940c5cf3d6077d734/12379e809ea1294eea9b117368181cff1dd3915fdb1611f940c5cf3d6077d734-json.log 打…...
美国大学生数学建模竞赛(MCM/ICM)介绍
美国大学生数学建模竞赛(MCM/ICM)是一项具有较高影响力的国际赛事。以下是一份美赛教程: 一、前期准备 组队 寻找合适的队友,最好具备不同的专业技能,如数学、计算机、工程等。团队成员应具备良好的沟通能力、合作精神和责任心。明确各自的分工,例如有人负责建模、有人负…...
【独家:AI编程助手Cursor如何revolutionize Java设计模式学习】
【独家:AI编程助手Cursor如何revolutionize Java设计模式学习】 导语 在Java高级编程的世界里,设计模式是每个开发者必须掌握的利器。但是,如何快速理解并灵活运用这些模式呢?让我们一起探索如何借助AI编程助手Cursor,轻松掌握设计模式,提升Java编程技能! 正文 设计模式:J…...
数据仓库宽表概述
宽表是指一种将多个相关数据集整合到一个表中的数据建模方法,具有减少连接操作、提高查询性能、简化数据管理的优点。 一、宽表的定义 宽表,顾名思义,是一种在数据仓库中使用的表格形式,其特征是包含了大量的列。这种表格设计的…...
在数据库中编程 vs 在应用程序中编程
原文地址 https://brandur.org/fragments/code-database-vs-app 数据库领域有一个长期存在的问题:你是更愿意将应用逻辑放在更接近数据库本身的存储过程和触发器中,还是置于数据库之上的应用程序代码中? 没有客观正确的答案,只有…...
【设计模式系列】装饰器模式
目录 一、什么是装饰器模式 二、装饰器模式中的角色 三、装饰器模式的典型应用场景 四、装饰器模式在BufferedReader中的应用 一、什么是装饰器模式 装饰器模式是一种结构型设计模式,用于在不修改对象自身的基础上,通过创建一个或多个装饰类来给对象…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
