方案1
创建一个hooks直接全局引用,然后在需要使用的界面中的按钮上绑定search-button样式,这样监听回车事件之后再去找class为search-button上的click事件,直接调用就可以模拟回车搜索功能
import { onMounted, onActivated, onDeactivated, onBeforeUnmount } from "vue";
export const useKeyEnter = () => {
let mounted = false
let removed = false
let handleKeyDown = (event: any) => {
if (event.keyCode === 13) {
event.preventDefault();
event.stopPropagation();
let dom: any = document.querySelector('.search-button');
if (dom) {
dom.click();
}
}
}
onMounted(() => {
if (!mounted) {
mounted = true
document.addEventListener('keydown', handleKeyDown)
}
})
onBeforeUnmount(() => {
if (!removed) {
removed = true
document.removeEventListener('keydown', handleKeyDown)
}
})
}
但这样做有两个缺点
- 范围太广只要页面上有键盘操作就会执行
- 会和已有的键盘回车事件发生冲突
方案2
使用a-form包裹表单,然后在a-form上添加回车事件即可,这样做的好处是不会影响到别的页面。
<a-form @keypress.enter="handleSearch">
...
</a-form>
但是测试之后发现还是有些bug,比如form表单中如果没有a-input,并不会触发回车事件,可见a-form内部应该是监听了input的回车事件,好吧,既然没有input那我们人为插入一个input,然后再把它隐藏不就行了,于是就有了如下代码:
<a-form @keypress.enter="handleSearch">
...
<a-input style="width:0;padding:0;border:none;opacity:0"/>
</a-form>
但真这样简单可就好了,使用完发现并没有什么卵用,好吧排查了一段时间发现只有input聚焦才会触发enter,那么问题来了怎么才能让input一直聚焦?
<a-form @keypress.enter="handleSearch">
...
<a-input ref="aInputRef" @blur=e=>e.focus() style="width:0;padding:0;border:none;opacity:0"/>
</a-form>
onMounted(()=>{
unref(aInputRef).focus()
})
逻辑就是开始聚焦,blur之后也执行focus方法即可,好了大功告成,接下来就是每个页面复制粘贴即可,但是思来想去总感觉这种方式很low,有没有更简化的方法?那当然是有的,当我想到要插入一个input的时候,自定义指令这颗种子就早已在我心中生根发芽了
方案3
上文说到a-form中只有input才能触发键盘事件,那既然我们已经插入了input是不是连a-form也不需要了,直接封装一个指令插入到按钮的父节点即可
import { createVNode, render } from "vue";
import { Input } from 'ant-design-vue';
const vEnter = {
mounted(el, binding) {
let handleKeyPress = (e) => {
if (e.keyCode === 13) {
binding.value()
}
}
// 虚拟dom节点
let vdom = createVNode(Input, { autofocus: true, onKeypress: handleKeyPress, onBlur: (e) => e.target.focus(), style: { padding: 0, width: 0, opacity: 0, border: 'none' } })
// 真实节点
let container = (document as any).createElement('div');
container.style.height = 0
// 将虚拟dom挂载到真实节点
container && render(vdom, container);
if (el.hideInputContainer) {
if (el.hideInputContainer.parentNode === el) {
return
}
}
el.appendChild(container)
el.hideInputContainer = container
},
// 注销
unmounted(el) {
if (el.hideInputContainer) {
if (el.hideInputContainer.parentNode) {
el.hideInputContainer.parentNode.removeChild(el.hideInputContainer);
}
}
}
}
export const setupEnterDirective = (app: any) => {
app.directive('enter', vEnter);
};
好了,这样注册完指令后页面上就变成了
<div v-enter="search">
...
</div>
简洁的一比,怎么看怎么顺心