# 二.state 的 使用
# 1.案例
- 1.新建 store.js 文件
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
count: 100,
},
});
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 2.在 main.js 中添加 store
import Vue from "vue";
import App from "./App.vue";
import store from "./store";
Vue.config.productionTip = false;
new Vue({
store,
render: (h) => h(App),
}).$mount("#app");
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- 3.在 App.vue 中使用 store 中定义的 count 变量
<template>
<div id="app">
{{this.$store.state.count}}
</div>
</template>
<script>
export default {
name: "app"
};
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 打开浏览器页面出现定义的变量:100
# 2.state 的实现
- 1.在 store.js 中新建 vuex.js 文件
Vue.use(Vuex);
会调用 Vuex 中的install
方法,声明一个变量Vue
,保留用户的构造函数
let Vue;
class Store {}
let install = (_Vue) => {
Vue = _Vue;
};
export default {
Store,
install,
};
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- 2.混合
mixin
,可以给所有的实列混合些东西,beforeCreate
所有的组件创建之前都可以调用
let Vue;
class Store {}
let install = (_Vue) => {
Vue = _Vue;
Vue.mixin({
beforeCreate() {
console.log("aaa");
},
});
};
export default {
Store,
install,
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
调用两次,第一次是 main.js 调用,第二次是 App.vue 组件调用
- 3.我们需要把根组件中 store 实列给每个组件都增加一个
$store
在 vuex.js 中
beforeCreate() {
if (this.$options && this.$options.store) {
this.$store = this.$options.store;
} else {
this.$store = this.$parent && this.$parent.$store;
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
先判断是否是根组件,然后子组件根据父组件的 store 拿到 store
4.组件中调用自己写的 vuex 方法,看是否有 store
在 App.js 中
<template>
<div id="app">
<!-- {{this.$store.state.count}} -->
</div>
</template>
<script>
export default {
name: "app",
mounted() {
console.log(this.$store);
}
};
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
打开浏览器控制台显示:Store {}
5.获取 state 中的值
组件中的 Store 是从 vuex 中 new 出来的
new Vuex.Store
- Store 类中有
state
getters
mutations
actions
等属性,可以通过state
属性拿到state
中的值
let Vue;
class Store {
constructor(options) {
let state = options.state;
this._vm = new Vue({
data: {
state,
},
});
}
get state() {
return this._vm.state;
}
}
let install = (_Vue) => {
Vue = _Vue;
Vue.mixin({
beforeCreate() {
if (this.$options && this.$options.store) {
this.$store = this.$options.store;
} else {
this.$store = this.$parent && this.$parent.$store;
}
},
});
};
export default {
Store,
install,
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- 什么样的属性可以实现双向数据绑定 有
get
和set
如,new vue({data:{}})
- 查看浏览器:100
# 3.getters 的使用
- 1.getter 的使用
sotre.js 中
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
count: 100,
},
getters: {
newCount(state) {
return state.count + 100;
},
},
});
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
App.vue 中
<template>
<div id="app">
{{this.$store.state.count}}
{{this.$store.getters.newCount}}
</div>
</template>
<script>
export default {
name: "app",
mounted() {}
};
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 浏览器页面显示:100 200
# 4. getters 的实现
- 1.将 options 中的 getters 拿出来遍历这个对象,将值返回
let Vue;
class Store {
constructor(options) {
let state = options.state;
this.getters = {};
this.mutations = {};
this.actions = {};
this._vm = new Vue({
data: {
state,
},
});
if (options.getters) {
let getters = options.getters;
forEach(getters, (getterName, getterFn) => {
Object.defineProperty(this.getters, getterName, {
get: () => {
return getterFn(state);
},
});
});
}
}
get state() {
return this._vm.state;
}
}
function forEach(obj, callback) {
Object.keys(obj).forEach((item) => callback(item, obj[item]));
}
let install = (_Vue) => {
Vue = _Vue;
Vue.mixin({
beforeCreate() {
if (this.$options && this.$options.store) {
this.$store = this.$options.store;
} else {
this.$store = this.$parent && this.$parent.$store;
}
},
});
};
export default {
Store,
install,
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
- 页面出现:100 200
# 5.mutations 的使用
- 1.mutations 的用法
store.js
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
count: 100,
},
getters: {
newCount(state) {
return state.count + 100;
},
},
mutations: {
change(state) {
state.count += 10;
},
},
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
App.js
<template>
<div id="app">
{{this.$store.state.count}}
{{this.$store.getters.newCount}}
<button @click="change">add</button>
</div>
</template>
<script>
export default {
name: "app",
mounted() {},
methods: {
change() {
this.$store.commit("change");
}
}
};
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- 点击按钮页面数字加 10
# 6. mutations 的实现
Vuex.js
class Store {
constructor(options) {
let state = options.state;
this.getters = {};
this.mutations = {};
this.actions = {};
this._vm = new Vue({
data: {
state,
},
});
if (options.getters) {
let getters = options.getters;
forEach(getters, (getterName, getterFn) => {
Object.defineProperty(this.getters, getterName, {
get: () => {
return getterFn(state);
},
});
});
}
let mutations = options.mutations;
forEach(mutations, (mutationName, mutationFn) => {
this.mutations[mutationName] = () => {
mutationFn.call(this, state);
};
});
}
get state() {
return this._vm.state;
}
commit(type) {
this.mutations[type]();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
- 刷新浏览器页面数字加 10
# 7.actions 的使用
- 1.action 的用法(异步方法)
store.js
actions: {
change({ commit }) {
setTimeout(() => {
commit("change");
}, 1000);
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
App.js
change() {
this.$store.dispatch("change");
}
1
2
3
2
3
- 点击浏览器按钮 1 秒后加 10
# 8.actions 的实现
store.js
class Store {
constructor(options) {
let state = options.state;
this.getters = {};
this.mutations = {};
this.actions = {};
this._vm = new Vue({
data: {
state,
},
});
if (options.getters) {
let getters = options.getters;
forEach(getters, (getterName, getterFn) => {
Object.defineProperty(this.getters, getterName, {
get: () => {
return getterFn(state);
},
});
});
}
let mutations = options.mutations;
forEach(mutations, (mutationName, mutationFn) => {
this.mutations[mutationName] = () => {
mutationFn.call(this, state);
};
});
let actions = options.actions;
forEach(actions, (actionName, actionFn) => {
this.actions[actionName] = () => {
actionFn.call(this, this);
};
});
let { commit, dispatch } = this;
this.commit = (type) => {
commit.call(this, type);
};
this.dispatch = (type) => {
dispatch.call(this, type);
};
}
get state() {
return this._vm.state;
}
commit(type) {
this.mutations[type]();
}
dispatch(type) {
this.actions[type]();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
- 打开浏览器点击按钮数据加 10
# 9.modules 的使用
store.js
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
a: {
state: {
count: 200,
},
modules: {
b: {
state: {
count: 300,
},
},
},
},
},
state: {
count: 100,
},
getters: {
newCount(state) {
return state.count + 100;
},
},
mutations: {
change(state) {
state.count += 10;
},
},
actions: {
change({ commit }) {
setTimeout(() => {
commit("change");
}, 1000);
},
},
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
App.vue
<template>
<div id="app">
{{this.$store.state.count}}
{{this.$store.getters.newCount}}
{{this.$store.state.a.b.count}}
<button @click="change">add</button>
</div>
</template>
<script>
export default {
name: "app",
mounted() {},
methods: {
change() {
this.$store.dispatch("change");
}
}
};
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- 打开浏览器会有 300 显示出来
# 10.modules 的实现
let Vue;
class ModuleCollection {
// 默认actions mutation 都会定义到store上面
constructor(options) {
// vuex [a]
this.register([], options);
}
register(path, rawModule) {
// path 是个空数组 rawModule就是个对象
let newModule = {
_raw: rawModule, // 对象 当前 有state getters 那个对象
_children: {}, // 表示 他包含的模块
state: rawModule.state, // 自己模块的状态
};
if (path.length == 0) {
this.root = newModule; // 根
} else {
// [a,b]; // reduce方法 {{a.b.c}}
let parent = path.slice(0, -1).reduce((root, current) => {
return root._children[current];
}, this.root);
parent._children[path[path.length - 1]] = newModule;
}
if (rawModule.modules) {
// 有子模块
forEach(rawModule.modules, (childName, module) => {
// [a,b];
// [a,d]
this.register(path.concat(childName), module);
});
}
}
}
// vuex 中间件 可以封装自己的逻辑 subscirbe registerModule unregisterModule
function installModule(store, rootState, path, rootModule) {
// rootState.a = {count:200}
// rootState.a.b = {count:3000}
if (path.length > 0) {
// [a,b]
// 第二次 获取到的就是a对应的对象
let parent = path.slice(0, -1).reduce((root, current) => {
return root[current];
}, rootState);
// {count:1000,a:{}}
Vue.set(parent, path[path.length - 1], rootModule.state);
}
if (rootModule._raw.getters) {
forEach(rootModule._raw.getters, (getterName, getterFn) => {
Object.defineProperty(store.getters, getterName, {
get: () => {
return getterFn(rootModule.state);
},
});
});
}
if (rootModule._raw.actions) {
forEach(rootModule._raw.actions, (actionName, actionFn) => {
let entry = store.actions[actionName] || (store.actions[actionName] = []);
entry.push(() => {
actionFn.call(store, store);
});
});
}
if (rootModule._raw.mutations) {
forEach(rootModule._raw.mutations, (mutationName, mutationFn) => {
let entry =
store.mutations[mutationName] || (store.mutations[mutationName] = []);
entry.push(() => {
mutationFn.call(store, rootModule.state);
});
});
}
forEach(rootModule._children, (childName, module) => {
installModule(store, rootState, path.concat(childName), module);
});
}
class Store {
// state getters mutations actions
constructor(options) {
let state = options.state; // {count:200}
this.getters = {};
this.mutations = {};
this.actions = {};
// 什么样的属性 可以实现双向 有get 和set new vue({data:{}})
// vuex核心就是借用了vue的实例 因为vue的实例数据变化 会刷新视图
this._vm = new Vue({
data: {
state,
},
});
// 把模块直接的关系进行整理 自己根据用户传入的参数维护了一个对象
// root._children=>a._children=>b
this.modules = new ModuleCollection(options);
// 无论是子模块 还是孙子 所有的mutation 都是根上的
// this是store的实例 [] path this.mdoue.root 当前的根模块
installModule(this, state, [], this.modules.root); // {_raw,_children,state}
let { commit, dispatch } = this;
this.commit = (type) => {
commit.call(this, type);
};
this.dispatch = (type) => {
dispatch.call(this, type);
};
}
get state() {
// Object.definefineProperty get
return this._vm.state;
}
commit(type) {
// undefine
this.mutations[type].forEach((fn) => fn());
}
dispatch(type) {
this.actions[type].forEach((fn) => fn());
}
}
function forEach(obj, callback) {
Object.keys(obj).forEach((item) => callback(item, obj[item]));
}
let install = (_Vue) => {
Vue = _Vue; // 保留vue的构造函数
Vue.mixin({
beforeCreate() {
// 我需要把根组件中 store实例 给每个组件都增加一个$store的属性
// 是否是根组件
if (this.$options && this.$options.store) {
debugger;
this.$store = this.$options.store;
} else {
// 子组件 深度优先 父-> 子 -> 孙子
this.$store = this.$parent && this.$parent.$store;
}
},
});
};
export default {
Store,
install,
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143