问题描述:
最近项目有一个需求,在表单填写相关页面,如果用户没有保存表单内容,点击导航栏将要离开页面的时候提示“信息未保存,离开页面数据将会丢失,是否确定离开?”
(1)选择“确定” —— 执行路由跳转
(2)选择“取消” —— 中止跳转,仍旧留在当前页
以上为需求描述,遇到的问题是:选择取消后,侧导航栏的高亮项不正确。
简单示例如下图:点击“错误收集”,取消路由跳转,页面仍停留在“指令”页面,但是路由高亮已经变成了“错误收集”。
解决思路:
1. 在当前页面中添加路由守卫,满足条件继续跳转,否则中止跳转;
2. 给导航栏menuItem添加自定义高亮样式(如 class="xmj-menu-active"),不要用iview的menu组件的默认高亮类(目前没有找到使用默认高亮类名 ".ivu-menu-item-active.ivu-menu-item-selected" 时候的解决方法);
3. 在路由更新时相应改变active-class(beforeRouteEnter,beforeRouteUpdate);
代码示例:
(1)当前表单页面:
<!-- formPage.vue -->
<template>
<div>
<p>模拟当前页表单数据保存状态:{{saved}}</p>
<Modal
v-model="modalShow"
title="确定离开么?"
@on-ok="ok"
@on-cancel="cancel">
<p>当前页面数据未保存,离开后数据将会丢失。</p>
</Modal>
</div>
</template>
<script>
export default {
name: 'form_page',
data () {
return {
saved: false,
modalShow: false,
next: null
}
},
methods:
ok () { // 用户点击确认
this.next()
},
cancel () { // 用户点击取消
this.modalShow = false
}
},
// 在路由拦截中判断当前页表单是否保存,已保存->继续,未保存->中止跳转,展示弹窗
beforeRouteLeave (to, from, next) {
if (this.saved) {
next()
} else {
this.modalShow = true
this.next = next
next(false)
}
}
}
</script>
(2)主页面main.vue
<!-- main.vue -->
<template>
<div>
<!-- ...省略 -->
<Menu
:active-name="routeActiveName"
theme="light"
width="auto"
:accordion="true"
:open-names="vexOpenNames?[vexOpenNames]:openNames"
@on-select="changeMenu"
>
<div v-for="item in menuList.list" :key="item.id">
<Submenu v-if="item.list&&item.list.length" :name="item.code">
<template slot="title">{{item.name}}</template>
<!-- ** 注意:此处自定义高亮类 xmj-menuitem-active ,添加相应样式,不使用默认的iview高亮类名 ** -->
<MenuItem
v-for="v in item.list"
:name="v.code"
:key="v.id"
:class="['menuItem1', routeActiveName==v.code?'xmj-menuitem-active': '']"
>
<span>{{v.name}}</span>
</MenuItem>
</Submenu>
<!-- ...省略 -->
</div>
</Menu>
</div>
</template>
<script>
export default {
name: 'main_page',
data () {
return {
routeActiveName: this.$route.name,
menuList: [] // 后台拉取的路由权限列表,动态渲染导航栏
}
},
// 在当前路由改变,但是该组件被复用时调用
beforeRouteUpdate (to, from, next) {
this.routeActiveName = to.name
next()
},
// 在渲染该组件的对应路由被 confirm 前调用, 不!能!获取组件实例 `this`, 但是在 next() 里面可以通过vm访问组件实例
beforeRouteEnter (to, from, next) {
next(vm => {
vm.routeActiveName = to.name
})
},
methods: {
changeMenu () {
this.$router.push('/' + active)
}
}
}
</script>
<style>
.xmj-menuitem-active {
/* 高亮样式 */
}
</style>