Vue JS 将下一个输入集中在 enter 上
Vue JS focus next input on enter
我有 2 个输入,希望在用户按 Enter 时将焦点从第一个切换到第二个。
我尝试将 jQuery 与 Vue 混合使用,因为我找不到任何函数来关注 Vue 文档中的某些内容:
<input v-on:keyup.enter="$(':focus').next('input').focus()"
...>
<input ...>
但是在输入时我在控制台中看到错误:
build.js:11079 [Vue warn]: Property or method "$" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option. (found in anonymous component - use the "name" option for better debugging messages.)warn @ build.js:11079has @ build.js:9011keyup @ build.js:15333(anonymous function) @ build.js:10111
build.js:15333 Uncaught TypeError: $ is not a function
经过一些测试,它正在工作
new Vue({
el:'#app',
methods: {
nextPlease: function (event) {
document.getElementById('input2').focus();
}
}
});
<script src="https://vuejs.org/js/vue.js"></script>
<div id='app'>
<input type="text" v-on:keyup.enter="nextPlease">
<input id="input2" type="text">
</div>
您可以尝试这样的操作:
<input v-on:keyup.enter="$event.target.nextElementSibling.focus()" type="text">
更新
如果目标元素在 form
元素内并且下一个表单元素不是真正的兄弟元素,那么您可以执行以下操作:
html
<form id="app">
<p>{{ message }}</p>
<input v-on:keyup.enter="goNext($event.target)" type="text">
<div>
<input type="text">
</div>
</form>
js
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
focusNext(elem) {
const currentIndex = Array.from(elem.form.elements).indexOf(elem);
elem.form.elements.item(
currentIndex < elem.form.elements.length - 1 ?
currentIndex + 1 :
0
).focus();
}
}
})
在我看来,@zurzui 的跟进是使用 $refs
API (https://vuejs.org/v2/api/#vm-refs) 的更清洁的替代方案。
使用 $refs
API,可以让您以更简单的方式定位元素,而无需遍历 DOM。
Example: https://jsfiddle.net/xjdujke7/1/
directives: {
focusNextOnEnter: {
inserted: function (el,binding,vnode) {
let length = vnode.elm.length;
vnode.elm[0].focus();
let index = 0;
el.addEventListener("keyup",(ev) => {
if (ev.keyCode === 13 && index<length-1) {
index++;
vnode.elm[index].focus();
}
});
for (let i = 0;i<length-1;i++) {
vnode.elm[i].onfocus = (function(i) {
return function () {
index = i;
}
})(i);
}
}
}
}
// 使用它
<el-form v-focusNextOnEnter>
...
</el-form>
虽然我喜欢指令的答案,因为它与其他元素(样式包装器等)中的输入一起工作,但我发现它对于来来去去的元素有点不灵活,尤其是当它们根据其他领域。它还做了更多的事情。
相反,我将以下两个不同的指令放在一起。根据:
在您的 HTML 中使用它们
<form v-forcusNextOnEnter v-focusFirstOnLoad>
...
</form>
在您的 Vue 对象上(或在混入中)定义它们:
directives: {
focusFirstOnLoad: {
inserted(el, binding, vnode) {
vnode.elm[0].focus();
},
},
focusNextOnEnter: {
inserted(el, binding, vnode) {
el.addEventListener('keyup', (ev) => {
let index = [...vnode.elm.elements].indexOf(ev.target);
if (ev.keyCode === 13 && index < vnode.elm.length - 1) {
vnode.elm[index + 1].focus();
}
});
},
},
},
按下回车键时,它会在输入列表中查找当前输入的索引,验证它是否可以上移,然后聚焦下一个元素。
主要区别:长度和索引在点击时计算,更适合字段addition/removal;更改缓存变量不需要额外的事件。
不利的一面是,与 运行 相比,这会有点 slower/more 密集,但考虑到它基于 UI 互动...
Vue.js 的指令是满足此要求的良好做法。
定义一个全局指令:
Vue.directive('focusNextOnEnter', {
inserted: function (el, binding, vnode) {
el.addEventListener('keyup', (ev) => {
if (ev.keyCode === 13) {
if (binding.value) {
vnode.context.$refs[binding.value].focus()
return
}
if (!el.form) {
return
}
const inputElements = Array.from(el.form.querySelectorAll('input:not([disabled]):not([readonly])'))
const currentIndex = inputElements.indexOf(el)
inputElements[currentIndex < inputElements.length - 1 ? currentIndex + 1 : 0].focus()
}
})
}
})
注意:我们应该排除禁用和只读输入。
用法:
<form>
<input type="text" v-focus-next-on-enter></input>
<!-- readonly or disabled inputs would be skipped -->
<input type="text" v-focus-next-on-enter readonly></input>
<input type="text" v-focus-next-on-enter disabled></input>
<!-- skip the next and focus on the specified input -->
<input type="text" v-focus-next-on-enter='`theLastInput`'></input>
<input type="text" v-focus-next-on-enter></input>
<input type="text" v-focus-next-on-enter ref="theLastInput"></input>
</form>
我有 2 个输入,希望在用户按 Enter 时将焦点从第一个切换到第二个。 我尝试将 jQuery 与 Vue 混合使用,因为我找不到任何函数来关注 Vue 文档中的某些内容:
<input v-on:keyup.enter="$(':focus').next('input').focus()"
...>
<input ...>
但是在输入时我在控制台中看到错误:
build.js:11079 [Vue warn]: Property or method "$" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option. (found in anonymous component - use the "name" option for better debugging messages.)warn @ build.js:11079has @ build.js:9011keyup @ build.js:15333(anonymous function) @ build.js:10111
build.js:15333 Uncaught TypeError: $ is not a function
经过一些测试,它正在工作
new Vue({
el:'#app',
methods: {
nextPlease: function (event) {
document.getElementById('input2').focus();
}
}
});
<script src="https://vuejs.org/js/vue.js"></script>
<div id='app'>
<input type="text" v-on:keyup.enter="nextPlease">
<input id="input2" type="text">
</div>
您可以尝试这样的操作:
<input v-on:keyup.enter="$event.target.nextElementSibling.focus()" type="text">
更新
如果目标元素在 form
元素内并且下一个表单元素不是真正的兄弟元素,那么您可以执行以下操作:
html
<form id="app">
<p>{{ message }}</p>
<input v-on:keyup.enter="goNext($event.target)" type="text">
<div>
<input type="text">
</div>
</form>
js
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
focusNext(elem) {
const currentIndex = Array.from(elem.form.elements).indexOf(elem);
elem.form.elements.item(
currentIndex < elem.form.elements.length - 1 ?
currentIndex + 1 :
0
).focus();
}
}
})
在我看来,@zurzui 的跟进是使用 $refs
API (https://vuejs.org/v2/api/#vm-refs) 的更清洁的替代方案。
使用 $refs
API,可以让您以更简单的方式定位元素,而无需遍历 DOM。
Example: https://jsfiddle.net/xjdujke7/1/
directives: {
focusNextOnEnter: {
inserted: function (el,binding,vnode) {
let length = vnode.elm.length;
vnode.elm[0].focus();
let index = 0;
el.addEventListener("keyup",(ev) => {
if (ev.keyCode === 13 && index<length-1) {
index++;
vnode.elm[index].focus();
}
});
for (let i = 0;i<length-1;i++) {
vnode.elm[i].onfocus = (function(i) {
return function () {
index = i;
}
})(i);
}
}
}
}
// 使用它
<el-form v-focusNextOnEnter>
...
</el-form>
虽然我喜欢指令的答案,因为它与其他元素(样式包装器等)中的输入一起工作,但我发现它对于来来去去的元素有点不灵活,尤其是当它们根据其他领域。它还做了更多的事情。
相反,我将以下两个不同的指令放在一起。根据:
在您的 HTML 中使用它们<form v-forcusNextOnEnter v-focusFirstOnLoad>
...
</form>
在您的 Vue 对象上(或在混入中)定义它们:
directives: {
focusFirstOnLoad: {
inserted(el, binding, vnode) {
vnode.elm[0].focus();
},
},
focusNextOnEnter: {
inserted(el, binding, vnode) {
el.addEventListener('keyup', (ev) => {
let index = [...vnode.elm.elements].indexOf(ev.target);
if (ev.keyCode === 13 && index < vnode.elm.length - 1) {
vnode.elm[index + 1].focus();
}
});
},
},
},
按下回车键时,它会在输入列表中查找当前输入的索引,验证它是否可以上移,然后聚焦下一个元素。
主要区别:长度和索引在点击时计算,更适合字段addition/removal;更改缓存变量不需要额外的事件。
不利的一面是,与 运行 相比,这会有点 slower/more 密集,但考虑到它基于 UI 互动...
Vue.js 的指令是满足此要求的良好做法。
定义一个全局指令:
Vue.directive('focusNextOnEnter', {
inserted: function (el, binding, vnode) {
el.addEventListener('keyup', (ev) => {
if (ev.keyCode === 13) {
if (binding.value) {
vnode.context.$refs[binding.value].focus()
return
}
if (!el.form) {
return
}
const inputElements = Array.from(el.form.querySelectorAll('input:not([disabled]):not([readonly])'))
const currentIndex = inputElements.indexOf(el)
inputElements[currentIndex < inputElements.length - 1 ? currentIndex + 1 : 0].focus()
}
})
}
})
注意:我们应该排除禁用和只读输入。
用法:
<form>
<input type="text" v-focus-next-on-enter></input>
<!-- readonly or disabled inputs would be skipped -->
<input type="text" v-focus-next-on-enter readonly></input>
<input type="text" v-focus-next-on-enter disabled></input>
<!-- skip the next and focus on the specified input -->
<input type="text" v-focus-next-on-enter='`theLastInput`'></input>
<input type="text" v-focus-next-on-enter></input>
<input type="text" v-focus-next-on-enter ref="theLastInput"></input>
</form>