共计 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>
正文完