Vuex与Vuex-Class的底层原理简单实现

vuex-class是在class-component中使用vuex的辅助工具。

学习任何技术栈的使用,最透彻的掌握方法就是去简单实现一下,下面先简单实现一下vuex,然后基于我们自己实现的vuex再去实现一个vuex-class,彻底搞定vuex-class的使用。

首先回忆一下vuex的使用(配置)方法,首先我们需要在某个位置执行Vue.use(Vuex),然后通过new Vuex.Store的方式创建一个Store实例,在实例化Vue时将其传入配置对象:new Vue({store})

src/store/index.js

import Vue from 'vue';
import Vuex from 'vuex';
​
Vue.use(Vuex);
​
export default new Vuex.Store({state: {count: 0}
})

main.js

import Vue from 'vue'
import App from './App.vue'
import store from './store'
​
Vue.config.productionTip = false
​
new Vue({store,render: h => h(App),
}).$mount('#app')

经过如上的配置,我们就可以在组件中通过this.$store.xxx去访问Store对象的属性,使用statecommit

为了保留核心,删繁就简,我们自己的vuex只实现在组件中通过this.$store.state访问响应式state的能力。

实现vuex

思路分析

因为vue2中的组件其实就是一个对象,整个项目以App.vue作为根组件,与所有子组件构成了一个巨大的组件树,说白了就是一个对象树,并且基于当前组件对象可以通过$parent等属性访问组件树的相邻(父)组件。

那么我们既然要让所有组件都可以通过$store属性访问到store对象,那么就是很单纯的给所有组件都加一个$store属性就好了。

实现切入点

借助Vue的插件机制:Vue.use方法可以接收一个对象,并执行这个对象的install方法,Vue构造函数将作为install的参数,我们可以在install的逻辑中通过Vue.mixin给未来要实例化的所有组件注入逻辑!

代码实现

整个组件树挂载$store

Vuex对象中除了install方法之外,还要有一个Store构造函数(new Vuex.Store(...)),我们暂且不管这个构造函数究竟如何创建实例store,我们先让所有组件都能拿到它创建的实例store

因为在main.js中我们把store实例传给了new Vue的配置对象,也就是说可以通过根组件对象的$options.store拿到store

对于App.vue这个根组件,为了达成通过this.$store访问store对象的目的,我们完全可以在其beforeCreate生命周期中执行this.$store = this.$options.store,但是对于组件树上的任意组件我们无法访问到根组件,但熟悉vue渲染机制的话我们知道:组件的渲染是从外至内的,也就是先创建父组件再是其子组件,所以借助整个App渲染时从外至内的“遍历”顺序,我们可以轻松写出如下算法,即除了根组件之外,让所有组件都去$parent上去找store对象并给自己的$store属性赋值,因为当前组件渲染时可以确定其父组件已经完成渲染:

src/store/myVuex.js(未来替换vuex):

class Store {constructor(options) {}
}
​
const install = function(Vue) {Vue.mixin({beforeCreate(){if (this.$options && this.$options.store){ // 如果是根组件($options.store非空)this.$store = this.$options.store}else { //如果是任意子组件this.$store = this.$parent && this.$parent.$store}}})
}
​
const Vuex = {Store,install,
}
​
export default Vuex;

store数据响应式处理

现在的问题在于如何让我们Store构造函数能根据option.state创建一个响应式的state对象呢?vue2并没有像vue3中提供与组件解绑的方法(如refreactive)来创建响应式数据,所以最朴素也是唯一的一个方法就是创建一个vue组件实例,并利用它的data配置来获取一个响应式数据!

install方法的执行早于Store实例的创建,所以在install中对Vue进行引用记录,让Store的构造函数中可以使用它来创建组件。

+ let _Vue;class Store {constructor(options) {
+       this.vm = new _Vue({
+           data: {
+               state: options.state
+           }
+       })}
+   get state() {
+       return this.vm.state;
+   }}
​
const install = function(Vue) {
+   _Vue = Vue;Vue.mixin({beforeCreate(){if (this.$options && this.$options.store){this.$store = this.$options.store}else {this.$store = this.$parent && this.$parent.$store}}})
}
​
const Vuex = {Store,install,
}
​
export default Vuex;

这样我们的vuex就基本实现了,替换vuex的导入地址为:

import Vuex from './myVuex';

测试组件:

// 父组件
<template><div id="app">vuex中的数据:count--{{ this.$store.state.count }}<ChildComponent /><ClassChildComponent /></div>
</template>
​
<script>
import ChildComponent from './components/ChildComponent.vue'
​
export default {name: 'App',components: {ChildComponent,},mounted() {console.log(this);}
}
</script>
​
// 子组件
<template><div><hr />child<button @click="addCount">addCount</button></div>
</template>
​
<script>
export default {name: 'ChildComponent',methods: {addCount() {this.$store.state.count += 1;}}
}
</script>

子组件中点击按钮父组件ui发生变化。

实现vuex-class

同样,为了理清核心逻辑,我们只实现一下State方法,先回顾一下store中的数据如何在class-component中使用的。

import { State } from 'vuex-class';
​
export default class Xxx extends Vue {@State((state) => state.xxx) xxxS!: any;someFun() {// this.xxxS}
}

其实概括来讲就是利用装饰器在执行class代码进行组件初始化的同时,对options组件对象进行同步构建。并且在文章中详解了vue-property-decorator库的@Ref方法的实现,概括来说就是将class属性映射为options组件的计算属性,实现class组件代码中this.xxxRefthis.$refs.xxxRef的映射。

其实明白了上面的思路,这里要实现State方法就手到擒来了,与@Ref的实现可谓“换汤不换药”。

src/store/myVuexClass.js

import { createDecorator } from "vue-class-component";
​
export function State(selector) {return createDecorator((options, key) => {options.computed = options.computed || {};options.computed[key] = {cache: false,get() {return selector(this.$store.state);},}});
}

我们丢给State方法一个selector函数参数,最终构造的计算属性中调用selector时把this.$store.state扔进去让使用者去选所需的state中的状态就好了。

总结来说,如果要实现vuex-class,本质还是对于options组件对象的构建,实现State方法,是对其计算属性的构建,如果要实现mutation或者action,那么就是对option组件对象的methods的构建了,这里不再赘述。

完整附件:点此下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/601614.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

更改数据库名称时 存储过程的数据库名称如何改变

在 SQL Server 中&#xff0c;当你更改数据库名称时&#xff0c;存储过程中的 USE [big_data] 语句不会自动更改。你需要手动更新所有引用旧数据库名称的存储过程。 若要修改存储过程中的数据库引用&#xff0c;可以按照以下步骤操作&#xff1a; 首先&#xff0c;使用 ALTER…

trino-435:dynamic catalog数据库存储代码实现

一、dynamic catalog数据库存储源码分析 dynamic catalog的实现主要涉及到两个类&#xff1a;CoordinatorDynamicCatalogManager、WorkerDynamicCatalogManager&#xff0c;这两个类的详细信息如下&#xff1a; 这两个类主要提供了对catalog的增删改查的方法。trino-435源码中…

​三子棋(c语言)

前言&#xff1a; 三子棋是一种民间传统游戏&#xff0c;又叫九宫棋、圈圈叉叉棋、一条龙、井字棋等。游戏规则是双方对战&#xff0c;双方依次在9宫格棋盘上摆放棋子&#xff0c;率先将自己的三个棋子走成一条线就视为胜利。但因棋盘太小&#xff0c;三子棋在很多时候会出现和…

力扣(leetcode)第415题字符串相加(Python)

415.字符串相加 题目链接&#xff1a;415.字符串相加 给定两个字符串形式的非负整数 num1 和num2 &#xff0c;计算它们的和并同样以字符串形式返回。 你不能使用任何內建的用于处理大整数的库&#xff08;比如 BigInteger&#xff09;&#xff0c; 也不能直接将输入的字符串…

推荐一款Apache开源的文档内容解析工具

shigen坚持更新文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 hello&#xff0c;伙伴们&#xff0c;在闲暇的时候逛了一下掘金&#xff0c;发现了这样的一篇文章&#xf…

机器人相关知识

机器人学&#xff08;Robotics) 一些基础概念 位姿 位姿位置姿态 位姿的表示 刚体 刚性物体是一组粒子的集合&#xff0c;其中任意两个粒子之间的距离保持固定&#xff0c;不受物体运动或施加在物体上的力的影响。 “完全不可变形”的物体就是刚体。 刚体位置 刚性连杆 …

【网络技术】【Kali Linux】Wireshark嗅探(八)动态主机配置协议(DHCP)

一、实验目的 本次实验使用 Wireshark &#xff08;“网鲨”&#xff09;流量分析工具进行网络流量嗅探&#xff0c;旨在初步了解动态主机配置协议&#xff08;DHCP协议&#xff09;的工作原理。 二、DHCP协议概述 动态主机配置协议&#xff08; D ynamic H ost C onfigurat…

工智能基础知识总结--导出SVM要优化的问题

导出SVM要优化的问题 对于上图中这样一个二分类线性可分问题,期望找到一个分类超平面将正负类分开,SVM就是一个用来寻找这样的分类超平面的算法。 定义正负类的标签分别为1、-1,分类超平面的表达式为 f ( x ) = w T x + b f(x)=w^Tx+b

使用代理IP保护爬虫访问隐私数据的方法探讨

目录 前言 1. 获取代理IP列表 2. 随机选择代理IP 3. 使用代理IP发送请求 4. 处理代理IP异常 总结 前言 保护爬虫访问隐私数据是一个重要的安全问题。为了保障用户的隐私&#xff0c;很多网站会采取限制措施&#xff0c;如封禁IP或限制访问频率。为了绕过这些限制&#x…

宏电股份5G RedCap终端产品助力深圳极速先锋城市建设

12月26日&#xff0c;“全城全网&#xff0c;先锋物联”深圳移动5G-A RedCap助力深圳极速先锋城市创新发布会举行&#xff0c;宏电股份携一系列5G RedCap终端产品应邀参与创新发布会&#xff0c;来自全国5G生态圈的各界嘉宾、专家学者济济一堂&#xff0c;共探信息化数字化创新…

L1-078:吉老师的回归

题目描述 曾经在天梯赛大杀四方的吉老师决定回归天梯赛赛场啦&#xff01; 为了简化题目&#xff0c;我们不妨假设天梯赛的每道题目可以用一个不超过 500 的、只包括可打印符号的字符串描述出来&#xff0c;如&#xff1a;Problem A: Print "Hello world!"。 众所周知…

实验笔记之——服务器链接

最近需要做NeRF相关的开发,需要用到GPU,本博文记录本人配置服务器远程链接的过程,本博文仅供本人学习记录用~ 连上服务器 首先先确保环境是HKU的网络环境(HKU AnyConnect也可)。伙伴已经帮忙创建好用户(第一次登录会提示重新设置密码)。用cmd ssh链接ssh -p 60001 <u…

计算机毕业设计 SpringBoot的中小型制造企业质量管理系统 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

Linux基础——进程地址空间

1. 地址空间的验证 之前我们在学习语言时&#xff0c;曾知道有下面这张图 对于这个图我们可以用下面的代码验证 运行后我们可以发现 其对应关系如下 我们使用fork函数&#xff0c;来分别对父子进程中的g_val进行修改&#xff0c;即 运行后我们可以发现 在子进程修改了g_val后…

矩阵的乘法

首先矩阵的乘法定义如下&#xff1a; #include <stdio.h> int main() { int i 0; int j 0; int arr[20][20] { 0 }; int str[20][20] { 0 }; int s[20][20] { 0 }; int n1 0; int n2 0; int m2 0; int z 0; int m1 0;…

AMP 通讯RPMsg

参考 RPMsg&#xff1a;协议简介_rpmsg协议-CSDN博客 【软件架构】【通信】S32G IPCF - 知乎 openamp https://www.cnblogs.com/sky-heaven/p/14085800.html virtualIO 虚拟化技术 — VirtIO 虚拟设备接口标准 - 知乎 Virtio-fs介绍与性能优化_guest docker Docker Docs

LeetCode 每日一题 Day 3334(hard)35 ||二进制枚举/单调栈/链表遍历

2397. 被列覆盖的最多行数 给你一个下标从 0 开始、大小为 m x n 的二进制矩阵 matrix &#xff1b;另给你一个整数 numSelect&#xff0c;表示你必须从 matrix 中选择的 不同 列的数量。 如果一行中所有的 1 都被你选中的列所覆盖&#xff0c;则认为这一行被 覆盖 了。 形式…

CPU算力分配(100用例)C卷 (JavaPythonC语言C++Node.js)

现有两组服务器A和B,每组有多个算力不同的CPU,其中A[i]是A组第i个CPU的运算能力,B[i]是B组第i个CPU的运算能力,一组服务器的总算力是各CPU的算力之和。 为了让两组服务器的算力相等,允许从每组各选出一个CPU进行一次交换,求两组服务器中,用于交换的CPU的算力,并且要求从…

认识jmeter接口测试工具!

jmeter简介 Apache JMeter是Apache组织开发的基于Java的压力测试工具。用于对软件做压力测试&#xff0c;它最初被设计用于Web应用测试&#xff0c;但后来扩展到其他测试领域。 下载 下载地址&#xff1a;​​​​​​Apache JMeter - Download Apache JMeter 安装 由于Jmeter…

学会视频剪辑方法:从视频中提取封面,增加视频观看量

在数字媒体时代&#xff0c;视频已经成为信息传递的主要方式之一。那如何让视频在众多内容中脱颖而出&#xff0c;吸引更多的观众呢&#xff1f;除了内容本身的质量外&#xff0c;视频的封面也是吸引的关键因素之一。下面一起看云炫AI智剪如何通过视频剪辑方法从视频中提取封面…