1、原理
(1)Vuex本质是一个对象
(2)Vuex对象有两个属性,一个是install方法,一个是Store这个类
install方法的作用是将store这个实例挂载到所有的组件上,注意是同一个store实例。
(3)Store这个类拥有commit,dispatch这些方法,
(4)Store类里将用户传入的state包装成data,作为new Vue的参数,从而实现了state 值的响应式。
【引用】:https://zhuanlan.zhihu.com/p/166087818
总结:
(1)Vuex的双向绑定通过调用 new Vue实现,
(2)通过 Vue.mixin 注入到Vue组件的生命周期中,在所有组件的beforeCreate 生命周期注入了设置 this.$store,值就是使用Vuex时所创建的Vuex实例,
2、相关知识
1、方法的简写
var obj = {
foo: function() {
/* code */
},
bar: function() {
/* code */
}
};
被简写成
var obj = {
foo() {
/* code */
},
bar() {
/* code */
}
};
2、关于类里面的方法的问题
类的注意事项
(1)函数声明和类声明之间的一个重要区别在于,函数声明会提升,类声明不会。你首先需要声明你的类,然后再访问它
(2)constructor方法是一个特殊的方法,这种方法用于创建和初始化一个由class创建的对象。一个类只能拥有一个名为 “constructor”的特殊方法
(3)static 关键字用来定义一个类的一个静态方法。调用静态方法不需要实例化 该类,但不能通过一个类实例调用静态方法,使用类名**XX.**调用
(1)在类找那个定义的方法会出现在类的原型上
(2)当调用静态或原型方法时没有指定 this 的值,那么方法内的 this 值将被置为 undefined
class Animal {
//原型方法
speak() {
return this;
}
//不可以这样定义! 会报错!
//speak2:function() {
// return this;
// }
//静态方法
static eat() {
return this;
}
}
let obj = new Animal();
obj.speak(); // Animal {}
let speak = obj.speak;
speak(); // undefined
Animal.eat() // class Animal
let eat = Animal.eat;
eat(); // undefined
提案中:公有实例字段和公共实例方法
公有实例字段
公有实例字段存在于类的每一个实例中。通过声明一个公有字段,我们可以确保该字段一直存在
class ClassWithInstanceField {
instanceField = 'instance field';
}
const instance = new ClassWithInstanceField();
console.log(instance.instanceField);
公共实例方法
公共实例方法是可以在类的实例中使用的。
class ClassWithPublicInstanceMethod {
publicMethod() {
return 'hello world';
}
}
const instance = new ClassWithPublicInstanceMethod();
console.log(instance.publicMethod());
实验的结果
class A {
a = 1;
// 原型方法
speak() {
console.log(this.a);
}
// 静态方法
static cry() {
console.log("cry", this.a);
}
eat = function () {
console.log(this);
};
sleep = () => {
console.log(this);
};
}
let a = new A();
let a2 = new A();
console.log("A", A);
console.log("a", a);
console.log("a", a2);
A.cry();
a.cry();
3、关于解构赋值的一些问题
解构对象时会查找原型链(如果属性不在对象自身,将从原型链中查找)
// 声明对象 和 自身 self 属性
var obj = {self: '123'};
// 在原型链中定义一个属性 prot
obj.__proto__.prot = '456';
// test
const {self, prot} = obj;
// self "123"
// prot "456"(访问到了原型链)
3、实现vuex
准备
src\main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
src\views\Home.vue
<template>
<div class="home">
<div>这里是:{{ name }},</div>
<div>时间是{{ time }}</div>
<div>我的年纪是 {{ age }}岁</div>
<div>我的积分是:{{score}}</div>
<div>{{ allScore }}</div>
<button @click="addScore">点击积分+1</button>
<button @click="reduceScore">点击积分-1</button>
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from "@/components/HelloWorld.vue";
export default {
name: "Home",
components: {
HelloWorld,
},
mounted() {
// setInterval(() => {
// //函数体
// this.$store.state.age++;
// }, 3000);
},
computed: {
name() {
return this.$store.state.name;
},
age() {
return this.$store.state.age;
},
score() {
return this.$store.state.score;
},
time() {
return this.$store.state.time;
},
allScore() {
return this.$store.getters.allScore;
},
},
methods:{
addScore(){
this.$store.commit("addScore",1)
},
reduceScore(){
this.$store.dispatch("reduceScore",1)
}
}
};
</script>
核心
vuex.js
let Vue;
//优化封装
// 取出配置的方法名 和 方法
//obj 配置对象,cb回调
const ForEachFn = (obj, cb) => {
Object.keys(obj).forEach((key) => {
//key是方法名,obj[key]是方法
cb(key, obj[key]);
});
};
class Store {
// 构造函数,在new的时候执行的
// 创建类的实例
constructor(options = {}) {
// this.state = options.state;
// state的数据响应式
// 同时处理了get set操作以及更新
this.s = new Vue({
data() {
return { state: options.state };
},
});
let getters = options.getters;
this.getters = {};
/*
this.getter 代理对 options.getters的操作
getters是一个对象
*/
// Object.keys(getters).forEach((getterName) => {
// // 通过循环,拿出键值,绑定get劫持对象的所有属性
// Object.defineProperty(this.getters, getterName, {
// get: () => {
// return getters[getterName](this.state);
// },
// });
// });
ForEachFn(getters, (getterName, getter) => {
Object.defineProperty(this.getters, getterName, {
get: () => {
return getter(this.state);
},
});
});
let mutations = options.mutations;
this.mutations = {};
// Object.keys(mutations).forEach((mutationName) => {
// //在原方法的基础上 改造
// this.mutations[mutationName] = (payload) => {
// // 传入了响应式的 this.state
// mutations[mutationName](this.state, payload);
// };
// });
ForEachFn(mutations, (mutationName, mutation) => {
// 原来方法的基础上传入 state
this.mutations[mutationName] = (payload) => {
mutation(this.state, payload);
};
});
let actions = options.actions;
this.actions = {};
ForEachFn(actions, (actionName, action) => {
// 原来方法的基础上传入 this
this.actions[actionName] = (payload) => {
action(this, payload);
};
});
}
commit = (mutationName, payload) => {
this.mutations[mutationName](payload);
};
dispatch = (actionName, payload) => {
this.actions[actionName](payload);
};
get state() {
return this.s.state;
}
}
const install = function (_Vue) {
// _Vue Vue的构造函数
Vue = _Vue;
Vue.mixin({
// 混入的生命周期 会在组件的生命周期函数执行之前执行
beforeCreate() {
// new Vue的时候一次
// 渲染APP的时候走一次
if (this.$options && this.$options.store) {
// 根实例
this.$store = this.$options.store;
} else {
// 子实例,从父实例上取得
this.$store = this.$parent && this.$parent.$store;
}
},
});
};
export default {
install, //提供注册的方法 Vue.use的时候调用
Store,
};
store\index.js
import Vue from "vue";
// import Vuex from 'vuex'
import Vuex from "../vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
name: "自己的vuex",
time: "2022-07-26",
age: 1,
score:20
},
mutations: {
addScore(state, val) {
state.score += val;
},
reduceScore(state, val){
state.score -= val;
}
},
actions: {
reduceScore({commit},val){
setTimeout(()=>{
commit("reduceScore",val)
},1000)
}
},
getters: {
allScore(state) {
return `我的积分x3倍是${state.score * 3}分`;
},
},
modules: {},
});
优化的方法:
是指上是从每个对象里面取出来所有key,再对这个key使用指定的回调,会叫的参数是key (方法名)和对象的value(方法)
const ForEachFn = (obj, cb) => {
Object.keys(obj).forEach((key) => {
//key是方法名,obj[key]是方法
cb(key, obj[key]);
});
};
原始的mutations和getters
let getters = options.getters;
this.getters = {};
//this.getter 代理对 options.getters的操作
//getters是一个对象
Object.keys(getters).forEach((getterName) => {
// 通过循环,拿出键值,绑定get劫持对象的所有属性
Object.defineProperty(this.getters, getterName, {
get: () => {
return getters[getterName](this.state);
},
});
});
let mutations = options.mutations;
this.mutations = {};
Object.keys(mutations).forEach((mutationName) => {
//在原方法的基础上 改造
this.mutations[mutationName] = (payload) => {
// 传入了响应式的 this.state
mutations[mutationName](this.state, payload);
};
});