如何手动聚焦输入

时间:2020-08-20 20:53:08

标签: html vue.js

我想复制一个通用的项目列表重命名功能,这里有一个图层列表,如果双击一个图层,它将把该图层项目更改为输入,并且该输入也将自动选中其文本。

在我的示例中,我无法通过其focus() ref <div v-for="(item, i) in items"> <div @click="changeToInput(i)" v-if="!item.input">{{item.name}}</div> <input ref="input" v-model="item.name" onfocus="select()" v-else> </div> ,因为它表示未定义。仅当将元素更改为输入后,再次单击该元素时,此方法才有效。如何设置自动对焦?

 changeToInput(i) {
      this.items[i].input = true;
      //this.$refs.input.focus()
 }
requests.post(api_url, files={'image': open(img_path, 'rb')})

下面是完整的示例:https://codesandbox.io/s/reverent-khayyam-2x8mp?file=/src/App.vue:481-573

1 个答案:

答案 0 :(得分:2)

两种解决方案:

第一个:使用v-if + this.$nextTick

v-if将在绑定表达式为true / false时插入/销毁组件,因此在当前循环中,input尚未进入Dom树。您必须使用nextTick等待下一个周期才能获取Input的Dom元素。并且this.$refs.input将是一个基于多少v-if=true的数组,因此您必须过滤掉this.items以找出正确的索引(这就是为什么我使用Array.slice和Array.filter)。

已更新this.$refs.input1的元素顺序是创建VNode的顺序。例如:单击input2-> input3-> input1,this.$refs.input1的顺序为[2,3,1],而不是[1,2,3]。

第二个:使用v-show + this.$nextTick

这将使事情变得更容易,因为v-show仅更新Dom元素的css样式,而不会从VNode树中添加/删除组件实例(Vnode)。因此this.$refs.input将始终等于this.items.length

new Vue ({
  el:'#app',
  data() {
    return {
      items1: [
        { name: "Joe", input: false },
        { name: "Sarah", input: false },
        { name: "Jeff", input: false }
      ],
      items2: [
        { name: "Joe", input: false },
        { name: "Sarah", input: false },
        { name: "Jeff", input: false }
      ],
      refSort: {}
    };
  },
  methods: {
    changeToInput1(i) {
      this.items1[i].input = true;
      let refCount = (this.$refs.input1 && this.$refs.input1.length) || 0
      refCount < this.items1.length && (this.refSort[i] = refCount)
      this.$nextTick(() => {
        // the purpose uses this.refSort is record the order of this.$refs.input (Its order is same as the creating order of Ref), you can uncomment below line to see the root cause
        //console.log(this.$refs.input1[0] && this.$refs.input1[0].value, this.$refs.input1[1] && this.$refs.input1[1].value, this.$refs.input1[2] && this.$refs.input1[2].value)
        this.$refs.input1[this.refSort[i]].focus()
      })
    },
    changeToInput2(i) {
      this.items2[i].input = true;
      this.$nextTick(() => this.$refs.input2[i].focus())
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
  <div id="app">
    <h3>Uses v-if: <p>{{items1}}</p></h3>
    <div v-for="(item, i) in items1">
      <div @click="changeToInput1(i)" v-if="!item.input">{{item.name}}</div>
      <input ref="input1" v-model="item.name" onfocus="select()" v-else>
    </div>
    <h3>Uses v-show: <p>{{items2}}</p></h3>
    <div v-for="(item, i) in items2">
      <div @click="changeToInput2(i)" v-show="!item.input">{{item.name}}</div>
      <input ref="input2" v-model="item.name" onfocus="select()" v-show="item.input">
    </div>
  </div>