element-plus $confirm 弹框中实现enter不触发确认按钮

背景:放置用户误操作,对删除按钮的confirm弹框中,误触回车键,导致删除。
条件:element-plus组件

先来一段视频:

废话不多说:代码如下

 this.$confirm(tip, this.$t('public.delete'), {
    confirmButtonText: this.$t('public.delete'),
    cancelButtonText: this.$t('public.cancel'),
       type: 'warning',
       closeOnClickModal: false,
       confirmButtonClass: 'confirm-btn',
       beforeClose: (action, instance, done) => {
       // 确认按钮按下时
         if (action === 'confirm') {
            const confirmButton = document.querySelector('.confirm-btn')
            // 监听确认按钮的点击事件
            const onClickHandler = event => {
            event = event || window.event
            // enter键入detail为0,不进入done,阻止关闭;点击确认detail为1,进入done,进入then
               if (event.detail !== 0) {
                  done()
               }
            }
            // 先移除之前可能存在的点击事件处理函数
            confirmButton.removeEventListener('click', onClickHandler)
             // 再为确认按钮添加新的点击事件处理函数
            confirmButton.addEventListener('click', onClickHandler)
             onClickHandler()
           } else {
             // 其他情况,相当于取消,进入catch
             done()
            }
           }
     }).then(() => {
         this.deleteEmailTemplate(res.id)
     }).catch(() => {
        this.$message({
           type: 'info',
           message: this.$t('public.canceledDelete')
         })
     })
}

官网:MessageBox 消息弹框 | Element Plus

在beforeClose处赋值一个回调,有三个参数action操作类型 instance实例 done,调用done则关闭否则反之

然后用confirmButtonClass定义类名,查询到当前dom节点,并且监听按钮的点击事件,通过event.detail的值可以判断出是手动点击确认还是按下enter触发的,当然如果存在input select等可输入类型的表单按下回车键,可以手动在这边过滤一下;随后移除上一次关闭弹框之后的监听,随后为按钮新增监听,手动触发一次即可。
拓展:全局$confirm如何都实现呢?总不能每个$confirm都去加一遍吧。
vue2小伙伴可以使用Vue.prototype.$confirm 绑定到Vue实例

vue3小伙伴呢可以使用app.config.globalProperties全局挂载属性利用插件把confirm封装‘enter不触发确认操作’的逻辑

// confirm-plugin.js 自定义插件
// custom-confirm-plugin.js
import { ElMessageBox } from 'element-plus'

const ConfirmPlugin = {
  install(app) {
    // 添加全局方法 $confirm
    app.config.globalProperties.$confirm = function (message, title, userOptions = {}) {
      // 合并默认配置和用户自定义选项
      const defaultOptions = {
        confirmButtonClass: 'confirm-btn',
        beforeClose: (action, instance, originalDone) => {
          if (action === 'confirm') {
            const confirmButton = document.querySelector('.confirm-btn')
            const onClickHandler = event => {
              event = event || window.event

              const isInputLikeElement = target => {
                const inputTypes = ['textarea', 'input', 'select']

                return inputTypes.includes(target.tagName.toLowerCase())
              }
              if (event.detail !== 0 && !isInputLikeElement(event.target)) {
                originalDone() // 点击确认或非回车键时正常关闭
              }
            }

            confirmButton.removeEventListener('click', onClickHandler)
            confirmButton.addEventListener('click', onClickHandler)

            onClickHandler()
          } else {
            originalDone()
          }
        }
      }

      const finalOptions = { ...defaultOptions, ...userOptions }

      // 返回原生的$confirm方法调用,但使用的是合并后的选项
      return ElMessageBox.confirm(message, title, finalOptions)
    }
  }
}

export default ConfirmPlugin

// main.js 注册这个插件

import { createApp} from 'vue'
import App from './App'
import ConfirmPlugin from '@/mixin/confirmPlugin'

...
const app = createApp(App)
app.use(ConfirmPlugin)
...

//  普通页面正常使用$confirm

 this.$confirm(tip, this.$t('public.delete'), {
    confirmButtonText: this.$t('public.delete'),
    cancelButtonText: this.$t('public.cancel'),
       type: 'warning',
       closeOnClickModal: false,
     }).then(() => {
         this.deleteEmailTemplate(res.id)
     }).catch(() => {
        this.$message({
           type: 'info',
           message: this.$t('public.canceledDelete')
         })
     })
}

不过vue3不推荐使用gobalProperties,尤其是组合式api不会被所有组件自动注入,所以推荐project/inject 方式将方法注入,然后创建全局mixin再引入上面透传的方法,随后进行全局绑定$confirm
话不多说:

// confirmService.js

// confirmService.js
import { ElMessageBox } from 'element-plus'

const ConfirmService = {
  confirm(message, title, userOptions = {}) {
    const defaultOptions = {
      confirmButtonClass: 'confirm-btn',
      beforeClose: (action, instance, originalDone) => {
        if (action === 'confirm') {
          const confirmButton = document.querySelector(`.${defaultOptions.confirmButtonClass}`)
          const onClickHandler = event => {
            event = event || window.event
            const isInputLikeElement = target => {
              const inputTypes = ['textarea', 'input', 'select']
              return inputTypes.includes(target.tagName.toLowerCase())
            }
            if (event.detail !== 0 && !isInputLikeElement(event.target)) {
              originalDone() // 点击确认或非回车键时正常关闭
            }
          }
          confirmButton.removeEventListener('click', onClickHandler)
          confirmButton.addEventListener('click', onClickHandler)
          onClickHandler()
        } else {
          originalDone()
        }
      }
    }

    const finalOptions = { ...defaultOptions, ...userOptions }

    return ElMessageBox.confirm(message, title, finalOptions)
  }
}

export default ConfirmService

// mixin.js

// globalConfirmMixin.js
import { inject } from 'vue'

const globalConfirmMixin = {
  data() {
    return {
      confirmService: null
    }
  },
  mounted() {
    this.confirmService = inject('confirmService')
  },
  methods: {
    $confirm(message, title, options = {}) {
      return this.confirmService.confirm(message, title, options)
    }
  }
}

export default globalConfirmMixin

// main.js

import { createApp, provide } from 'vue'
import ConfirmService from '@/mixin/confirmService'
import GlobalConfirmMixin from '@/mixin/globalConfirmMixin'

app.provide('confirmService', ConfirmService)
app.mixin(GlobalConfirmMixin)

 /  普通页面正常使用$confirm

 this.$confirm(tip, this.$t('public.delete'), {
    confirmButtonText: this.$t('public.delete'),
    cancelButtonText: this.$t('public.cancel'),
       type: 'warning',
       closeOnClickModal: false,
     }).then(() => {
         this.deleteEmailTemplate(res.id)
     }).catch(() => {
        this.$message({
           type: 'info',
           message: this.$t('public.canceledDelete')
         })
     })
}

 大功告成!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值