在Vue中使用Element UI(Plus) 时,confirm处存在的问题_vue confirm
项目场景:Vue2项目中confirm自动聚焦
就以在Vue2的项目中为例子,两种组件库都有这个问题,不能说是bug,只能说是当初创建组件库和后续使用时所遇到的需求的冲突:
问题描述
由于个别原因,就通过图片展示一下:
可以看到这里的点击审批后,对弹窗做了一个设置:
this.$confirm(`请对${row.rwmc}进行审批`?\'提示信息\',{confirmButtonText:\'通过\'cancelButtonText:\'驳回\'type: \'info\',distinguishCancelAndClose:true})
前两个属性就是将其默认的确定和取消改成了通过和驳回
type就是规定的这个信息的类型distinguishCancelAndClose
作用是明确区分 “取消” 操作和 “关闭” 操作,让这两种行为触发不同的逻辑。
乍一看,好像没啥问题,但是因为我这边的收到的需求就是修改样式,当我去查看页面,点击 ‘审批’ 后,发现 通过 按钮 自动就出现了:hover
的样式,主要是悬浮样式和默认样式的区分度比较大,看着就很不协调
当时我通过 F12 去找问题,发现我只要按下了 F12 悬浮效果就消失了,这显然时焦点对焦的问题了,后来查找资料发现这就是Element UI设计之初就是这样的。
原因分析:
乍一看,好像没啥问题,但是因为我这边的收到的需求就是修改样式,当我去查看页面,点击 ‘审批’ 后,发现 通过 按钮 自动就出现了
:hover
的样式,主要是悬浮样式和默认样式的区分度比较大,看着就很不协调
当时我通过 F12 去找问题,发现我只要按下了 F12 悬浮效果就消失了,这显然时焦点对焦的问题了,后来查找资料发现这就是Element UI设计之初就是这样的。
解决方案:
有多种解决方案,可以通过源码修改,MutationObserver监听弹窗渲染,我这里给一种最简单的方法:
this.$confirm(\'这是确认提示信息\', \'提示\', { confirmButtonText: \'确定\', cancelButtonText: \'取消\'}).then(() => { // 确认后的逻辑}).catch(() => { // 取消后的逻辑});setTimeout(() => { const activeElement = document.activeElement; if (activeElement instanceof HTMLElement) { activeElement.blur(); }}, 0);
解释:
- document.activeElement
这是浏览器提供的只读属性,指向当前页面中获得焦点的元素(例如被点击的按钮、输入框等)。
在弹窗场景中,Element UI 默认会将焦点自动设置到第一个按钮(通常是 “确定” 按钮)。 - activeElement.blur()
blur() 是 DOM 元素的方法,用于移除元素的焦点。
例如,按钮失焦后,键盘的 Enter/Space 键将不再触发其点击事件,视觉上的焦点边框也会消失。
总的来说:
setTimeout 在这里的作用是:
延迟执行失焦逻辑,确保弹窗已经渲染完成。
避免焦点自动出现在弹窗按钮上,提升用户体验(例如避免误触 Enter 键提交)。
到这里还没结束,紧接着我又遇到一个问题了:
confirm给确定按钮自动加上了el-button--primary
这不是我要求的效果,原先我在element.scss
以及 variables.scss
文件中,给所有的按钮type类型都做了取消原有样式,也就是给el-button
设置了我自己的样式(需求嘛,改好看一点),但是confirm这一操作,但是我样式的修改又不对劲了。
起初我想通过::v-deep 穿透去强制样式修改
,发现好像不管用,优先级不够,总不能给所有属性都加上!important
吧
起初我想通过修改属性来达到不再添加el-button--primary
:
confirmButtonType:\'default\',cancelButtonType:\'default\'
但是这个不会覆盖原先的primary
而是给它的class
末尾加上一个el-button--default
属性
解决(有多种方式,简单说几个):
用自己的HTML
不去使用Element UI 的默认样式类
this.$confirm( \'确认删除这条数据吗?\' + \' \', \'提示\', { dangerouslyUseHTMLString: true, showClose: false, showCancelButton: false, showConfirmButton: false }).then(() => { // 确认逻辑}).catch(() => { // 取消逻辑});
直接修改 node_modules/element-ui/packages/message-box/src/main.vue
中的按钮类:
<!-- 原始代码 --><el-button size=\"small\" :class=\"[\'el-button--primary\', customClass]\" @click=\"handleClose(\'confirm\')\"> {{ confirmButtonText }}</el-button><!-- 修改为 --><el-button size=\"small\" :class=\"[customClass]\" // 移除 el-button--primary @click=\"handleClose(\'confirm\')\"> {{ confirmButtonText }}</el-button>
主要推荐的还是自己封装组件:
import { MessageBox } from \'element-ui\';export function customConfirm(message, title, options = {}) { return MessageBox({ title, message, type: \'warning\', confirmButtonText: options.confirmButtonText || \'确定\', cancelButtonText: options.cancelButtonText || \'取消\', customClass: \'custom-message-box\', // 用于样式覆盖 ...options, beforeClose: (action, instance, done) => { // 移除确认按钮的 primary 类 setTimeout(() => { const confirmButton = document.querySelector(\'.el-message-box__btns button.el-button--primary\'); if (confirmButton) { confirmButton.classList.remove(\'el-button--primary\'); confirmButton.classList.add(\'el-button--default\'); // 添加默认类 } }, 0); done(); } });}
最后的最后的最后,实在没招了,还可以改这里的源码:node_modules/elemnt-ui/lib/theme-chalk/index.scss
,在里面全局搜索你要改的属性名,然后去操作,有点蠢,但是小项目还是实用