接下来,将 src/main.js 中对于 pinia 的引用改成对自己实现的引用。
1 2 3
|
import { createPinia } from '@/pinia'
|
新建 src/pinia/index.js 作为库的入口文件。前面的 TodoList 中用到了两个方法:createPinia
和 defineStore
。
1 2 3 4 5
| import createPinia from './createPinia' import defineStore from './defineStore'
export { createPinia, defineStore }
|
观察 app.use(createPinia())
可知,createPinia
是一个方法,返回一个包含 install
方法的对象,可以作为 app.use
方法的参数。
1 2 3 4 5 6 7
| export default () => { function install(app) {} return { install } }
|
创建一个总的 Store,来存储所有通过 defineStore
方法创建的 store。
1 2 3 4 5 6 7 8 9 10 11 12
| import { reactive } from 'vue'
export default () => { const piniaStore = reactive({})
function install(app) {}
return { install } }
|
要把 piniaStore
暴露出来供 defineStore
调用,可以使用 vue 提供的 provide
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { reactive } from 'vue'
export default () => { const piniaStore = reactive({})
function install(app) { app.provide('piniaStore', piniaStore) }
return { install } }
|
但是把整个 Store 暴露出来并不十分合理,可以改成把存入 store 的方法 setSubStore
暴露出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import { reactive } from 'vue'
export default () => { const piniaStore = reactive({})
function setSubStore(name, store) { if (!piniaStore[name]) { piniaStore[name] = store } return piniaStore }
function install(app) { app.provide('setSubStore', setSubStore) }
return { install } }
|
一些公共的 api 比如 $patch
可以在这里传入。新建一个文件 src/pinia/apis.js。
1 2 3 4 5 6 7 8
| export function patch({ value }) { const store = this
for (let key in value) { store[key] = value[key] } }
|
给 store 添加上公共的 api。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import { reactive } from 'vue' import { patch } from './apis'
export default () => { const piniaStore = reactive({})
function setSubStore(name, store) { if (!piniaStore[name]) { piniaStore[name] = store piniaStore[name].$patch = patch } return piniaStore }
function install(app) { app.provide('setSubStore', setSubStore) }
return { install } }
|
观察 src/store/todoList.js 中对 defineStore
方法的调用可知,该方法第一个参数是 store 的名称,第二个参数是 options 对象。
1 2 3 4 5 6 7 8 9 10 11
| export default ( name, { state, getters, actions } ) => { const store = {} }
|
先来实现 state
,并将 store
打印出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import { reactive, toRef } from 'vue'
export default ( name, { state, getters, actions } ) => { const store = {}
if (state && typeof state === 'function') { const _state = state() store.$state = reactive(_state)
for (let key in _state) { store[key] = toRef(store.$state, key) } }
console.log(store) }
|

然后来实现 actions
。
1 2 3 4 5 6 7 8
|
if (actions && Object.keys(actions).length > 0) { for (let method in actions) { store[method] = actions[method] } }
|

再来实现 getters
。getters
里面的方法都:
- 接收一个
state
参数;
- 其中的
this
指向 state
;
- 可以通过形如
this.anotherGetter()
这样的语句调用其他 getter。
1 2 3 4 5 6 7 8 9
|
if (getters && Object.keys(getters).length > 0) { for (let getter in getters) { store[getter] = getters[getter].bind(store.$state, store.$state) store.$state[getter] = store[getter] } }
|
优化一下代码,将 state、actions、getters 的处理拆分到单个文件中。
1 2 3 4 5 6 7 8 9 10 11
| import { reactive, toRef } from 'vue'
export function createStates(store, state) { const _state = state() store.$state = reactive(_state)
for (let key in _state) { store[key] = toRef(store.$state, key) } }
|
1 2 3 4 5 6
| export function createActions(store, actions) { for (let method in actions) { store[method] = actions[method] } }
|
1 2 3 4 5 6 7 8 9 10 11
| import { computed } from 'vue'
export function createGetters(store, getters) { for (let getter in getters) { store[getter] = computed( getters[getter].bind(store.$state, store.$state) ) store.$state[getter] = store[getter] } }
|
1 2 3 4 5 6
| import { createStates } from './state' import { createActions } from './action' import { createGetters } from './getter'
export { createStates, createActions, createGetters }
|
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
| import { inject, reactive } from 'vue'
import { createStates, createActions, createGetters } from './options'
export default ( name, { state, getters, actions } ) => { const store = {}
state && typeof state === 'function' && createStates(store, state) actions && Object.keys(actions).length > 0 && createActions(store, actions) getters && Object.keys(getters).length > 0 && createGetters(store, getters)
return () => { const setSubStore = inject('setSubStore') const piniaStore = setSubStore(name, reactive(store))
return piniaStore[name] } }
|
TodoList 的功能完美实现,将 store 打印出来看,有一点小瑕疵,但总体上前面分析的都实现了。

本小节完。