实现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中的应用 一、什么是装饰器模式 装饰器模式是一种结构型设计模式,用于在不修改对象自身的基础上,通过创建一个或多个装饰类来给对象…...
人工智能毕业设计2026方向集合
0 选题推荐 - 人工智能篇 毕业设计是大家学习生涯的最重要的里程碑,它不仅是对四年所学知识的综合运用,更是展示个人技术能力和创新思维的重要过程。选择一个合适的毕业设计题目至关重要,它应该既能体现你的专业能力,又能满足实际…...
Dramatron:AI驱动剧本创作的协同进化方法
Dramatron:AI驱动剧本创作的协同进化方法 【免费下载链接】dramatron Dramatron uses large language models to generate coherent scripts and screenplays. 项目地址: https://gitcode.com/gh_mirrors/dr/dramatron 问题:当代创作者的三重困境…...
像素时装锻造坊入门必看:预设咒语+Forge Scale滑块参数详解
像素时装锻造坊入门必看:预设咒语Forge Scale滑块参数详解 1. 工具介绍:像素时装锻造坊 像素时装锻造坊(Pixel Fashion Atelier)是一款基于Stable Diffusion与Anything-v5模型的图像生成工具。它采用独特的复古日系RPG界面设计&…...
海康WEBSDK无插件版实战:零基础构建WEB端网络摄像机实时监控系统
1. 环境准备:5分钟搞定基础配置 第一次接触海康WEBSDK无插件版时,我也被那些专业术语吓到过。但实际操作后发现,只要准备好三样东西就能开工:一台能联网的电脑、海康网络摄像机、以及从官网下载的开发包。这里分享几个新手容易踩的…...
大模型“预训练”是怎么回事
经常在想,大模型是怎么学会“理解和生成语言”的。仔细看,它的训练过程其实很有规律,简单讲可以拆解成几个步骤。数据准备 训练大模型之前,最重要的是数据。我看到的做法是从各种网络资源收集海量文本,比如网页、书籍、…...
iText7中文渲染完全指南:从乱码到完美显示的技术突破
iText7中文渲染完全指南:从乱码到完美显示的技术突破 【免费下载链接】itext7-chinese-font 项目地址: https://gitcode.com/gh_mirrors/it/itext7-chinese-font 在数字化文档处理领域,PDF格式以其跨平台一致性成为信息传递的首选。然而…...
VSCode配置STM32标准库开发环境:手把手解决core_cm3.c编译报错与头文件路径问题
VSCode搭建STM32开发环境:解决标准库兼容性与智能感知难题 当开发者从Keil或IAR转向VSCode时,往往会遇到两个棘手的拦路虎:标准库与GCC的兼容性问题,以及代码智能感知的缺失。本文将深入解决这两个核心痛点,带你构建一…...
8255A工作方式0实战:手把手教你用汇编语言驱动八路抢答器LED与数码管
8255A工作方式0实战:从零构建八路抢答器驱动框架 记得第一次在实验室见到8255A芯片时,那块黑色的DIP封装器件看起来平平无奇,直到它让八颗LED随着我的汇编指令跳起"灯光芭蕾"。本文将带你深入这个经典可编程并行接口芯片的实战应用…...
4个关键步骤解决Calibre中文路径乱码难题
4个关键步骤解决Calibre中文路径乱码难题 【免费下载链接】calibre-do-not-translate-my-path Switch my calibre library from ascii path to plain Unicode path. 将我的书库从拼音目录切换至非纯英文(中文)命名 项目地址: https://gitcode.com/gh_m…...
CTF是什么?一文带你读懂网络安全大赛
CTF是什么?一文带你读懂网络安全大赛 前言 随着大数据、人工智能的发展,人们步入了新的时代,逐渐走上科技的巅峰。 科技是一把双刃剑,网络安全不容忽视,人们的隐私在大数据面前暴露无遗,账户被盗、资金损失…...
