【问题标题】:Vue: How to call .focus() on button clickVue:如何在按钮单击时调用 .focus()
【发布时间】:2017-07-30 11:03:41
【问题描述】:

我昨天才开始使用vue.js 编码,不知道如何在不使用“传统”JS 方式(即document.getElementById('myTextBox').focus())的情况下“关注”文本框。

最初,我的文本框是隐藏的。我有一个“开始”按钮,当用户单击它时,会显示文本框,我想在那里设置focus,可以这么说。我已经尝试过使用ref,但无济于事(参见下面的代码)。

HTML:

<input id="typeBox" ref="typeBox" placeholder="Type here..." />

Javascript

export default {
  name: 'game',

  methods: {
    startTimer () {
      setTimeout(function () { /* .focus() won't work without this */

        /* ugly and not recommended */
        // document.getElementById('typeBox').focus()

        /* Throws the error: Cannot read property 'typeBox' of undefined */
        this.$refs.typeBox.focus()

        // ... any other options?
          // ...

      }, 1)
    }
  } /* END methods */

} /* END export default */

有人知道怎么做吗?请帮忙。

更新:

input 上添加autofocus 可以在页面加载后立即聚焦。但是在我的应用程序中,需要在不重新加载页面的情况下多次“重新聚焦”输入字段,这就是为什么我需要一种调用.focus() 的方法。

【问题讨论】:

  • 更新:一位高级开发人员刚刚帮助我解决了这个问题。我将下面的代码发布为答案,以防其他人来这里解决同样的问题。感谢所有的帮助,伙计们。

标签: javascript vue.js vuejs2 setfocus


【解决方案1】:

在这里分享解决方案以防万一有人遇到同样的问题...

在一位资深程序员的帮助下,我终于弄明白了。我还能够一路消除setTimeout,使用它的vue 版本nextTick()

正确的JS代码:

startTimer () {
    this.$nextTick(() => {

        // this won't work because `this.$refs.typeBox` returns an array
        // this.$refs.typeBox.focus()

        //this one works perfectly
        this.$refs.typeBox[0].focus()

    })
} /* END startTimer */

说明:

当我使用console.log(this.$refs.typeBox)时,它返回了这个数组:

这就是代码工作的原因,它必须是 typeBox[0].focus() 而不是 typeBox.focus()

【讨论】:

  • 可以确认我也不得不在我的工作中使用这个解决方案。使用 $nextTick 是解决这个问题的方法,忘记使用 setTimeout
  • 你的数组会不会是v-for引起的? “当使用 v-for 用于元素/组件时,注册的引用将是一个包含 DOM 节点或组件实例的数组。”
【解决方案2】:

setTimeout函数中this的值将被设置为window对象,因为它是一段时间后执行的回调函数,它已经失去了this关键字的范围,该关键字是从动态设置的调用函数的位置。

箭头函数不绑定它自己的值this

startTimer () {
  setTimeout(() => {
    this.$refs.typeBox.focus()
  }, 1)
}

startTimer () {
  const self = this;
  setTimeout(function () {
    self.$refs.typeBox.focus()
  }, 1)
}

【讨论】:

  • 谢谢,但还是不行。错误现在更改为_this.$refs.typeBox.focus is not a function。我尝试从focus() 中删除(),它没有抛出错误,但仍然无法聚焦。第二个选项也会抛出我上面提到的原始错误。
  • 谢谢,但从 $refs 中删除美元符号也没有效果。
  • 你在created钩子中调用startTimer 函数吗?如果是,则错误,因为该元素尚未放入 DOM,调用 mounted 钩子中的 startTimer 函数,DOM 将准备好并发生焦点。 @ITWitch
  • startTimer 没有任何问题。如果您还没有注意到,我将setTimeout 放在里面以“等待”元素被放置在 DOM 中。而且我已经证明使用document.getElementById 可以做到这一点,并且可以完全按照我想要的方式关注input 元素。我需要的是摆脱 document.getElementById 并将其替换为 vue.js 中的等效项
  • 你能检查一下这个小提琴吗?将this.refs 更改为this.$refs jsfiddle.net/50wL7mdz/19718 @ITWitch
【解决方案3】:

终于解决了没有setTimeout的问题,感谢window.requestAnimationFrame(不知道为什么):

startTimer () {
    window.requestAnimationFrame(() => this.$refs.typeBox.focus())
}

它甚至适用于自定义组件聚焦。

【讨论】:

    【解决方案4】:

    看到这个:

    $(function(){
      $("#my_text").hide();
    })
    
    function onClickTest(){
      $("#my_text").show();
        document.getElementById("my_text").focus();
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <input type="text" id="my_text"/>
    
        <button onclick="onClickTest()">click</button>

    【讨论】:

    • 这个问题没有用jQuery标记,设置焦点根本不需要jQuery。
    • @str 我没有使用jquery的焦点,只是使用元素来隐藏/显示字段供测试
    • 谢谢,但就像我上面提到的,我不应该使用document.getElementById,因为它在某种程度上超出了使用vue.js 的目的。
    猜你喜欢
    • 2017-09-24
    • 1970-01-01
    • 2019-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    相关资源
    最近更新 更多