1、给 Vue 实例添加类似 vue-router 插件的 $router 的属性
2、给 Vue 实例添加钩子(类似)(仅是回调函数,不影响生命周期)
Vue 2.x 。(实际使用 Vue 2.6.10)
最近一个Vue项目,使用 Vuex 管理数据。为了方便,使用了 VueX 的插件 vuex-orm 以及 vuex-orm 的插件 vuex-orm-localforage 。
需要在 mounted 中 通过 vuex-orm 查询数据 ,但是由于 vuex-orm-localforage 从持久层恢复数据是异步的,mounted 时,数据还未恢复,查询到 undefined,此时 vuex-orm 无法更新查询结果。导致数据永远为 undefined。
有几个解决办法。
在数据恢复之后,通过事件总线 分发 restored 事件,Vue实例中监听该事件,更新数据。
缺陷:
造成重复代码,虽然只增加三四行代码,但是如果勉强止步与此,就永远学不到更好的方案。
这样就能保证,mounted时 能够访问到 所有数据 。原来的代码:
const vue = new Vue({ store, router, render: h => h(App)}).$mount('#app')
改为:
const vue = new Vue({ store, router, render: h => h(App)})
const promises = restoreData() // 恢复数据返回Promise数组
Promise.all(promises).then(() => vue.$mount('#app'))//恢复成功后挂载
但是,此方案缺陷更严重。
缺陷:数据量比较大时,恢复严重影响页面加载速度
考虑到我的应用中,vuex-orm无法更新数据的查询都是在子路由中,只有开发环境时,为了方便才会直接打开路由路径。在此方方案,基础上判断是否是生产环境,再决定挂载顺序,也勉强可以接受。
然后代码中 使用 promise.then 即可。
let restored = Promise.all(restore())
export { restored }
// 使用时调用 restored.then即可
使用的地方较多,需要不停的 import 。我比较懒,就得想更好的办法改进
何不像 vuex 和 vue-router 那的 this.$store 那样, 为 Vue 混入 $restore 。 Vuex vue-router能做到,我们一定也可以。
Vuex 是通过 Vue.mixin 来混入 ,查询一下 Vue.mixin的API ,即刻动手
/**
* restore init
*/
function initRestore () {
const options = this.$options
if (options.restore) {
this.$restore = options.restore
} else if (options.parent && options.parent.$restore) {
this.$restore = options.parent.$restore
}
}
// 导出 mixin 选项
export default { created: initRestore }
然后new Vue 的时候 传入 restore 即可
const restore = Promise.all(restoring())
const vue = new Vue({ store, router, restore render: h => h(App)}).$mount('#app')
注意此处 修改了一下方法名称
混入 restored 钩子,这样使用时,又省了一层箭头函数。
/store
// file mixin.js
/**
* restore init
*/
function initRestore () {
const options = this.$options
if (options.restore) {
this.$restore = options.restore
} else if (options.parent && options.parent.$restore) {
this.$restore = options.parent.$restore
}
}
/**
* 给 Vue 实例添加 restored 钩子。
* resotore 完成之后调用(无论成功失败)
*/
function initRestored () {
const restored = this.$options.restored
if (restored && (typeof restored === 'function')) {
if (this.$restore) {
this.$restore.finally(() => restored.call(this))
}
}
}
// 导出 mixin 选项
//export default { created: initRestore, mounted: initRestored }
// 为了示意 省略 导出、导入,直接写在一个文件
Vue.minx({ created: initRestore, mounted: initRestored })
main.js
const restore = Promise.all(restoring())
const vue = new Vue({ store, router, restore render: h => h(App)}).$mount('#app')
/views 或者 /components
export default {
data(){},
mounted(){},
restored(){
// 像 mounted 一样
}
}