实现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…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
ui框架-文件列表展示
ui框架-文件列表展示 介绍 UI框架的文件列表展示组件,可以展示文件夹,支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项,适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...
node.js的初步学习
那什么是node.js呢? 和JavaScript又是什么关系呢? node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说, 需要在node.js的环境上进行当JavaScript作为前端开发语言来说,需要在浏览器的环境上进行 Node.js 可…...
