WEB架构师学习笔记_Vue_03简单实现Vuex
程序员文章站
2024-03-24 08:24:40
...
知识导航
- vuex的使用
- 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中:
入口文件main.js中:
思路
通过观察我们可以知道插件中要实现的事情。
- 实现install方法
- 接收参数
- 实现commit和dispatch
- 注意getters(我们在组件中使用getters中的东西时是这样this.$store.getters.showData。这可不是一个方法的调用。它更像一个去对象中取值的操作。其实仔细观察它其实更类似于双向数据绑定,即数据一变,数据包装跟着改变,getters里的方法只是决定了如何包装数据而已)
- 实现install
这里的主要工作还是用混入将这个store实例挂到vue原型上去
function install(_vue) {
Vue = _vue;
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store;
}
},
})
}
- 接收参数
接收参数分别存储时要注意state中的数据是响应式的
class Store {
constructor(args = {}) {
this.state = new Vue({
data: args.state
});
this.actions = args.actions || {};
this.mutations = args.mutations || {};
}
- 实现commit
cmmit要做的工作很简单,观察到组件中使用commit时会传一个mutations 中的方法名,和一些其他的参数
commit(fnName, arg) {
let fn = this.mutations[fnName];//利用传过来的方法名去mutations找对应的函数
fn(this.state, arg);//调用这个函数即可,传入要改的state数据源和组件中该过来的参数
}
- 实现dispatch
它的实现和commit类似,只不过因为它里面要调用的可能是有返回值的异步函数。所以可能需要返回函数执行结果。同时这次调用参数中的方法时要传的第一个参数是这个store实例,或者说是此处的上下文
dispatch(fnName, arg) {
let fn = this.actions[fnName];
return fn(this, arg);
}
- 包装数据
这个实现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);
}
})
})
}
效果:
全部代码:
// 思路
// 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 }
上一篇: maven repositories