Vue JS 在按下 Enter 键后聚焦到下一个输入框

27

我有两个输入框,想要在用户按下回车键时从第一个输入框切换到第二个。 我尝试了使用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

我不知道答案,但请尝试这个v-on:keyup.enter="this.nextSibling.focus()" - Robiseb
感谢您的帮助!结果是 build.js:15333 未捕获的类型错误:无法读取未定义的 'focus' 属性 - Ivan Borshchov
你的第二个输入框有一个ID吗?<input id="XX" ...>。尝试添加一个并更改此行 v-on:keyup.enter="document.getElementById('XX').focus()" - Robiseb
如果我能在Vue的点击处理程序中执行原生JS,我可以使用document.getElementById('next_id').focus();,但是它会再次出现build.js:11079 [Vue warn]: Property or method "getElementById" is not defined on the instance but referenced during render - Ivan Borshchov
8个回答

34

你可以尝试像这样做:

<input v-on:keyup.enter="$event.target.nextElementSibling.focus()" type="text">

JSfiddle 示例

更新

如果目标元素在 form 元素内,且下一个 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

的翻译是:

JavaScript

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();
    }
  }
})

JSFiddle 示例


1
谢谢 - 那个jsfiddle不再工作,因为Vue的加载方式已经改变。这个修订版可以使用:https://jsfiddle.net/dyq08v0p/ - adrian
有没有办法找到下一个表单元素,即使它不是DOM中的兄弟节点? - 30thh
1
@30thh 我已更新我的答案来涵盖此情况。 - yurzui

12

this的答案之后,我认为使用$refs API是一种更清晰的替代方案。

使用$refs API可以让您以更简单的方式定位元素,而无需遍历DOM。

示例


这不再执行所期望的行为。 - 22289d

3
经过一些测试,它正在运行。
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>

是的,谢谢。我几分钟前意识到将代码移动到方法中可以解决问题。 - Ivan Borshchov

2

试试这个:

<input ref="email" /> 
this.$refs.email.focus()

2
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>

欢迎来到Stack Overflow!请不要只回答源代码。尝试提供一个关于你的解决方案如何工作的好描述。请参阅:如何撰写好的答案?。谢谢。 - sɐunıɔןɐqɐp

1
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>

1

虽然我喜欢指令的答案,因为它可以与其他元素(样式包装等)内部的输入一起使用,但我发现对于出现和消失的元素来说有点不够灵活,特别是如果它们根据其他字段出现和消失。 它还做了一些其他的事情。

相反,我编写了以下两个不同的指令。按照以下方式在您的HTML中使用它们:

<form v-forcusNextOnEnter v-focusFirstOnLoad>
...
</form>

使用以下方式在Vue对象(或mixin中)定义它们:

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();
                    }
                });
            },
        },
    },

当按下回车键时,它会查找当前输入在输入列表中的索引,验证它是否可以提高,并将焦点放在下一个元素上。

主要区别:长度和索引是在单击时计算的,使其更适合于字段添加/删除;不需要额外的事件来更改缓存变量。

缺点是,这将运行速度稍慢/更加密集,但考虑到它基于UI交互...


-1

<input type="text" @keyup.enter="$event.target.nextElementSibling.focus() />


1
虽然这段代码可能解决了问题,但是包括解释它如何以及为什么解决了问题将有助于提高您的帖子质量,并可能导致更多的赞。请记住,您正在回答未来读者的问题,而不仅仅是现在提问的人。请[编辑]您的答案以添加解释并指出适用的限制和假设。 - Yunnosch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接