简单自定义vuex的设计思路

news2024/10/5 12:48:29

vuex集中式存储管理应用所有组件的状态,并以响应的规则保证状态以可预测的方式 发生变化。

步骤:

1.Store类,保存选项,_mutations,_actions,getters

2.响应式状态:new Vue方式设置响应式。

3.get state 和 set state commit dispatch

4.install方法 挂载store到vue的原型对象上,所有实例都可以读取到。

生成Vuex类

说到底,vuex也还是个插件,所以生成一个类,按照使用插件的形式将其export导出。

挂载到Vue实例上我们还是使用mixin的方式,原理和vue-router的自定义方式一致,这里就不多说了。

let Vue

class Store{
    constructor(options){
        //保存选项

        // state为响应式数据
        this.state = new Vue({
            data:options.state
        })
    }
}

function install(_Vue){
    Vue = _Vue
    //挂载$store给外面使用
    Vue.mixin({
        beforeCreate() {
            if(this.$options.store){
                //挂载到vue原型上,每个vue实例都可以访问到
                Vue.prototype.$store = this.$options.store
            }
        },
    })
}

export default {
    Store,install
}

但是在这里,我们使用new Vue的data属性来让state成为一个响应式的数据,有个弊端就是能够直接的修改data里的数据,那这样违反了vuex单向数据流的特点,那么我们要封装一下。

官网解释,有两个的$变量就不做代理,所以也就不会再_vm的根上访问到$$state这个属性,同时设置set get俩属性,get为只读,那么外面就无法修改state的值,只能通过commit或actions进行修改。_vm下的响应式对象会挂载在_data的对象上,_vm下的$data是一个原始对象,不具备响应式,所以使用_data。

如下图,$data不存在observer

class Store{
    constructor(options){
        //保存选项
        // state为响应式数据
        this._vm = new Vue({
            data:{
                $$state:options.state
            }
        })
    }
    //给用户暴露接口
    get state(){
        console.log(this._vm);
        return this._vm._data.$$state
    }
    set state(val){
        throw Error('replaceSate')
    }
}

commit和dispatch

响应式的数据发生变化就会引起render函数渲染数据 ,在commit中会接收到参数,我们在构造函数中存储传入的mutations和actions,然后在commit和dispach中匹配到详情的操作,然后执行。

但是在执行过程中有坑,this的指向问题:当前的调用是在外部,所以指向的是外部的store实例,是没有commit等参数,所以没有办法调用到。需要在constructor存储上下文,并且改变this指向到当前的实例,获取到对应的上下文即可。

class Store{
    constructor(options){
        //保存选项
        this._mutations  = options.mutations||{}
        this._actions  = options.actions||{}
        // state为响应式数据
        this._vm = new Vue({
            data:{
                $$state:options.state
            }
        })
        //上下文的绑定
        this.commit=this.commit.bind(this)
        this.dispatch=this.dispatch.bind(this)
    }
    //给用户暴露接口
    get state(){
        return this._vm._data.$$state
    }
    set state(val){
        throw Error('replaceSate')
    }
    //store.commit(type,payload)
    commit(type,payload){
        //获取mutitions
        const entry = this._mutations[type]
        if(!entry){
            console.error('unknown mutition type');
        }
        entry(this.state,payload)
    }
    dispatch(type,payload){
        const entry = this._actions[type]
        if(!entry){
            console.error('unknown actions type');
        }
        console.log(this);
        entry(this,payload)//注意这里的this指向问题,当前的调用是在外部,所以指向的是外部的store实例,是没有commit等参数,所以没有办法调用到。需要在constructor存储上下文,并且改变this指向。
    }
}

getters

getters我们可以借助computed属性,只可获取不可更改,获取到getters的key给到computed,并且在给一个函数,在其内部调用fn并且传入state,再将computed属性进行响应式处理。

this._wrappedGetters  = options.getters||{}
        //定义computed选项
        const computed={}
        this.getters={}
        const store= this
        Object.keys(this._wrappedGetters).forEach(key=>{
            //获取用户定义的getter
            const fn = store._wrappedGetters[key]
            // 转换为computed可以使用的无参数形式
            computed[key]=function(){
                return fn(store.state)
            }
            //为getters定义只读属性
            Object.defineProperty(store.getters,key,{
                get:()=>{
                    return store._vm[key]
                }
            })
        })

        // state为响应式数据
        this._vm = new Vue({
            data:{
                $$state:options.state
            },
            computed
        })

附完整代码:

let Vue

class Store{
    constructor(options){
        //保存选项
        this._mutations  = options.mutations||{}
        this._actions  = options.actions||{}
        this._wrappedGetters  = options.getters||{}
        //定义computed选项
        const computed={}
        this.getters={}
        const store= this
        Object.keys(this._wrappedGetters).forEach(key=>{
            //获取用户定义的getter
            const fn = store._wrappedGetters[key]
            // 转换为computed可以使用的无参数形式
            computed[key]=function(){
                return fn(store.state)
            }
            //为getters定义只读属性
            Object.defineProperty(store.getters,key,{
                get:()=>{
                    return store._vm[key]
                }
            })
        })

        // state为响应式数据
        this._vm = new Vue({
            data:{
                $$state:options.state
            },
            computed
        })
        //上下文的绑定
        this.commit=this.commit.bind(this)
        this.dispatch=this.dispatch.bind(this)
    }
    //给用户暴露接口
    get state(){
        return this._vm._data.$$state
    }
    set state(val){
        throw Error('replaceSate')
    }
    //store.commit(type,payload)
    commit(type,payload){
        //获取mutitions
        const entry = this._mutations[type]
        if(!entry){
            console.error('unknown mutition type');
        }
        entry(this.state,payload)
    }
    dispatch(type,payload){
        const entry = this._actions[type]
        if(!entry){
            console.error('unknown actions type');
        }
        entry(this,payload)//注意这里的this指向问题,当前的调用是在外部,所以指向的是外部的store实例,是没有commit等参数,所以没有办法调用到。需要在constructor存储上下文,并且改变this指向。
    }
}

function install(_Vue){
    Vue = _Vue

    //挂载$store给外面使用
    Vue.mixin({
        beforeCreate() {
            if(this.$options.store){
                //挂载到vue原型上,每个vue实例都可以访问到
                Vue.prototype.$store = this.$options.store
                
            }
        },
    })
}

export default {
    Store,install
}

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

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

相关文章

Java网络编程,使用UDP实现TCP(三), 基本实现四次挥手

简介 四次挥手示意图 在四次挥手过程中,第一次挥手中的Seq为本次挥手的ISN, ACK为 上一次挥手的 Seq1,即最后一次数据传输的Seq1。挥手信息由客户端首先发起。 实现步骤: 下面是TCP四次挥手的步骤: 第一次挥手&…

环境变量提权

环境变量提权 借鉴文章LINUX提权之环境变量提权篇 - 知乎 (zhihu.com) 利用条件 存在一个文件,利用su权限执行,普通用户可以执行此文件,但只限制在一个目录下可以执行 利用方式 将此文件的目录添加到环境变量中 export PATH/tmp:$PATHe…

分层自动化测试的实战思考!

自动化测试的分层模型 自动化测试的分层模型,我们应该已经很熟悉了,按照分层测试理念,自动化测试的投入产出应该是一个金字塔模型。越是向下,投入/产出比就越高,但开展的难易程度/成本和技术要求就越高,但…

Linux安装Halo(个人网站)

docker安装 curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun && systemctl start docker && systemctl enable docker && sudo mkdir -p /etc/docker && sudo tee /etc/docker/daemon.json <<-EOF && sudo…

开题PPT答辩复盘

目录 总体思路加粗和红体字使用研究现状之后主要研究内容讨论 总体思路 分为五个部分&#xff0c;规定在10分钟以内讲完。这次开题答辩&#xff0c;主要是要讲清楚研究背景和意义&#xff0c;国内外研究现状。因此前两部分需要花大概6分钟重点解释&#xff0c;主要研究内容用2…

提升--22---ReentrantReadWriteLock读写锁

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 ReadWriteLock----读写锁1.读写锁介绍线程进入读锁的前提条件&#xff1a;线程进入写锁的前提条件&#xff1a;而读写锁有以下三个重要的特性&#xff1a; Reentran…

jQuery遍历与删除添加节点

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章…

如何通过 SSH 访问 VirtualBox 的虚机

VirtualBox 是一款免费虚机软件。在用户使用它安装了 linux 以后&#xff0c;它默认只提供了控制台的管理画面。 直接使用控制台管理 Linux 没有使用诸如 putty 或者 vscode 这样的 ssh 远程管理工具方便。那么可不可以直接使用 ssh 访问 VirtualBox 上的 Linux 呢&#xff1f…

关于碰撞试验

主要参数&#xff1a; 冲击与碰撞试验的主要参数及调整方法 - 百度文库 碰撞试验的技术指标包括&#xff1a;峰值加速度、脉冲持续时间、速度变化量&#xff08;半正弦波&#xff09;、每方向碰撞次数。 加速度&#xff1a;冲击的强度&#xff0c;单位为g&#xff1b;一般为3…

【小红书运营指南2】小红书自律标签的达人分解

小红书标签的达人分解 写在最前面11.27初步想法达人分析 标签拆解&#xff08;速览版&#xff09;分析应用 思路 相关标签拆解&#xff08;详细版&#xff09;11、职场-职场干货 文化薯&#xff08;创业&#xff0c;也是专注知识付费&#xff0c;可以对标学习&#xff09;笔记画…

C++刷题 -- 哈希表

C刷题 – 哈希表 文章目录 C刷题 -- 哈希表1.两数之和2.四数相加II3.三数之和&#xff08;重点&#xff09; 当我们需要查询一个元素是否出现过&#xff0c;或者一个元素是否在集合里的时候&#xff0c;就要第一时间想到哈希法; 1.两数之和 https://leetcode.cn/problems/two…

springcloud多环境部署打包 - maven 篇

背景 在使用 springboot 和sringcloudnacos开发项目过程中&#xff0c;会有多种环境切换&#xff0c;例如开发环境&#xff0c;测试环境&#xff0c;演示环境&#xff0c;生产环境等&#xff0c;我们通过建立多个 yml 文件结合 profiles.active 属性进行环境指定&#xff0c;但…

Dockerfile创建镜像INMP+wordpress

Dockerfile创建镜像INMPwordpress 需要哪些呢&#xff1a; Nginx 172.111.0.10 docker-nginx Mysql 172.111.0.20 docker-mysql PHP 172.111.0.30 docker-PHP 开始实验&#xff1a; 创建各级目录&#xff0c;他们各自的包和配置文件必须要在同一目录下才可以生效&…

互联网加竞赛 LSTM的预测算法 - 股票预测 天气预测 房价预测

0 简介 今天学长向大家介绍LSTM基础 基于LSTM的预测算法 - 股票预测 天气预测 房价预测 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/postgraduate 1 基于 Ke…

STM32——串口实验(非中断)

需求&#xff1a; 接受串口工具发送的字符串&#xff0c;并将其发送回串口工具。 硬件接线&#xff1a; TX -- A10 RX -- A9 一定要记得交叉接线&#xff01;&#xff01; 串口配置&#xff1a; 1. 选定串口 2. 选择模式 异步通讯 3. 串口配置 4. 使用MicroLIB库 从…

PaddleOCR:超越人眼识别率的AI文字识别神器

在当今人工智能技术已经渗透到各个领域。其中&#xff0c;OCR&#xff08;Optical Character Recognition&#xff09;技术将图像中的文字转化为可编辑的文本&#xff0c;为众多行业带来了极大的便利。PaddleOCR是一款由百度研发的OCR开源工具&#xff0c;具有极高的准确率和易…

PyQt6 QStatusBar状态栏控件

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计44条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

漂亮的WPF界面 流行的一个界面,向上悬浮的窗口,终于试成功了

目前随便打开个APP&#xff0c;就可以看到一个悬浮的窗口 今天测试一下目前流行的一个界面&#xff0c;向上悬浮的窗口&#xff0c;终于试成功了。看着还不错的。

【无标题】树莓派 4B 多串口配置

0. 实验准备以及原理 0.1 实验准备 安装树莓派官方系统的树莓派 4B&#xff0c;有 python 环境&#xff0c;安装了 serial 库 杜邦线若干 屏幕或者可以使用 VNC 进入到树莓派的图形界面 0.2 原理 树莓派 4B 有 UART0&#xff08;PL011&#xff09;、UART1&#xff08;mini UAR…

AI 绘画快速开始-StableDiffusionWebui

文章目录 介绍WebUI 的安装和部署参数介绍Prompt技巧初阶Prompt&#xff1a;直接描述的精细化二阶Prompt&#xff1a;巧用标签的扩展三阶Prompt&#xff1a;负面提示词的深入应用四阶Prompt&#xff1a;文本权重调整的细化引入 LoRA&#xff1a;模型特效的创新应用 案例-生成漫…