vue-页面离开时二次提示,点击确定离开,点击取消留在当页

1,339 阅读2分钟

前端开发过程中,有一些页面,当用户离开时,需要提醒用户确认是否离开,例如还未支付,提醒用户是否进行支付;我这里的场景是页面是一个大的表单,防止用户填写了很多内容,误触了其他页面,导致之前填写的内容丢失

一、效果

动画.gif

二、实现

由于这一块的逻辑相对独立,所有将这块逻辑抽离到mixin中

utils/backConfirm.js

import { mapState, mapMutations } from 'vuex'
/*
  mixin使用说明:
    1. 导入 import { confirmMixin } from '@/mixins/backConfirm'
    2. 注册 mixins: [confirmMixin],
    3. 需要在data中定义highlight属性,值为需要高亮的路由路径,如:highlight: '/product/product-add/type'
    4. isSubmit参数控制是否需要在离开时给出二次提示,若为true,说明是点击提交按钮离开,此时不需要二次提示;
       若为false,说明是点击浏览器的前进、后退按钮或者是点击其他的菜单栏离开,此时需要二次提示
*/
export const confirmMixin = {
  computed: {
    ...mapState({
      activeIndex: (state) => state.app.activeIndex,
      activePath: (state) => state.app.activePath,
      isSubmit: (state) => state.app.isSubmit
    })
  },
  created() {
    this.SET_IS_SUBMIT(false)
  },
  beforeRouteLeave(to, from, next) {
    // history.pushState(null, null, window.location.href)
    if (this.isSubmit) {
      next() // 允许离开
    } else {
      const answer = window.confirm('确认离开,当前页面的信息将丢失')
      if (answer) {
        next() // 允许离开
      } else {
        next(false) // 阻止导航
        this.SET_ACTIVE_INDEX(this.activeIndex + 1)
        this.SET_ACTIVE_PATH(this.$options.data().highlight)
      }
    }
  },
  mounted() {
    window.addEventListener('beforeunload', this.handleBeforeUnload)
  },
  beforeDestroy() {
    window.removeEventListener('beforeunload', this.handleBeforeUnload)
  },
  methods: {
    ...mapMutations({
      SET_ACTIVE_INDEX: 'app/SET_ACTIVE_INDEX',
      SET_ACTIVE_PATH: 'app/SET_ACTIVE_PATH',
      SET_IS_SUBMIT: 'app/SET_IS_SUBMIT'
    }),
    handleBeforeUnload(event) {
      const message = '确认离开,当前页面的信息将丢失'
      event.returnValue = message
      return message
    }
  }
}

需要在state中定义好3个字段:

  activeIndex: 0, // 每次从产品发布第二页(page2)离开时,如果点击取消,则将此参数加1;在Sidebar组件中,监听此参数,若发生变化,重置菜单栏的高亮为产品发布
  activePath: '', // 需要高亮的菜单
  isSubmit: false // 是否是点击提交按钮离开,默认为false,点击提交离开时设置为true

在mutations中定义3个方法:

  SET_ACTIVE_INDEX: (state, num) => {
    state.activeIndex = num
  },

  SET_ACTIVE_PATH: (state, path) => {
    state.activePath = path
  },

  SET_IS_SUBMIT: (state, isSubmit) => {
    state.isSubmit = isSubmit
  }

使用mixin:mixins: [confirmMixin],

Sidebar组件:

这里是将菜单栏的高亮重置为当前页,需要用到activeIndex属性

给el-menu组件添加ref属性:ref="menuRef"


  watch: {
    // 每次离开产品发布第二页(page2)时,点击取消时,会触发activeIndex变化,此时需要重置菜单栏的高亮为产品发布
    activeIndex: {
      handler() {
        this.$refs.menuRef.activeIndex = this.activePath
      }
    }
  }

三、提示说明

  1. beforeRouteLeave钩子中,一开始是用的this.$confirm方法,但是这个方法在点击浏览器的后退按钮时,无法正常弹出,所以用window.confirm方法
  2. beforeunload事件,可以监听浏览器刷新及关闭窗口

如果你觉得这篇文章对你有用,可以看看作者封装的库xtt-utils,里面封装了非常实用的js方法。如果你也是vue开发者,那更好了,除了常用的api,还有大量的基于element-ui组件库二次封装的使用方法和自定义指令等,帮你提升开发效率。不定期更新,欢迎交流~