关于vue.js:vuejs业务页面的发布订阅代码设计

8次阅读

共计 4205 个字符,预计需要花费 11 分钟才能阅读完成。

平时用 vuejs 写业务页面时,发现常常会用到雷同的逻辑去搭建页面,初始化数据、校验参数、子页体面路由的渲染等。所以在这里总结一下这种页面的初始化套路,不便后续创立页面或者优化逻辑。

设计准则

利用公布 - 订阅的模式去初始化子页面,父页面解决全局的相干操作。

  • 父页面:校验参数、数据的合法性,并发网络申请,疏导至全局的谬误页面,最终触发 initReady=true。
  • 子页面:订阅 initReady 事件,胜利后进行子页面初始化。

逻辑图

代码设计

1. vuex 状态数据

// store.js

import 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>
正文完
 0