手写一个简易版的 vuex(支持 state,getters,mutations,actions)
简介:vuex 相信大家都用过,内部到底是如何实现的呢,我根据源码以及一些参考资料,手写了一个简易版的 vuex,供大家参考。
下面是实现步骤
1.项目依赖:(先安装,步骤略)
package.json
1 | { |
2 | "name": "vue-my-vuex", |
3 | "version": "0.1.0", |
4 | "private": true, |
5 | "scripts": { |
6 | "serve": "vue-cli-service serve", |
7 | "build": "vue-cli-service build", |
8 | "lint": "vue-cli-service lint" |
9 | }, |
10 | "dependencies": { |
11 | "core-js": "^3.6.4", |
12 | "vue": "^2.6.11", |
13 | "vuex": "^3.1.3" |
14 | }, |
15 | "devDependencies": { |
16 | "@vue/cli-plugin-babel": "~4.3.0", |
17 | "@vue/cli-plugin-eslint": "~4.3.0", |
18 | "@vue/cli-plugin-vuex": "^4.3.1", |
19 | "@vue/cli-service": "~4.3.0", |
20 | "babel-eslint": "^10.1.0", |
21 | "eslint": "^6.7.2", |
22 | "eslint-plugin-vue": "^6.2.2", |
23 | "vue-template-compiler": "^2.6.11" |
24 | } |
25 | } |
2.项目目录结构
3.核心代码
/src/store/Vuex.js
1 | export let Vue |
2 | function install(_Vue) { |
3 | Vue = _Vue |
4 | |
5 | Vue.mixin({ |
6 | beforeCreate() { |
7 | // 在vue原型上注册$store |
8 | if (this.$options.store) { |
9 | Vue.prototype.$store = this.$options.store |
10 | } |
11 | } |
12 | }) |
13 | } |
14 | |
15 | class Store { |
16 | constructor(options) { |
17 | this.$option = options |
18 | |
19 | // 使用vue实例使state响应式 |
20 | this.state = new Vue({ |
21 | data: options.state |
22 | }) |
23 | |
24 | // 保存options里的mutations,actions |
25 | this.mutations = options.mutations || {} |
26 | this.actions = options.actions || {} |
27 | |
28 | // 实现getters |
29 | this.getters = {} |
30 | // 使getters响应式 |
31 | Object.keys(options.getters).forEach(key => { |
32 | Object.defineProperty(this.getters, key, { |
33 | get: () => { |
34 | return options.getters[key](this.state) |
35 | }, |
36 | enumerable: true |
37 | }) |
38 | }) |
39 | } |
40 | |
41 | // 实现commit方法 |
42 | commit(type, pyload) { |
43 | this.mutations[type](this.state, pyload) |
44 | } |
45 | |
46 | // 实现dispatch方法 |
47 | dispatch(type, pyload) { |
48 | this.actions[type]( |
49 | { |
50 | state: this.state, |
51 | commit: this.commit.bind(this) |
52 | }, |
53 | pyload |
54 | ) |
55 | } |
56 | } |
57 | |
58 | export default { Store, install } |
59 | /** |
60 | * 这样导出 相当于 |
61 | * const Vuex={Store,install} |
62 | * export default Vuex |
63 | * |
64 | *之所以这样导出 是因为使用的时候是 new Vuex.Store() |
65 | */ |
/src/App.vue
1 | <template> |
2 | <div id="app"> |
3 | <h1>App 组件</h1> |
4 | <div>计数:{{ $store.state.count }}个</div> |
5 | <div>getters计数:{{ $store.getters.count }}个</div> |
6 | <button @click="add">commit加</button> |
7 | <button @click="dispatchAdd">dispatch加</button> |
8 | |
9 | <HelloWorld msg="Welcome to Your Vue.js App" /> |
10 | </div> |
11 | </template> |
12 | |
13 | <script> |
14 | import HelloWorld from './components/HelloWorld.vue' |
15 | |
16 | export default { |
17 | name: 'App', |
18 | components: { |
19 | HelloWorld |
20 | }, |
21 | methods: { |
22 | add() { |
23 | this.$store.commit('ADD_COUNT', 100) |
24 | }, |
25 | dispatchAdd() { |
26 | this.$store.dispatch('addCount', 1) |
27 | } |
28 | } |
29 | } |
30 | </script> |
31 | |
32 | <style> |
33 | #app { |
34 | font-family: Avenir, Helvetica, Arial, sans-serif; |
35 | -webkit-font-smoothing: antialiased; |
36 | -moz-osx-font-smoothing: grayscale; |
37 | text-align: center; |
38 | color: #2c3e50; |
39 | margin-top: 60px; |
40 | } |
41 | </style> |
/src/components/HelloWorld.vue
1 | <template> |
2 | <div class="hello"> |
3 | <h1>HelloWorld 组件</h1> |
4 | {{ $store.state.count }} |
5 | </div> |
6 | </template> |
7 | |
8 | <script> |
9 | export default { |
10 | name: 'HelloWorld', |
11 | props: { |
12 | msg: String |
13 | } |
14 | } |
15 | </script> |
4.实现效果
参考链接