首页 >> js开发 >> jsVue中实现回车键切换焦点的方法js大全
jsVue中实现回车键切换焦点的方法js大全
发布时间: 2021年1月13日 | 浏览:
| 分类:js开发
几乎在所有浏览器中,都具有 Tab 键切换焦点的功能。但是任性的用户强烈要求一定要有 Enter 键切换焦点的功能。为了交付上线拿到钱,我们只好再一次毫无原则性的接受了客户的需求。在上一代人中,大多都有这种操作习惯。习惯把保存成为编辑,习惯用回车替换 Tab。这是受到微软 excel 荼毒的结果。起初我以为这个功能很简单,无非就是把 Enter 键的功能转接到 Tab 键上面,分分钟就可以解决掉的问题。可困难马上就出现了,我发现这条路是走不通的。我们经常可以主动触发某个事件,比如 el.click() 就可以调用点击事件,或者使用 dispatchEvent 。但是键盘和鼠标事件却不行。el.click()dispatchEvent我查阅了很多资料,也做了很多尝试。最后总结出来一个结论,在浏览器中,JavaScript 无法操作用户的键盘或者鼠标,这是出于安全策略的考虑。仔细想一下,如果可以用一段 JavaScript 脚本控制用户键盘和鼠标的话,那么用户只需要打开一个黑客网站,黑客就可以瞬间得到他想得到的一切。所以,如果要通过除 Tab 键以外的其他方式来触发焦点切换, focus 几乎是唯一的选择。focus在原生页面中实现回车键切换焦点项目是基于 vue 和 element-ui 做的,为了把实现思路先讲清楚,暂时把这些抛开,从原生的页面中寻找答案。以下是一个原生的 html 页面。
Demo
Demo
接下来要实现通过回车键切换焦点,我把思路梳理如下:
监听回车键按下事件。
获取当前聚焦元素。
获取下一个要被聚焦的元素。
切换焦点。
监听回车键按下事件。获取当前聚焦元素。获取下一个要被聚焦的元素。切换焦点。思路有了,实现起来也非常简单。1.监听回车键按下事件在文档中添加 script 标签,写入如下代码。
function enterCallback(e) {
if (e.keyCode === 13) {
// 按下回车后的逻辑
}
}
window.addEventListener("keydown", enterCallback);
function enterCallback(e) {
if (e.keyCode === 13) {
// 按下回车后的逻辑
}
}
window.addEventListener("keydown", enterCallback);要注意, enterCallback 单独拿出来,用于注销监听事件。enterCallback监听按键事件最常用的方法就是使用事件委托,将事件绑定到 window 对象上。相比较给每一个元素都绑定一个事件的方式,这样做的最大好处就是节省内存空间,性能更好。window判断按下哪个键的方式有很多,比如判断 e.key 、 e.code 或者 e.keyCode 等方式。但绝大多数的情况下都建议使用 e.keyCode 。下面是一张来自网络的 keyCode 表。e.keye.codee.keyCodee.keyCodekeyCode2.获取当前聚焦元素很容易就可以做到这一步。常见的有两种方式。第一种是 e.target ,第二种是 document.activeElement 。这种情况下,个人更推荐使用第二种。e.targetdocument.activeElement
function enterCallback(e) {
if (e.keyCode === 13) {
let activeEl = document.activeElement;
}
}
function enterCallback(e) {
if (e.keyCode === 13) {
let activeEl = document.activeElement;
}
}3.获取下一个要被聚焦的元素这一步也比较容易。使用 el.nextElementSibling API 即可获取。el.nextElementSibling
function enterCallback(e) {
if (e.keyCode === 13) {
let activeEl = document.activeElement;
let nextEl = activeEl.nextElementSibling;
}
}
function enterCallback(e) {
if (e.keyCode === 13) {
let activeEl = document.activeElement;
let nextEl = activeEl.nextElementSibling;
}
}4.切换焦点切换焦点调用 focus 即可实现。focus
function enterCallback(e) {
if (e.keyCode === 13) {
let activeEl = document.activeElement;
let nextEl = activeEl.nextElementSibling;
nextEl && nextEl.focus();
}
}
function enterCallback(e) {
if (e.keyCode === 13) {
let activeEl = document.activeElement;
let nextEl = activeEl.nextElementSibling;
nextEl && nextEl.focus();
}
}至此一个最简单的 Demo 已经实现了,接下来看看项目中实际的情况。在 element-ui 项目中实现回车键切换焦点在 element-ui 项目中实现回车键切换焦点因为是使用组件开发,加上样式等因素,dom 节点并不像上面写的原生 Demo 那么简单,实际情况是多层嵌套的。下面是实际生成的代码结构。
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 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;
}
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();
const container = findFormItem(document.activeElement);
findInput(container) && findInput(container).focus();完整的代码大概是这样的。在 methods 中声明三个方法。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();
}
}
}
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 中移除回车键听。mounteddestroy
mounted() {
this.addEnterListener();
},
destroy() {
this.removeEnterListener();
},
mounted() {
this.addEnterListener();
},
destroy() {
this.removeEnterListener();
},需要注意的是,项目是多标签页的形式,表单组件可能会被渲染多次,所以通过在 window 对象上添加一个 __completeEnterBind__ 字段来确保回车换行事件正确绑定。__completeEnterBind__总结总结总结以上所述是小编给大家介绍的Vue中实现回车键切换焦点的方法,希望对大家有所帮助,也非常感谢大家对网站的支持!
接下来要实现通过回车键切换焦点,我把思路梳理如下:
监听回车键按下事件。
获取当前聚焦元素。
获取下一个要被聚焦的元素。
切换焦点。
监听回车键按下事件。获取当前聚焦元素。获取下一个要被聚焦的元素。切换焦点。思路有了,实现起来也非常简单。1.监听回车键按下事件在文档中添加 script 标签,写入如下代码。
function enterCallback(e) {
if (e.keyCode === 13) {
// 按下回车后的逻辑
}
}
window.addEventListener("keydown", enterCallback);
function enterCallback(e) {
if (e.keyCode === 13) {
// 按下回车后的逻辑
}
}
window.addEventListener("keydown", enterCallback);要注意, enterCallback 单独拿出来,用于注销监听事件。enterCallback监听按键事件最常用的方法就是使用事件委托,将事件绑定到 window 对象上。相比较给每一个元素都绑定一个事件的方式,这样做的最大好处就是节省内存空间,性能更好。window判断按下哪个键的方式有很多,比如判断 e.key 、 e.code 或者 e.keyCode 等方式。但绝大多数的情况下都建议使用 e.keyCode 。下面是一张来自网络的 keyCode 表。e.keye.codee.keyCodee.keyCodekeyCode2.获取当前聚焦元素很容易就可以做到这一步。常见的有两种方式。第一种是 e.target ,第二种是 document.activeElement 。这种情况下,个人更推荐使用第二种。e.targetdocument.activeElement
function enterCallback(e) {
if (e.keyCode === 13) {
let activeEl = document.activeElement;
}
}
function enterCallback(e) {
if (e.keyCode === 13) {
let activeEl = document.activeElement;
}
}3.获取下一个要被聚焦的元素这一步也比较容易。使用 el.nextElementSibling API 即可获取。el.nextElementSibling
function enterCallback(e) {
if (e.keyCode === 13) {
let activeEl = document.activeElement;
let nextEl = activeEl.nextElementSibling;
}
}
function enterCallback(e) {
if (e.keyCode === 13) {
let activeEl = document.activeElement;
let nextEl = activeEl.nextElementSibling;
}
}4.切换焦点切换焦点调用 focus 即可实现。focus
function enterCallback(e) {
if (e.keyCode === 13) {
let activeEl = document.activeElement;
let nextEl = activeEl.nextElementSibling;
nextEl && nextEl.focus();
}
}
function enterCallback(e) {
if (e.keyCode === 13) {
let activeEl = document.activeElement;
let nextEl = activeEl.nextElementSibling;
nextEl && nextEl.focus();
}
}至此一个最简单的 Demo 已经实现了,接下来看看项目中实际的情况。在 element-ui 项目中实现回车键切换焦点在 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"
/>
style="margin-bottom: 0vh; width: 25%; display: inline-block;"
>
>
type="text"
autocomplete="off"
id="el-input"
placeholder="未填写协议号"
class="el-input__inner"
/>
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 明显找不到下一个兄弟元素。nextElementSibling思路是,通过回溯的手段朝外层寻找,直到找到一个类名包含 el-form-item 和 el-form-item--small 的祖级元素,然后再从这个祖级元素的下一个兄弟元素中寻找类名包含 el-input__inner 的 input 元素。el-form-itemel-form-item--smallel-input__inner所以要再写两个函数,分别是寻找组件元素的 findFormItem 和寻找 input 元素的 findInput 。findFormItemfindInputfindFormItem:style="margin-bottom: 0vh; width: 25%; display: inline-block;"
>
>
type="text"
autocomplete="off"
id="el-input"
placeholder="未填写协议号"
class="el-input__inner"
/>
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 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;
}
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();
const container = findFormItem(document.activeElement);
findInput(container) && findInput(container).focus();完整的代码大概是这样的。在 methods 中声明三个方法。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();
}
}
}
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 中移除回车键听。mounteddestroy
mounted() {
this.addEnterListener();
},
destroy() {
this.removeEnterListener();
},
mounted() {
this.addEnterListener();
},
destroy() {
this.removeEnterListener();
},需要注意的是,项目是多标签页的形式,表单组件可能会被渲染多次,所以通过在 window 对象上添加一个 __completeEnterBind__ 字段来确保回车换行事件正确绑定。__completeEnterBind__总结总结总结以上所述是小编给大家介绍的Vue中实现回车键切换焦点的方法,希望对大家有所帮助,也非常感谢大家对网站的支持!