有vuex的state , getters, mutations ,actions ,modules
会将所有文件的代码分享出来,看不懂的安装vue脚手架 , 然后将这些代码贴进去 ,
然后在main.js文件中引入我写的index.js,然后使用就行
import store from './store'
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
我这里是将index.js放在store文件夹下面
vuex.js文件代码及解析,就是源码
let Vue // 声明Vue变量
// 先看这里 第一步
const install = _Vue => { //在main.js文件中使用了Vue.use(Vuex) 可以使用安装函数 . 函数参数为Vue实例
Vue = _Vue //将Vue实例赋值到全局变量
Vue.mixin({
beforeCreate() { // 为每一个组件的beforeCreate生命周期添加this.$store
if (this.$options && this.$options.store) {
// this.$options 基本等于 main.js中 new Vue({
// el: '#app',
// router,
// store,
// components: { App },
// template: '<App/>'
// })里面的参数
// 所以 this.$options.store = 类 Store的实例
this.$store = this.$options.store //将 this.$options.store 的值赋给 this.$store
}
else {
this.$store = this.$parent && this.$parent.$store
// 如果当前组键不存在 this.$options.store 则拿父亲的$store,这样保证所有的this.$store都是同一个store ,也就是类Store的实例
}
}
})
}
const installCollection = (store, state, path, rootModules) => {
if (path.length > 0) {
// 和上面基本类似
// 主要作用是将 state 由 {name:10}变为
// {
// name: 10, a: {
// x: 1,
// c: { a:8}
// },
// b{}
// }
let parent = path.slice(0, -1).reduce((state, current) => {
return state[current]
}, state)
Vue.set(parent, [path[path.length - 1]], rootModules.state);
}
let getters = rootModules._raw.getters
// 为你传过来的getters
if (getters) {
Object.keys(getters).forEach(getter => {
// 将所有的getter 属性 劫持在最外层的getters 上 也就是this.$store.getters
Object.defineProperty(store.getters, getter, {
get: () => {
return getters[getter](rootModules.state)
//getters的参数为当前state
}
})
})
}
let mutations = rootModules._raw.mutations
if (mutations) {
// 为你传过来的mutations
Object.keys(mutations).forEach(mutation => {
let arr = store.mutations[mutation] || (store.mutations[mutation] = [])
// 将this.$store.mutations转化成 {
// syncadd:[],
// asyncsub:[]
// }格式
// 因为执行 如 this.$store.commit("syncAdd", 10);代码 会将所有模块中的syncAdd执行
arr.push((...parmas) => {
// 将需要执行的函数放入队列中
mutations[mutation].call(store, rootModules.state, ...parmas)
})
})
}
let actions = rootModules._raw.actions
// 为你传过来的actions
if (actions) {
//基本类似mutations ,只是actions的第一个参数为 Store实例 ,mutaions的第一个参数为state
Object.keys(actions).forEach(action => {
let arr = store.actions[action] || (store.actions[action] = [])
arr.push((...parmas) => {
actions[action].call(store, store, ...parmas)
})
})
}
if (rootModules._children) {
Object.keys(rootModules._children).forEach(moduleName => {
installCollection(store, state, path.concat(moduleName), rootModules._children[moduleName])
})
}
}
// 第三步
class ModelesCollection {
// 主要目的是整合module,将module放入_children中,方便递归.
// 如 原仓库 :{
// state:{x:30},
// getter:{},
// ....,
// module:{
// a:{
// state:{ y:50},
// getter:{},
// ....
// },
// b:{
// state:{},
// getter:{},
// ....
// }
// }
// }
// 将数据整合成如下格式:
// _root = {
// _children: {
// a: {
// _children: {},
// state: {y:50},
// _row: {}
// },
// b: {
// _children: {},
// state: {},
// _row: {}
// }
// },
// _raw:{}, // _row 就是当前的模块仓库 ,如最外层的_raw就是this.$store
// state:{x:30}
// }
// }
constructor(options) {
this.register([], options) // 调用 register 函数 ,options 如第一次调用 opts 是 new Store 传过来的参数,也就是 index.js中 new Vuex.Store的参数
}
register(path, rootModules) {
let newModules = {
_raw: rootModules,
state: rootModules.state || {},
_children: {}
}
if (path.length === 0) { // 步骤 :3_1 当前的仓库没有父级,让this._root 为newModules
this._root = newModules
} else {
let parent = path.slice(0, -1).reduce((root, current) => {
return root._children[current]
}, this._root) //获取倒数第二个模块,让其成为父亲,如果长度为1 则父亲为 this._root
// 步骤 :3_3
// parent 分别为 this._root , this._root, a模块
parent._children[path[path.length - 1]] = newModules
}
if (rootModules.modules) { // 步骤 :3_2
Object.keys(rootModules.modules).forEach(moduleName => {
this.register(path.concat(moduleName), rootModules.modules[moduleName])
// 联合index 中的数据
// 此时 path.concat(moduleName) 分别为 ['a'],['b'],['a','c']
// rootModules.modules[moduleName] 分别为a模板中的所有数据,b模块中的所有数据,c模块中的所有数据
})
}
}
}
// 第二步
// 上面this.$store 就是这个类的实例
class Store {
constructor(opts) { //opts 是 new Store 传过来的参数,也就是 index.js中 new Vuex.Store的参数
this._vm = new Vue({
data() {
return {
state: opts.state
}
}
})
// 将state中的数据放入vue中的data中
this.getters = {} //创建一个空的getters 对象
this.mutations = {} //创建一个空的mutations 对象
this.actions = {} // 创建一个空的actions对象
this.modules = new ModelesCollection(opts) //跳转到第三步
installCollection(this, this.state, [], this.modules._root)
// 跳转到第四步 参数分别为 Store的实例 , 就是你使用的this.$store , 最外层的 state , 路径 空数组 代表无父亲 为 root , 如[a,b,c]则,a的父亲为root,b的父亲为a,c的父亲为b
//第四个参数 就是这类数据
// {
// _raw: rootModules,
// state: rootModules.state || {},
// _children: {}
// }
}
get state() {
return this._vm.state //当读 this.$store.state 时触发 ,返回 opts.state ,也就是仓库中的state
}
commit = (type, ...parmas) => {
//执行所有type 类型的函数
this.mutations[type].forEach(fn => {
fn(...parmas)
})
}
dispatch = (type, ...parmas) => {
// 基本同 commit
this.actions[type].forEach(fn => {
fn(...parmas)
})
}
}
export default {
Store,
install
}
APP.vue文件代码
<template>
<div id="app">
<div>{{this.$store.state.name}}</div>
<div>{{this.$store.getters.myage}}</div>
<div>{{this.$store.getters.y}}</div>
<div>{{this.$store.state.a.x}}</div>
<button @click="add">+10</button>
<button @click="sub">-10</button>
<router-view />
</div>
</template>
<script>
export default {
name: "App",
mounted() {
console.log(this.$store);
setTimeout(() => {
this.$store.state.name = 100;
}, 1000);
},
methods: {
add() {
this.$store.commit("syncAdd", 10);
},
sub() {
this.$store.dispatch("asyncSub", 10);
}
}
};
</script>
index.js 代码 就是仓库代码
import Vue from 'vue'
import Vuex from './vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
name: 10
},
getters: {
myage(state) {
return state.name + 10
}
},
mutations: {
syncAdd(state, parmas) {
state.name += parmas
},
syncsub(state, parmas) {
state.name -= parmas
}
},
actions: {
asyncSub({ commit, dispatch }, ...parmas) {
setTimeout(() => {
commit('syncsub', ...parmas)
}, 1000);
}
},
modules: {
a: {
state: {
x: 1,
},
getters: {
y(state) {
return state.x + 3
}
},
modules: {
c: {
state: {
a:8
}
}
},
mutations: {
syncAdd(state, parmas) {
console.log(123);
}
},
},
b: {}
}
})