欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

WEB架构师学习笔记_Vue_03简单实现Vuex

程序员文章站 2024-03-24 08:24:40
...

知识导航

  • vuex的使用
  • Vuex的基本实现

知识点:
WEB架构师学习笔记_Vue_03简单实现Vuex

1. vuex的使用

Vuex想必我们都很熟悉了,它就是实现全局状态的一种管理机制。即可以实现所有组件共享同一数据。

1.1 实例化store时传入的参数

state:放数据;mutations:改变数据的一些方法;actions:异步方法或一些复杂逻辑;getters:类似于计算属性,对数据的包装。

{
    state: {
        count: 0
    },
    mutations: {
        add(state, a) {
            state.count += a;
        },
        sub(state, step) {
            state.count = state.count - step;
        }
    },
    actions: {
    //第一个参数是希望给一个store的实例,因为只有store实例才有commit方法
        asyncAdd(context, step) {
            setTimeout(function() {
                context.commit("add", step);
            }, 1000)
        },
        asyncsub(context, step) {
            setTimeout(function() {
                context.commit("sub", step);
            }, 1000)
        }
    },
    getters: {
        showData(state) {
            return `数字:${state.count}`
        }
    },
    modules: {}
}

1.2 组件1中的使用(我比较喜欢的方式)

commit:可调用mutations中的方法,dispatch:可调用actions中的方法

<template>
    <div>
        {{$store.state.count}}
        {{$store.getters.showData}}
        <button @click="add"></button>
         <button @click="addAsy">延时加</button>
    </div>
</template>

<script>
export default {
    methods: {
        add(){
            this.$store.commit("add",2);
        },
        addAsy(){
            this.$store.dispatch('asyncAdd', 3)
        }
    },
}
</script>

1.2 组件2中的使用

这里只是用了一下vuex提供的一些辅助函数

<template>
  <div>
    {{$store.state.count}}{{showData()}}
    <button @click="subHander"></button>
    <button @click="subHanderAsy">延时减</button>
  </div>
</template>

<script>
import { mapMutations, mapActions,mapGetters } from "vuex";
export default {
  methods: {
    ...mapMutations(["sub"]),//mapMutations辅助函数可将this.sub()映射为this.$store.commit('sub'),因为我们可能要的不止是一个所以用下扩展运算符展开它
    ...mapActions(["asyncsub"]),
    ...mapGetters(['showData']),

    subHander() {
      this.sub(2);
    },
    subHanderAsy() {
      this.asyncsub(2);
    }
  }
};
</script>

2. Vuex的基本实现

2.1 老样子,还是看使用时做了哪些工作

配置js中:
WEB架构师学习笔记_Vue_03简单实现Vuex
入口文件main.js中:
WEB架构师学习笔记_Vue_03简单实现Vuex

思路

通过观察我们可以知道插件中要实现的事情。

  • 实现install方法
  • 接收参数
  • 实现commit和dispatch
  • 注意getters(我们在组件中使用getters中的东西时是这样this.$store.getters.showData。这可不是一个方法的调用。它更像一个去对象中取值的操作。其实仔细观察它其实更类似于双向数据绑定,即数据一变,数据包装跟着改变,getters里的方法只是决定了如何包装数据而已)
  1. 实现install
    这里的主要工作还是用混入将这个store实例挂到vue原型上去
function install(_vue) {
    Vue = _vue;
    Vue.mixin({
        beforeCreate() {
            if (this.$options.store) {
                Vue.prototype.$store = this.$options.store;
            }
        },
    })
}
  1. 接收参数
    接收参数分别存储时要注意state中的数据是响应式的
class Store {
    constructor(args = {}) {
        this.state = new Vue({
            data: args.state
        });
        this.actions = args.actions || {};
        this.mutations = args.mutations || {};
       
    }
  1. 实现commit
    cmmit要做的工作很简单,观察到组件中使用commit时会传一个mutations 中的方法名,和一些其他的参数
   commit(fnName, arg) {
        let fn = this.mutations[fnName];//利用传过来的方法名去mutations找对应的函数
        fn(this.state, arg);//调用这个函数即可,传入要改的state数据源和组件中该过来的参数
    }
  1. 实现dispatch
    它的实现和commit类似,只不过因为它里面要调用的可能是有返回值的异步函数。所以可能需要返回函数执行结果。同时这次调用参数中的方法时要传的第一个参数是这个store实例,或者说是此处的上下文
    dispatch(fnName, arg) {
        let fn = this.actions[fnName];
        return fn(this, arg);
    }
  1. 包装数据
    这个实现getters应该是目前这里最难的,首先在接收参数时我们先要判断参数中是否有getters的东西,有则需要一个方法来处理它。这个方法要实现什么功能呢?其实也很简单就是把传过来的getters中的方法全部执行一遍。把执行完的数据存起来就可以了。

我首先想到的是像这样(错误示例):

    gettersHander(objGetFn) {
        this.getters = {};
        Object.keys(objGetFn).forEach(key => {
            this.getters[key] = objGetFn[key](this.state);
        })
    }

我因为this.state是响应式的,故只需state的状态一发生变化我this.getters中会跟着变化。但是这里程序好像不是按照我期望的流程走的。
我现在是希望在访问 this.getters中数据时有一段劫持代码用来做中间件来处理一下,即一访问这个 this.getters中数据,中间件会帮我们更新this.getters中的数据。以到达响应式的结果。

可以实现数据劫持的有两个方法:Object.defineProperty()和Proxy。(后面还会用到这里不写使用了,去MDN看一下就行)
修改上面代码:

    gettersHander(objGetFn) {
        this.getters = {};

        Object.keys(objGetFn).forEach(key => {
            Object.defineProperty(this.getters, key, {
                get: () => {
                    return objGetFn[key](this.state);
                }
            })
        })

    }

效果:
WEB架构师学习笔记_Vue_03简单实现Vuex
全部代码:

// 思路
// 1. 首先实现install
// 2. 接收参数并找分类容器保存
// 3. 将state里面的数据做出响应式
// 4. 实现三方法,commit,dispath
let Vue;

function install(_vue) {
    Vue = _vue;
    Vue.mixin({
        beforeCreate() {
            if (this.$options.store) {
                Vue.prototype.$store = this.$options.store;
            }
        },
    })
}

class Store {
    constructor(args = {}) {
        this.state = new Vue({
            data: args.state
        });
        this.actions = args.actions || {};
        this.mutations = args.mutations || {};
        args.getters && this.gettersHander(args.getters);
    }
    commit(fnName, arg) {
        let fn = this.mutations[fnName];
        fn(this.state, arg);
    }
    dispatch(fnName, arg) {
        let fn = this.actions[fnName];
        return fn(this, arg);
    }
    gettersHander(objGetFn) {
        this.getters = {};

        Object.keys(objGetFn).forEach(key => {
            Object.defineProperty(this.getters, key, {
                get: () => {
                    return objGetFn[key](this.state);
                }
            })
        })

    }

}
export default { install, Store }
相关标签: 前端架构