平时用vuejs写业务页面时,发现常常会用到雷同的逻辑去搭建页面,初始化数据、校验参数、子页体面路由的渲染等。所以在这里总结一下这种页面的初始化套路,不便后续创立页面或者优化逻辑。
设计准则
利用公布-订阅的模式去初始化子页面,父页面解决全局的相干操作。
- 父页面:校验参数、数据的合法性,并发网络申请,疏导至全局的谬误页面,最终触发initReady=true。
- 子页面:订阅initReady事件,胜利后进行子页面初始化。
逻辑图
代码设计
1. vuex状态数据
// store.jsimport global from './modules/global';import cards from './modules/cards';export default { namespaced: true, modules: { global, cards, },};
// ./modules/global.js/** 全局数据*/export default { // 命名空间隔离 namespaced: true, state: { // 全局事件-初始化实现,子页面订阅此事件的变更 initReady: false, // 全局错误码 error: null, // 全局常量,不可更改 constants: Object.freeze({ test: 1, }), }, mutations: { SET_INIT_READY(state, value) { state.initReady = value; }, SET_ERROR(state, value) { state.error = value; }, }, actions: { setInitReady({ commit }, value) { commit('SET_INIT_READY', !!value); }, setError({ commit }, value) { commit('SET_ERROR', value || null); }, },};
// ./modules/cards.js/** 卡列表相干数据*/export default { // 命名空间隔离 namespaced: true, state: { // 以后卡 currentCard: {}, // 卡列表 cardsList: [], }, mutations: { SET_CURRENT_CARD(state, value) { state.currentCard = value; }, SET_CARDS_LIST(state, value) { state.cardsList = value; }, }, actions: { setCurrentCard({ commit }, value) { commit('SET_CURRENT_CARD', value || {}); }, setCardsList({ commit }, value) { commit('SET_CARDS_LIST', value || []); }, },};
2. vue router路由定义
// routes.js,subApp的路由定义const index = () => import(/* webpackChunkName: "HcTplSubApp" */ './views/index.vue');const home = () => import(/* webpackChunkName: "HcTplSubApp" */ './views/home.vue');export default [ { path: '/', component: index, meta: { title: '首页', }, children: [ { path: '', // 首页 name: 'RouteHome', // 应用路由名字进行跳转,有助于代码易读性 component: home, meta: { title: '首页', keepAlive: true, }, }, ], },];
3. index父页面
<template> <div class="page-index"> <!-- 谬误提醒 --> <error-page v-if="error" :error="error || {}"></error-page> <!-- 子页面 --> <template v-if="initReady"> <!-- 缓存 --> <keep-alive> <router-view v-if="$route.meta.keepAlive"/> </keep-alive> <!-- 非缓存 --> <router-view v-if="!$route.meta.keepAlive"/> </template> </div></template><script>import { mapActions, mapState } from 'vuex';import ErrorPage from '@/components/common/ErrorPage';export default { name: 'PageIndex', components: { ErrorPage, }, data() { return { // loading spinner loading: null, }; }, computed: { ...mapState('tpl/global', { initReady: state => state.initReady, constants: state => state.constants, error: state => state.error, }), ...mapState('tpl/cards', { cardsList: state => state.cardsList, currentCard: state => state.currentCard, }), }, created() { this.initPage(); }, methods: { ...mapActions('tpl/global', [ 'setInitReady', 'setError', ]), ...mapActions('tpl/cards', [ 'setCurrentCard', 'setCardsList', ]), /** * 全局初始化 */ async initPage() { this.loading = this.$weui.loading('加载中'); // 校验参数 if (!this.validateQuery()) { if (this.loading) this.loading.hide(); return; } // 所有初始化的异步申请 await Promise.all([this.initCard()]); // 校验后果 if (!this.validateResult()) { if (this.loading) this.loading.hide(); return; } // 触发ready事件 this.setInitReady(true); }, /** * 校验参数合法性 */ validateQuery() { const { hospitalId = '' } = this.$route.query; if (!hospitalId) { this.setError({ message: '医院标识[hospitalId]不能为空' }); return false; } return true; }, /** * 校验全局数据,报错或跳转 */ validateResult() { // 卡列表数据为空,跳转第三方链接建卡 if (this.cardsList.length === 0) { this.setError({ message: '卡列表不能为空' }); return false; } return true; }, /** * 获取卡列表 */ async initCard() { // 利用卡列表插件读取卡列表 const { card, cards } = await this.$Card.init(); this.setCurrentCard(card); this.setCardsList(cards); // 校准url里的healthCardId参数 const { query } = this.$route; if (card.healthCardId && query.healthCardId !== card.healthCardId) { await this.$router.replace({ query: { ...query, healthCardId: card.healthCardId, ecardNo: card.ecardNo, }, }); } }, },};</script><style lang="scss" scoped>.page-index {}</style>
4. home子页面
<template> <div class="page-home"> page home </div></template><script>import { mapState } from 'vuex';import pageMixin from 'hc-vue-mixins/page';export default { name: 'PageHome', mixins: [pageMixin], data() { return { // loading spinner loading: null, }; }, computed: { ...mapState('tpl/global', { initReady: state => state.initReady, }), ...mapState('tpl/cards', { cardsList: state => state.cardsList, currentCard: state => state.currentCard, }), }, // 利用hooks或者watch来订阅initReady事件 created() { if (this.initReady) this.initPage(); }, watch: { initReady() { if (this.initReady) this.initPage(); }, }, methods: { /** * 初始化 */ async initPage() { this.loading = this.$weui.loading('加载中'); // do something in this page console.log(this.currentCard); console.log(this.cardsList); this.loading.hide(); }, },};</script><style lang="scss">.page-home {}</style>