
问题背景
button
组件在点击时会获得焦点,如果设置了 :focus
的css样式,则在点击按钮后按钮会改变为相应的样式,直到点击其他的元素,使当前 button
失去焦点,此时按钮会回复样式。
element-plus
等组件库的 button
组件在点击时,都设计成聚焦 button
颜色变浅。如图所示:

本是组件设计者为了交互上的友好,做的特殊的精心设计。但还是有很多测试觉得这是个bug,按钮点击后,颜色应该理解还原,不能保持变色的状态。
很蛋疼,只能解决问题了。
问题分析
这个问题出现的原因,主要是组件库已经给el-button
的 :focus
预设好了 ,只要el-button
组件被点击后,处于聚焦状态,那就有显示对应的样式。所以说,要么覆写组件的:focus
样式,要么,就点击按钮的时候,写程序让其点击后立即失焦。
解决方案
1. 覆写组件样式
这种方案我没试过,网上有一些这种实现的。
看完网上的例子,我直接舍弃了这个方案。原因有三,
- 覆写样式实现相当麻烦,而且要保证你覆写的风格能跟原始的样式完全一致;
- 同时还要考虑组件的
primary
,success
,warning
等不同的类型的按钮的样式覆写; - 当你的系统是自定义按钮的颜色风格时,可能得针对你自己系统的UI风格做处理;
这样考虑下来,就很大程度的破坏了原生组件封装好的UI设计。
2. 自定义一个指令,监听按钮的 click
事件,使元素主动失焦
为什么不是监听
focus
事件?这里监听
focus
事件也是可以实现相同效果的,但是考虑到主要是为了解决button
的click
事件的交互问题,不应该扩大影像范围。像其他的交互实现的聚焦,会造成聚焦失败, 如,键盘操作聚焦,这时候用户可能会需要知道当前焦点的位置,就不应该主动失焦。
具体实现:
- 定义指令 v-blur
ts
// main.ts
import { createApp, type DirectiveBinding, type VNode } from 'vue'
import App from './App.vue'
const app = createApp(App)
const elBlur = (el: HTMLElement) => {
return () => el?.blur()
}
app.directive('blur', {
created (el: HTMLElement, binding: DirectiveBinding, vnode: VNode) {
if (vnode?.type === 'button') {
el.addEventListener('click', elBlur(el))
}
},
unmounted (el: HTMLElement) {
el.removeEventListener('click', elBlur(el))
}
})
app.mount('#app')
- 使用指令
html
<template>
<el-button type="primary" v-blur>Primary</el-button>
<el-button type="success" v-blur>Success</el-button>
<el-button type="warning" v-blur>Warning</el-button>
</template>
优势:
- 使用简单,添加一个指令即可实现;
- 灵活,就跟使用一个
el-button
一样方便,想用就用,不想用也没关系; - 必须要覆写组件逻辑, 对
element-plus
组件没有破坏性;
演示效果
