Vue:如何在按钮单击时调用 .focus()

问题描述 投票:0回答:4

我昨天才开始用

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 */

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

更新:

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

javascript vue.js vuejs2 setfocus
4个回答
19
投票

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

我终于在一位高级程序员的帮助下解决了这个问题。我还能够使用其

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)
时,它返回这个数组:

enter image description here

这就是为什么代码要工作,它必须是

typeBox[0].focus()
而不是
typeBox.focus()


5
投票

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

箭头函数不绑定它自己的

this
值。

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

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

3
投票

终于解决了没有

setTimeout
的问题,感谢
window.requestAnimationFrame
(不知道为什么):

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

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


0
投票

在我的例子中,

nextTick
不起作用,因为由于某种原因,反应值(例如
visible
布尔模型)更改和子组件安装之间存在相当明显的随机延迟。我没有利用
setTimeout
,而是使用这种“动作队列”模式解决了它:

<script setup lang="ts">
import Button from './ui/button/Button.vue'

const visible = defineModel<boolean>({ default: false })

const sidebarFocus = ref<InstanceType<typeof Button> | null>(null)

const actionQueue = ref<(() => void)[]>([])

watch(visible, (value) => {
  if (value) {
    actionQueue.value.push(() => {
      if (sidebarFocus.value)
        sidebarFocus.value.$el.focus() // Don't forget the `$el`
    })
  }
})

watch(sidebarFocus, (value) => {
  if (value) {
    actionQueue.value.forEach(action => action())
    actionQueue.value = []
  }
})
</script>

<template>
  <div v-if="visible" class="my-sidebar">
    <Button ref="sidebarFocus" @click="visible = false">
      Close <!-- This button gets focused each time the sidebar opens -->
    </Button>
  </div>
</template>

基本上,

visible
的观察者将回调推送到数组,然后在按钮安装时调用该回调,并清空队列(以防止无限循环)。回调本身只是将焦点放在按钮上。

© www.soinside.com 2019 - 2024. All rights reserved.