几乎在所有浏览器中,都具有 Tab 键切换焦点的功能。

但是任性的用户强烈要求一定要有 Enter 键切换焦点的功能。

为了交付上线拿到钱,我们只好再一次毫无原则性的接受了客户的需求。

在上一代人中,大多都有这种操作习惯。习惯把保存成为编辑,习惯用回车替换 Tab。这是受到微软 excel 荼毒的结果。

起初我以为这个功能很简单,无非就是把 Enter 键的功能转接到 Tab 键上面,分分钟就可以解决掉的问题。

可困难马上就出现了,我发现这条路是走不通的。

我们经常可以主动触发某个事件,比如 el.click() 就可以调用点击事件,或者使用 dispatchEvent 。但是键盘和鼠标事件却不行。

我查阅了很多资料,也做了很多尝试。最后总结出来一个结论,在浏览器中,JavaScript 无法操作用户的键盘或者鼠标,这是出于安全策略的考虑。仔细想一下,如果可以用一段 JavaScript 脚本控制用户键盘和鼠标的话,那么用户只需要打开一个黑客网站,黑客就可以瞬间得到他想得到的一切。

所以,如果要通过除 Tab 键以外的其他方式来触发焦点切换, focus 几乎是唯一的选择。

在原生页面中实现回车键切换焦点

项目是基于 vue 和 element-ui 做的,为了把实现思路先讲清楚,暂时把这些抛开,从原生的页面中寻找答案。

以下是一个原生的 html 页面。

Demo

接下来要实现通过回车键切换焦点,我把思路梳理如下:

监听回车键按下事件。

获取当前聚焦元素。

获取下一个要被聚焦的元素。

切换焦点。

思路有了,实现起来也非常简单。

1.监听回车键按下事件

在文档中添加 script 标签,写入如下代码。

function enterCallback(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 。这种情况下,个人更推荐使用第二种。

function enterCallback(e) {

if (e.keyCode === 13) {

let activeEl = document.activeElement;

}

}

3.获取下一个要被聚焦的元素

这一步也比较容易。使用 el.nextElementSibling API 即可获取。

function enterCallback(e) {

if (e.keyCode === 13) {

let activeEl = document.activeElement;

let nextEl = activeEl.nextElementSibling;

}

}

4.切换焦点

切换焦点调用 focus 即可实现。

function enterCallback(e) {

if (e.keyCode === 13) {

let activeEl = document.activeElement;

let nextEl = activeEl.nextElementSibling;

nextEl && nextEl.focus();

}

}

至此一个最简单的 Demo 已经实现了,接下来看看项目中实际的情况。

在 element-ui 项目中实现回车键切换焦点

因为是使用组件开发,加上样式等因素,dom 节点并不像上面写的原生 Demo 那么简单,实际情况是多层嵌套的。下面是实际生成的代码结构。

class="el-form-item el-form-item--small"

style="margin-bottom: 0vh; width: 25%; display: inline-block;"

>

>协议号

>

type="text"

autocomplete="off"

id="el-input"

placeholder="未填写协议号"

class="el-input__inner"

/>

可以看到,如果每一个输入框都是这种类型的嵌套结构,上面的方法是无法直接解决的。因为 nextElementSibling API 只能找到下一个兄弟元素,而在这里 input 明显找不到下一个兄弟元素。

思路是,通过回溯的手段朝外层寻找,直到找到一个类名包含 el-form-item 和 el-form-item--small 的祖级元素,然后再从这个祖级元素的下一个兄弟元素中寻找类名包含 el-input__inner 的 input 元素。

所以要再写两个函数,分别是寻找组件元素的 findFormItem 和寻找 input 元素的 findInput 。

findFormItem:

function findFormItem(el) {

const parent = el.parentElement;

if (!parent) return document.body;

if (

parent.className.includes("el-form-item") &&

parent.className.includes("el-form-item--small")

) {

return parent;

}

return findFormItem(parent);

}

findInput:

function findInput(container) {

let nextEl = container.nextElementSibling;

if (!nextEl) return;

let input = 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")) return input;

}

有了这两个函数以后,实现回车切换焦点就非常简单了。只需要执行两行代码。

const container = 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) {

function findFormItem(el) {

const parent = el.parentElement;

if (!parent) return document.body;

if (

parent.className.includes("el-form-item") &&

parent.className.includes("el-form-item--small")

) {

return parent;

}

return findFormItem(parent);

}

function findInput(container) {

let nextEl = container.nextElementSibling;

if (!nextEl) return;

let input = 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")) return input;

}

if (e.keyCode === 13) {

const container = findFormItem(document.activeElement);

findInput(container) && findInput(container).focus();

}

}

}

然后在 mounted 中添加回车监听和在 destroy 中移除回车键听。

mounted() {

this.addEnterListener();

},

destroy() {

this.removeEnterListener();

},

需要注意的是,项目是多标签页的形式,表单组件可能会被渲染多次,所以通过在 window 对象上添加一个 __completeEnterBind__ 字段来确保回车换行事件正确绑定。

总结

以上所述是小编给大家介绍的Vue中实现回车键切换焦点的方法,希望对大家有所帮助,也非常感谢大家对脚本之家网站的支持!

vue试按钮失去焦点_Vue中实现回车键切换焦点的方法相关推荐

  1. vue获取input的属性_Vue中自动获取input焦点

    1.给input属性添加autofocus属性,缺点autofocus 在移动版 Safari 上不工作 2.Vue官网给出的解决办法 // 注册一个全局自定义指令 `v-focus` Vue.dir ...

  2. vue改变class名字_vue中动态添加class类名的方法

    vue 动态添加class类名,灵活得让你发狂,下面示例几个 动态添加类名 文字的颜色) 文字的颜色) 三元表示式(文字的颜色) 文字的颜色) 文字的颜色) 通过方法设置class类名 export ...

  3. axios请求跨域前端解决_Vue中axios跨域请求解决方法

    跨域:指的是浏览器不能执行其他网站的脚本.它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制. 所谓同源是指,域名,协议,端口均相同,浏览器执行 js 脚本时,会检查这个脚本属 ...

  4. vue接口总是请求超时_vue axios请求超时的正确处理方法

    自从使用Vue2之后,就使用官方推荐的axios的插件来调用API,在使用过程中,如果服务器或者网络不稳定掉包了, 你们该如何处理呢? 下面我给你们分享一下我的经历. 具体原因 最近公司在做一个项目, ...

  5. vue 返回滚动条顶部组件_vue中回到顶部

    1. 回到顶部,使用 scrollIntoView 方法: Element.scrollIntoView方法滚动当前元素,进入浏览器的可见区域 该方法可以接受一个布尔值作为参数.如果为true,表示元 ...

  6. vue 函数 路由跳转_vue中通过路由跳转的三种方式

    router-view 实现路由内容的地方,引入组件时写到需要引入的地方 需要注意的是,使用vue-router控制路由则必须router-view作为容器. 通过路由跳转的三种方式 1.router ...

  7. vue打印props的值_vue中props传值方法

    vue中props传值方法 1.开发环境 vue 2.电脑系统 windows10专业版 3.在使用 vue开发的过程中,我们经常会使用 props进行组件的传值,下面是我的分享,希望对你有所帮助! ...

  8. vue异步数据 报错_vue中异步请求数据,异步请求还没完成,文件就执行了就会报错,怎么解决?...

    vue中,axios异步加载数据,但是有的文件里面需要用到异步拿到的数据,数据还没拿到,文件已经执行了,这时候数据就是空,就会报错,这个问题怎么解决? 具体表现: 我这边vue项目是进入页面的时候会调 ...

  9. vue 分享微信传参_vue 中使用微信分享接口(简单实用)

    前言 开发微信小程序时,基本上都要接入微信的SDK,而微信也提供了非常多的接口供我们去完成我们想要的功能.微信分享功能常常是我们在开发中常见的需求之一,本文将围绕微信分享接口使用展开,给自己以后碰到需 ...

最新文章

  1. P1892 [BOI2003]团伙(并查集,反集)难度⭐⭐★
  2. 29岁,从不学无术到技术Leader:这几个学习资源,决定你5年后的技术提升!
  3. OpenStack Nova 高性能虚拟机之 NUMA 架构亲和
  4. 数据源架构模式之数据映射器
  5. 蓝桥杯入门 (二)
  6. @springbootapplication 注解_Spring Boot最核心的27个干货注解,你了解多少?
  7. Linux下,使用nginx+ffmpeg+video.js实现直播效果(含centos7环境配置步骤)
  8. 程序猿修仙之路--数据结构之你是否真的懂数组?
  9. ms2005 SQL Server设置改为SQL Server身份验证
  10. Lucas定理及组合数取模
  11. 深度学习02——Softmax、DNN、WideDeep Model
  12. JNA—JNI终结者
  13. Repeater的使用
  14. Bossie Awards 2015: The best open source applicati
  15. php内容管理器是什么原因,有什么好的php内容管理后台吗?打算试水接单的大三狗提问...
  16. 【java】静态代理 proxy
  17. Android 关于java.util.NoSuchElementException错误
  18. 软件测试--缺陷报告常见问题03
  19. python制作web网页实例_基于python实现简单网页服务器代码实例
  20. 实验室信息化建设助力医药研发

热门文章

  1. mysql 生成随机(数字、英文字符、汉字函数)
  2. Latex中大括号内换行显示
  3. matlab模拟夫琅禾费单缝衍射,夫琅禾费单缝衍射光强分布MATLAB分析【毕业论文】.doc...
  4. 全网最全原理讲解!2021年抓住金三银四涨薪好时机,跳槽薪资翻倍
  5. 基于Jetson Nano2GB 的 40Pin学习 GPIO 点亮LED灯笔记记录
  6. ixia测试工具的全称_[转载] IXIA网络性能测试仪
  7. 贴片电容能否直接替换,正负极是否随便接呢?
  8. 新一代的构建工具Gradle
  9. 小 C 的数学(math)
  10. SQL删除某一列的默认约束