Open rottenpen opened 4 years ago
let Vue
// const isObject = (obj) => {
// return obj !== null && typeof obj === 'object'
// }
// const isPromise = (val) => {
// return val && typeof val.then === 'function'
// }
// function forEachValue (obj, fn) {
// Object.keys.forEach(key => {
// fn(obj, obj(key))
// })
// }
function forEachValue (obj, fn) {
// debugger
Object.keys(obj).forEach(function (key) { return fn(obj[key], key) })
}
function unifyObjectStyle (type, payload, options) {
if (typeof type === 'object' && type.type) {
options = payload
payload = type
type = payload.type
}
return {
type,
payload,
options
}
}
class Store {
constructor (options) {
this.vm = {
state: Vue.observable(options.state)
}
this.getters = Object.create(null)
this.actions = Object.create(null)
this.mutations = Object.create(null)
const store = this
// TODO: 依赖值变化的时候就变化,可以 store.getters.xxx 直接获得值,不需要另外运行函数,可以接受其他 getter 作为参数
const getters = options.getters || {}
forEachValue(getters, (fn, key) => {
Object.defineProperty(getters, key, {
get: function (state) {
return fn(store.state, store.getters)
}
})
})
// TODO: mutations 传一个 state 一个 payload 用于同步调用
const mutations = options.mutations || {}
forEachValue(mutations, (fn, key) => {
this.mutations[key] = (payload) => {
fn(this.state, payload)
}
})
// TODO: actions 传入一个 state 一个 payload 用于异步调用 在异步函数里想同步更新 state 需要再调用 mutations
const actions = options.actions || {}
forEachValue(actions, (fn, key) => {
this.actions[key] = (payload) => {
fn(this, payload)
}
})
}
get state () {
return this.vm.state
}
set state (v) {
console.error('不能直接赋值 state')
}
commit (_type, _payload, _options) {
const { type, payload, options } = unifyObjectStyle(_type, _payload, _options)
this.mutations[type](payload)
console.log(options)
}
dispatch (_type, _payload, _options) {
const { type, payload, options } = unifyObjectStyle(_type, _payload, _options)
this.actions[type](payload)
console.log(options)
}
}
// TODO: 一些辅助函数 用于映射 getters actions mutations
const mapGetters = () => {}
const mapActions = () => {}
const mapMutations = () => {}
const install = (_Vue) => {
// 证明之前已经安装了一次 vue store了
if (Vue && _Vue === Vue) {
return
}
Vue = _Vue
applyMixin(Vue)
}
function applyMixin (_Vue) {
// 为所有的 vue 组件植入 $store
_Vue.mixin({
beforeCreate: vueInit
})
function vueInit () {
const options = this.$options
if (options.store) { // 在根元素 App.vue 里引入包内的 store 类
this.$store = typeof options.store === 'function'
? options.store()
: options.store
} else if (options.parent && options.parent.$store) { // 自组件就直接用父组件的 $store 就可以了
this.$store = options.parent.$store
}
}
}
export default {
install,
Store,
mapActions,
mapGetters,
mapMutations
}
vuex 的功能模块
TODO: