Vue.js将焦点放在输入框上。

30

HTML

->

超文本标记语言

<span :style="{ display : displayTitle }" @dblclick="showInput()">
  {{ node.title }}
</span>
<input :style="{ display : displayTitleInput }" type="text" 
       @blur="hideInput1" @keydown="hideInput2" 
       @input="changeTitle(node.id , $event.target.value)" 
       :value="node.title">

JavaScript

data() {
  return {
      displayTitle: "inline-block",
      displayTitleInput: "none"
    };
},
showInput() {
    this.displayTitle = "none"
    this.displayTitleInput = "inline-block"
},
hideInput1() {
   this.displayTitle = "inline-block"
   this.displayTitleInput = "none"
},
hideInput2(event) {
    if (event.keyCode === 13) {
        this.hideInput1()
    }
},

我是一名初学的日本网页开发者。我的英语不太好,对不起。

HTML 在 "v-for" (v-for="node in list") 中。

双击文本时,它会变成 <input>

我希望它出现时能够聚焦到输入框。

我尝试了这个方法,但它没有起作用。

HTML

<span :style="{ display : displayTitle }" @dblclick="showInput(node.id)">
  {{ node.title }}
</span>
<input :ref='"input_" + node.id' :style="{display:displayTitleInput}" type="text" 
       @blur="hideInput1" @keydown="hideInput2" 
       @input="changeTitle(node.id , $event.target.value)" 
       :value="node.title">
JS
showInput(id) {
    this.displayTitle = "none"
    this.displayTitleInput = "inline-block"

    this.$nextTick(this.$refs["input_" + id][0].focus())
},

控制台没有报错,但是没有起作用。


非常感谢您的评论。您的意思是像这样吗? this.$nextTick(this.$refs["input_" + id].focus()) - Kuru
未捕获的类型错误:this.$refs[("input_" + t)].focus 不是一个函数 在 VueComponent.showInput (sl-vue-tree.js?c536:8) 在 dblclick (sl-vue-tree.js?c536:8) 在 invoker (vue.runtime.esm.js?2b0e:2023) 在 HTMLSpanElement.fn._withTask.fn._withTask (vue.runtime.esm.js?2b0e:1822) - Kuru
我遇到了这个错误(T_T)。 - Kuru
抱歉,我之前关于删除 [0] 的说法是错误的。由于某种原因,$refs 属性是一个数组。 - Phil
5个回答

34

你的主要问题是$nextTick需要一个回调函数,但你正在执行

this.$refs["input_" + id][0].focus()

立即操作。您可以使用

this.$nextTick(() => {
  this.$refs["input_" + id][0].focus()
})

然而,我认为你会遇到进一步的问题,你的代码可以变得更简单。

一个问题是,由于你的样式规则,当双击任何节点输入时,所有节点输入都会变为可见。

相反,你可以在node或者另一个对象上存储一个"editing"标记。

以下是一个示例,简化了你的代码...

  1. 使用v-for循环内使用时,ref的类似数组的特性和
  2. 在你的@keydown事件绑定上使用enter修饰符

new Vue({
  el: '#app',
  data: {
    list: [
      {id: 1, title: 'Node #1'},
      {id: 2, title: 'Node #2'}
    ],
    editing: {}
  },
  methods: {
    showInput(id, index) {
      this.$set(this.editing, id, true)
      
      this.$nextTick(() => {
        this.$refs.input[index].focus()
      })
    },
    hideInput(id) {
      this.editing[id] = false
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<ul id="app">
  <li v-for="(node, index) in list">
    <span v-show="!editing[node.id]" @dblclick="showInput(node.id, index)">
      {{ node.title }}
    </span>
    <input v-show="editing[node.id]" type="text"
           ref="input" :value="node.title"
           @blur="hideInput(node.id)" @keydown.enter="hideInput(node.id)">
  </li>
</ul>


哦我的天啊!!!非常感谢你!!!你真是个天才。我以前从未使用过这个.$set。非常专业! - Kuru
@nichika 不客气。this.$setVue.set 是一样的。你需要使用它来实现响应式,因为最初的 editing 没有属性,所以 Vue 无法自然地检测到新属性。请参阅 https://vuejs.org/v2/guide/reactivity.html。 - Phil

4
您使用this.$nextTick();的方式是不正确的。您应该向它传递一个回调函数。
this.$nextTick(function () {
    this.$refs["input_" + id].focus()
})

https://jsfiddle.net/un65e9oc/7/


不过,我并不确定你是如何使用数组访问的,因为我注意到$refs是一个对象,其中的键是引用名称。

[编辑:感谢@Phil的评论,上面已经很清楚了。]


以上是您问题的正确解决方案。由于您已经得到了答案,我将添加其他内容。

你看到这种行为的原因是因为当你在showInput()方法中更改文本框的可见性时,你在$refs中持有的引用没有被更新。所以当你调用this.$refs["input_" + id].focus();时,它实际上是在尝试设置焦点在一个隐藏的元素上(因为当前引用未更新)。

这就是为什么你需要调用$nextTick()来更新它。但如果你想要一个快速解决你的问题,而不调用$nextTick(),你可以手动更新它,像这样:

this.displayTitleInput = "inline-block"
this.$refs["input_" + id].style.display = this.displayTitleInput

this.$refs["input_" + id].focus();

这也可以起作用 :) 希望有所帮助!!

请参见此处的注释:“当在具有v-for的元素/组件上使用时,注册的引用将是一个包含DOM节点或组件实例的数组。” - Phil
是的,那个也让我有点困惑 :) - Phil
哦!!!非常感谢!!!在显示后放置焦点!我明白了。你很聪明!!! - Kuru
@Phil 是的,我现在注意到了数组。如果您没有使用v-for,它似乎会将引用保存在对象中。但是,恐怕您关于this的评论似乎不正确。这里完全可以正常工作。https://jsfiddle.net/un65e9oc/7/ - Nimeshka Srimal
1
当然。Vue将$nextTickcontext参数默认设置为当前的Vue实例。 - Phil

3
< p > autofocus 属性就是你的朋友:


<input type="text" autofocus />

(注意:移动Safari不支持自动对焦)从Vue文档中。 - Zhivko Zhelev
3
很遗憾,在SPA路由起作用时,它变得更加脆弱,而且只会触发一次。(如果你通过vue路由到另一个页面,最终回到这里,它无法设置焦点。)ref=...和.focus()已经通过测试,但我还没有在iOS上测试过这个。 - xander

3
如果您想在单击某个元素后设置焦点并使用Vue JS显示具有设置焦点的输入文本框。
directives: {
  focus: {
    // directive definition
    inserted: function (el) {
      el.focus()
    }
  }
}

并使用自定义指令。如果您需要它在单击时工作,则设置为点击

directives: {
  click: {
    // directive definition
    inserted: function (el) {
      el.focus()
    }
  }
}

并使用它

<input v-focus> or <input v-click>

enter code here

0

当我们验证表单并希望动态设置每个字段的焦点时,这对我很有效。

           this.$validator.validateAll("FORM_NAME").then(valid => {

                var errors = this.$validator.errors;

                if (valid) {
                    console.log('All Fields are valid')
                } else {
                    const errorFieldName = this.$validator.errors.items[0].field;
                    console.log(errorFieldName);
                    this.$refs[errorFieldName].focus();
                }

            });

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