1.Vuex特点1
使用Vuex的时候需要用到Vue的use方法
我们都知道use方法
是用于注册插件的
所以VueX的本质就是一个插件
所以实现VueX就是在实现一个全局共享数据的插件
2.Vuex特点2
在使用Vuex的时候我们会通过Vuex.Store创建一个仓库
所以还需要在Vuex中新增Store属性
, 这个属性的取值是一个类
// Nuex.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// 用于保存全局共享数据
state: {
},
// 用于同步修改共享数据
mutations: {
},
// 用于异步修改共享数据
actions: {
},
// 用于模块化共享数据
modules: {
}
})
3.Vuex特点3
为了保证每个Vue实例中都能通过this.$store拿到仓库,还需要给每个Vue实例动态添加一个 $store属性
。
4.手写Vuex
import Vue from 'vue'
const install = (Vue, options)=>{
// 给每一个Vue实例都添加一个$store属性
/**
* 在vue中有一个mixin方法,这个方法会在创建每一个Vue实例的时候执行
* 所以可以通过mixin方法给每一个Vue实例添加$store属性
*/
Vue.mixin({
// 重写
beforeCreate(){
/**
* Vue在创建实例的时候会先创建父组件,然后再创建子组件
*/
// console.log(this.$options.name);
// Root === App == helloworld
/**
* 如果是根组件,name默认就有store
* 只需要将store变成$store即可
*/
if(this.$options && this.$options.store){
this.$store = this.$options.store;
}
else{
/**
* 如果不是根组件,那么默认没有store
* 只需要将它父组件的$store赋值给它即可
*/
this.$store = this.$parent.$store; // 子组件的$store === 父组件的store
}
}
});
}
class ModuleCollection {
constructor(rootModule){
this.register([], rootModule);
}
register(arr, rootModule){
// console.log(arr); // [] [home] [account] [account, login]
// 1.按照我们需要的格式创建模块
let module = {
_raw: rootModule,
_state: rootModule.state,
_children: {}
}
// 2.保存模块信息
if(arr.length === 0){
// 保存根模块
this.root = module;
}else{
// 保存子模块
// this.root._children[arr[arr.length-1]] = module;
// let testArr = ['account', 'login'];
// let res = testArr.splice(0, testArr.length - 1);
// console.log(res);
// ['a', 'b', 'c'] -> ['a', 'b']
let parent = arr.splice(0, arr.length-1).reduce((root, currentKey)=>{
return root._children[currentKey];
}, this.root);
parent._children[arr[arr.length-1]] = module;
}
// 3.处理子模块
for(let childrenModuleName in rootModule.modules){
let childrenModule = rootModule.modules[childrenModuleName];
this.register(arr.concat(childrenModuleName) ,childrenModule)
}
}
}
class Store {
constructor(options){
// this.opions = options
// 将创建Store的时候需要共享的数据添加到Store上面
// 将来就能通过this.$store拿到这个Store
// 能拿到这个Store,就可以通过 .state拿到需要共享的属性
// this.state = options.state // 无法实现双向绑定数据
// ------------------------------------------------
// 将传递进来的state放到Store上
Vue.util.defineReactive(this, 'state', options.state);
// 提取模块信息
this.modules = new ModuleCollection(options);
// 安装子模块的数据
this.initModules([], this.modules.root);
/*
模块化
ModuleCollection方法将数据处理成下面这个格式:
let root = {
_raw: rootModule,
_state: rootModule.state,
_children: {
home:{
_raw: homeModule,
_state: homeModule.state,
_children: {}
},
account:{
_raw: accountModule,
_state: accountModule.state,
_children: {
login: {
_raw: loginModule,
_state: loginModule.state,
_children: {}
}
}
},
}
}
* */
}
initModules(arr, rootModule){
// console.log(arr); // [] [home] [account] [account, login]
// 如果当前是子模块, 那么就需要将数据安装到this.state上
if(arr.length > 0){
let parent = arr.splice(0, arr.length-1).reduce((state, currentKey)=>{
return state[currentKey];
}, this.state);
Vue.set(parent, arr[arr.length-1], rootModule._state);
}
// 将传递进来的getters放到Store上
this.initGetters(rootModule._raw);
// 将传递进来的mutations放到Store上
this.initMutations(rootModule._raw);
// 将传递进来的actions放到Store上
this.initActions(rootModule._raw);
// 如果当前不是子模块, 那么就需要从根模块中取出子模块的信息来安装
for(let childrenModuleName in rootModule._children){
let childrenModule = rootModule._children[childrenModuleName];
this.initModules(arr.concat(childrenModuleName), childrenModule);
}
}
dispatch = (type, payload)=>{
this.actions[type].forEach(fn=>fn(payload));
}
initActions(options){
// 1.拿到传递进来的actions
let actions = options.actions || {};
// 2.在Store上新增一个actions的属性
this.actions = this.actions || {};
// 3.将传递进来的actions中的方法添加到当前Store的actions上
for(let key in actions){
this.actions[key] = this.actions[key] || [];
this.actions[key].push((payload)=>{
actions[key](this, payload);
});
}
}
commit = (type, payload)=>{
// console.log(this);
// 允许相同的方法名,调用时,全部执行
this.mutations[type].forEach(fn=>fn(payload));
}
initMutations(options){
// 1.拿到传递进来的mutations
let mutations = options.mutations || {};
// 2.在Store上新增一个mutations的属性
this.mutations = this.mutations || {};
// 3.将传递进来的mutations中的方法添加到当前Store的mutations上
for(let key in mutations){
// 允许相同的方法名,数组将所有的方法保存
this.mutations[key] = this.mutations[key] || [];
this.mutations[key].push((payload)=>{
mutations[key](options.state, payload);
});
}
}
initGetters(options){
// this.getters = options.getters;
// 1.拿到传递进来的getters
let getters = options.getters || {};
// 2.在Store上新增一个getters的属性
this.getters = this.getters || {};
// 3.将传递进来的getters中的方法添加到当前Store的getters上
for(let key in getters){
Object.defineProperty(this.getters, key, {
get:()=>{
return getters[key](options.state);
}
})
}
}
}
export default {
install,
Store
}
使用
import Vue from 'vue'
// import Vuex from 'vuex'
import Vuex from './Nuex'
Vue.use(Vuex)
let home = {
state: {
name: 'www'
},
getters: {
getHomeName(state){
return state.name + '222222';
},
// 多个模块中不能出现同名的getters方法
// getGlobalName(state){
// return state.globalName + '111111';
// }
},
mutations: {
changeHomeName(state, payload){
state.name += payload;
},
// 注意点: 多个模块的mutations中可以出现同名的方法
// 多个同名的方法不会覆盖, 会放到数组中然后依次执行
changeGlobalName(state, payload){
console.log('home中的changeGlobalName');
state.globalName += payload;
}
},
actions: {
asyncChangeHomeName({commit}, payload){
setTimeout(()=>{
commit('changeHomeName', payload);
}, 1000);
},
// 注意点: 多个模块的actions中可以出现同名的方法
// 多个同名的方法不会覆盖, 会放到数组中然后依次执行
asyncChangeGlobalName({commit}, payload){
console.log('home中的asyncChangeGlobalName');
setTimeout(()=>{
commit('changeGlobalName', payload);
}, 1000);
}
}
}
let login = {
state: {
name: 'com'
},
getters: {
getLoginName(state){
return state.name + '333333';
}
},
mutations: {
changeLoginName(state, payload){
state.name += payload;
}
},
actions: {
asyncChangeLoginName({commit}, payload){
setTimeout(()=>{
commit('changeLoginName', payload);
}, 1000);
}
},
}
let account = {
state: {
name: 'it666'
},
getters: {
getAccountName(state){
return state.name + '333333';
}
},
mutations: {
changeAccountName(state, payload){
state.name += payload;
}
},
actions: {
asyncChangeAccountName({commit}, payload){
setTimeout(()=>{
commit('changeAccountName', payload);
}, 1000);
}
},
modules: {
login: login
}
}
export default new Vuex.Store({
// 用于保存全局共享数据
state: {
globalName: 'lnj'
},
getters: {
getGlobalName(state){
return state.globalName + '111111';
}
},
// 用于同步修改共享数据
mutations: {
changeGlobalName(state, payload){
console.log('全局中的changeGlobalName');
state.globalName += payload;
}
},
// 用于异步修改共享数据
actions: {
asyncChangeGlobalName({commit}, payload){
console.log('全局中的asyncChangeGlobalName');
setTimeout(()=>{
commit('changeGlobalName', payload);
}, 1000);
}
},
// 用于模块化共享数据
modules: {
home:home,
account: account
}
})
4.Vue.util.defineReactive
Vue.util.defineReactive(参数1, 参数2, 参数3)
在Vue中有一个
util的工具类
,在这个工具类上有一个defineReactive
通过这个方法就可以快速的将某个数据变成双向绑定
的数据
defineReactive这个方法接收三个参数
- 第一个参数:要给哪个对象添加属性
- 第二个参数:要给指定的对象添加什么属性
- 第三个参数:要给这个属性添加什么值
5.Vue.set
Vue.set( target, propertyName/index, value )
- 第一个参数:给哪个对象添加属性
- 第二个参数:添加的什么属性
- 第三个参数:添加什么数据
学习记录❥(^_-)