Vue中实现回车键切换焦点的方法
几乎在所有浏览器中,都具有Tab键切换焦点的功能。
但是任性的用户强烈要求一定要有Enter键切换焦点的功能。
为了交付上线拿到钱,我们只好再一次毫无原则性的接受了客户的需求。
在上一代人中,大多都有这种操作习惯。习惯把保存成为编辑,习惯用回车替换Tab。这是受到微软excel荼毒的结果。
起初我以为这个功能很简单,无非就是把Enter键的功能转接到Tab键上面,分分钟就可以解决掉的问题。
可困难马上就出现了,我发现这条路是走不通的。
我们经常可以主动触发某个事件,比如el.click()就可以调用点击事件,或者使用dispatchEvent。但是键盘和鼠标事件却不行。
我查阅了很多资料,也做了很多尝试。最后总结出来一个结论,在浏览器中,JavaScript无法操作用户的键盘或者鼠标,这是出于安全策略的考虑。仔细想一下,如果可以用一段JavaScript脚本控制用户键盘和鼠标的话,那么用户只需要打开一个黑客网站,黑客就可以瞬间得到他想得到的一切。
所以,如果要通过除Tab键以外的其他方式来触发焦点切换,focus几乎是唯一的选择。
在原生页面中实现回车键切换焦点
项目是基于vue和element-ui做的,为了把实现思路先讲清楚,暂时把这些抛开,从原生的页面中寻找答案。
以下是一个原生的html页面。
Demo
接下来要实现通过回车键切换焦点,我把思路梳理如下:
- 监听回车键按下事件。
- 获取当前聚焦元素。
- 获取下一个要被聚焦的元素。
- 切换焦点。
思路有了,实现起来也非常简单。
1.监听回车键按下事件
在文档中添加script标签,写入如下代码。
functionenterCallback(e){ if(e.keyCode===13){ //按下回车后的逻辑 } } window.addEventListener("keydown",enterCallback);
要注意,enterCallback单独拿出来,用于注销监听事件。
监听按键事件最常用的方法就是使用事件委托,将事件绑定到window对象上。相比较给每一个元素都绑定一个事件的方式,这样做的最大好处就是节省内存空间,性能更好。
判断按下哪个键的方式有很多,比如判断e.key、e.code或者e.keyCode等方式。但绝大多数的情况下都建议使用e.keyCode。下面是一张来自网络的keyCode表。
2.获取当前聚焦元素
很容易就可以做到这一步。
常见的有两种方式。第一种是e.target,第二种是document.activeElement。这种情况下,个人更推荐使用第二种。
functionenterCallback(e){ if(e.keyCode===13){ letactiveEl=document.activeElement; } }
3.获取下一个要被聚焦的元素
这一步也比较容易。使用el.nextElementSiblingAPI即可获取。
functionenterCallback(e){ if(e.keyCode===13){ letactiveEl=document.activeElement; letnextEl=activeEl.nextElementSibling; } }
4.切换焦点
切换焦点调用focus即可实现。
functionenterCallback(e){ if(e.keyCode===13){ letactiveEl=document.activeElement; letnextEl=activeEl.nextElementSibling; nextEl&&nextEl.focus(); } }
至此一个最简单的Demo已经实现了,接下来看看项目中实际的情况。
在element-ui项目中实现回车键切换焦点
因为是使用组件开发,加上样式等因素,dom节点并不像上面写的原生Demo那么简单,实际情况是多层嵌套的。下面是实际生成的代码结构。
协议号
可以看到,如果每一个输入框都是这种类型的嵌套结构,上面的方法是无法直接解决的。因为nextElementSiblingAPI只能找到下一个兄弟元素,而在这里input明显找不到下一个兄弟元素。
思路是,通过回溯的手段朝外层寻找,直到找到一个类名包含el-form-item和el-form-item--small的祖级元素,然后再从这个祖级元素的下一个兄弟元素中寻找类名包含el-input__inner的input元素。
所以要再写两个函数,分别是寻找组件元素的findFormItem和寻找input元素的findInput。
findFormItem:
functionfindFormItem(el){ constparent=el.parentElement; if(!parent)returndocument.body; if( parent.className.includes("el-form-item")&& parent.className.includes("el-form-item--small") ){ returnparent; } returnfindFormItem(parent); }
findInput:
functionfindInput(container){ letnextEl=container.nextElementSibling; if(!nextEl)return; letinput=nextEl.querySelector("input"); while(input.id==="el-select"){ nextEl=nextEl.nextElementSibling; if(!nextEl)return; input=nextEl.querySelector("input"); } if(input.className.includes("el-input__inner"))returninput; }
有了这两个函数以后,实现回车切换焦点就非常简单了。只需要执行两行代码。
constcontainer=findFormItem(document.activeElement); findInput(container)&&findInput(container).focus();
完整的代码大概是这样的。
在methods中声明三个方法。
methods:{ addEnterListener(){ if(window.__completeEnterBind__)return; window.addEventListener("keydown",this.enterCallback); window.__completeEnterBind__=true; }, removeEnterListener(){ window.removeEventListener("keydown",this.enterCallback); window.__completeEnterBind__=false; }, enterCallback(e){ functionfindFormItem(el){ constparent=el.parentElement; if(!parent)returndocument.body; if( parent.className.includes("el-form-item")&& parent.className.includes("el-form-item--small") ){ returnparent; } returnfindFormItem(parent); } functionfindInput(container){ letnextEl=container.nextElementSibling; if(!nextEl)return; letinput=nextEl.querySelector("input"); while(input.id==="el-select"){ nextEl=nextEl.nextElementSibling; if(!nextEl)return; input=nextEl.querySelector("input"); } if(input.className.includes("el-input__inner"))returninput; } if(e.keyCode===13){ constcontainer=findFormItem(document.activeElement); findInput(container)&&findInput(container).focus(); } } }
然后在mounted中添加回车监听和在destroy中移除回车键听。
mounted(){ this.addEnterListener(); }, destroy(){ this.removeEnterListener(); },
需要注意的是,项目是多标签页的形式,表单组件可能会被渲染多次,所以通过在window对象上添加一个__completeEnterBind__字段来确保回车换行事件正确绑定。
总结
以上所述是小编给大家介绍的Vue中实现回车键切换焦点的方法,希望对大家有所帮助,也非常感谢大家对毛票票网站的支持!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。