一、背景
目标:如果当前页面中有正在编辑中的内容,那么此时切换组件、跳转路由、关闭标签页、刷新页面,都会有离开确认提示,防止用户因误触导致填写的内容白费。
后台管理系统中有许多需要填写的表单,弹窗方式的表单一般都会关掉或提交,而单页个面的表单,有时候会忘记暂存或提交,直接离开页面,导致千辛万苦填写的内容全部置空,这是非常不友好的!!!于是,需要实现一个功能:如果当前页面中存在编辑中的内容,那么离开页面之前,要弹窗提示用户是否确认离开。
二、实现
1、路由守卫
考虑到会有许许多多个编辑表单的单页面,所以将编辑状态存在store里,并通过路由守卫来判断是否弹出弹窗。
①store/router.js
const state = {// 定义全局的 isEditing 状态 isEditing: false
}const mutations = {// 定义修改 isEditing 状态的 mutation SET_EDITING(state, isEditing) { state.isEditing = isEditing; }
}const actions = {setEditing({ commit }, data) {commit('SET_EDITING', data)}
}export default {namespaced: true,state,mutations,actions
}
②路由守卫
import router from '../router'
import store from '../store'
import { MessageBox } from 'element-ui'
// 其它......router.beforeEach(async(to, from, next) => {// 其它......if(!store.state.router.isEditing){ //页面中无正在编辑内容await routerPermission(to, from, next)}else{//页面中含有正在编辑内容MessageBox.confirm('您所做的更改暂未保存,确认离开页面?', '温馨提示', { confirmButtonText: '离开', cancelButtonText: '取消', type: 'warning' }) .then(async() => { store.commit('router/SET_EDITING', false)// 用户点击了确认,执行跳转 ==> 进入页面权限判断await routerPermission(to, from, next)}) .catch(() => { // 用户点击了取消或关闭了对话框,阻止路由跳转 next(false); // 传入 false 来取消导航 }); }// 其它......
})
通过这种全局的方式,可以在任何需要有这种判断的地方让isEditing变成true即可。下面是一个例子:
isEditProp(newVal) {this.isEdit = newValif(newVal===false){this.$emit('update:showEdit', false)}// 如果是整个表单一次性提交,则编辑状态下离开页面需要提示if(this.isAllAtOnce){this.$store.commit('router/SET_EDITING', newVal)}}
2、关闭标签页/刷新页面提示
如果用户填写一半,不小心关闭标签页或者刷新页面,也会导致表单清空,这也是一种很糟糕的情况,所以,我们还需要一个关闭标签页提示。
mounted() {window.addEventListener('beforeunload', e => this.beforeunloadHandler(e))},beforeDestroy() {window.removeEventListener('beforeunload', e => this.beforeunloadHandler(e))},methods: {beforeunloadHandler(e) {this._beforeUnload_time = new Date().getTime()e = e || window.eventif (e && this.$store.state.router.isEditing) {e.returnValue = '关闭提示'}return '关闭提示'},}
3、组件切换
对于tabs页面,切换视图并不会引起路由变化,所以路由守卫就不起作用了,这个时候,我们就要在组件切换之前进行提示。
①给el-tabs绑定一个事件:before-leave="confirmLeave"
<el-tabs:value="actived"class="tabs-container"v-bind="$attrs"@tab-click="tabClick":before-leave="confirmLeave">......</el-tabs>
②写提示方法
methods: {async confirmLeave(pane){if(pane!=='flimLibrary' && this.$store.state.router.isEditing){return await this.$confirm('您所做的更改暂未保存,确认离开页面??', '温馨提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.$store.commit('router/SET_EDITING', false)this.$emit('update:actived', pane)this.isIgnore = truereturn true}).catch(() => {this.isIgnore = falsereturn reject()})}}},
这样处理之后就成功实现了预期的效果啦!
三、 效果
①切换组件/跳转路由
②关闭标签页
③刷新页面