Vue $refs的正确使用方法

9

我正在尝试在我的vue组件中重新创建这个行内编辑功能。然而,可能我错了,我看到一些语法已经过时,特别是使用了v-el指令。我已经尝试更新语法如下:

new Vue({
  el: '#app',
  data: {
    numbers: [{
        val: 'one',
        edit: false
      },
      {
        val: 'two',
        edit: false
      },
      {
        val: 'three',
        edit: false
      }
    ]
  },

  methods: {
    toggleEdit: function(ev, number) {
      number.edit = !number.edit

      // Focus input field
      if (number.edit) {
        Vue.nextTick(function() {
          ev.$refs.input.focus(); // error occurs here
        })
      }
    },

    saveEdit: function(ev, number) {
      //save your changes
      this.toggleEdit(ev, number);
    }
  }
})
<div id="app">
  <template v-for="number in numbers">
        <span v-show="!number.edit"
              v-on:click="toggleEdit(this, number)">{{number.val}}</span>

        <input type="text"
               ref="input"
               v-model="number.val"
               v-show="number.edit"
               v-on:blur="saveEdit(ev, number)"> <br>
    </template>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13/dist/vue.js"></script>

然而我遇到了一系列错误...有没有建议如何正确执行此操作?

以下是错误信息:

[Vue警告]: 在nextTick中出错:"TypeError: undefined不是一个对象(评估'ev.$refs.input')"


为什么要绑定 ref?你的组件似乎没有 inputdataprop 属性。你可能只是想使用 ref="input",而不是 :ref="input" - Phil
请注意,您的JSFiddle示例正在使用Vue 0.12.15。这是正确的版本吗?如果不是,您想要使用哪个版本? - Phil
请原谅我没有粘贴正确/最新的代码,我已经更新了问题代码。 - John Durand
我想使用最新的Vue 2版本。 - John Durand
2个回答

16

从Vue.js 1.x到2.x,许多事情发生了变化。我将指导您完成必要更改:

  • v-repeat应替换为v-for
  • ref="input"代替v-el="input"
    • 由于您在v-for中使用了ref="input",因此this.$refs.input将是元素数组,而不是单个元素。
    • 要访问每个单独的元素,您需要一个索引(数组),这就是为什么应该在v-for中包含index变量的原因:v-for="(number, index) in numbers"
    • index传递给函数,而不是ev,这样您就可以稍后使用vm.$refs.input[index].focus();获取<input>s

就是这样。更改后您将得到:

new Vue({
  el: '#app',
  data: {
    numbers: [
        {
            val: 'one',
            edit: false
        },
        {   val: 'two',
            edit: false
        },
        {
            val: 'three',
            edit: false
        }
    ]
  },
  methods: {
    toggleEdit: function(index, number){
        number.edit = !number.edit;

        // Focus input field
        var vm = this;
        if (number.edit){
            Vue.nextTick(function() {
                vm.$refs.input[index].focus();
            })   
        }
    },

    saveEdit: function(index, number){
        //save your changes
        this.toggleEdit(index, number);
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13/dist/vue.js"></script>
<div id="app">
    <template v-for="(number, index) in numbers">
        <span v-show="!number.edit"
              v-on:click="toggleEdit(index, number)">{{number.val}}</span>

        <input type="text"
               ref="input"
               v-model="number.val"
               v-show="number.edit"
               v-on:blur="saveEdit(index, number)"> <br>
    </template>
</div>


3
如果你只想要功能而不是代码设计,我建议你重新设计它。我认为你想要编辑数据,而数据不应该知道它是否正在被编辑。这是组件的角色。
因此,让我们创建一个组件,让你可以使用 v-model 来编辑数据。该组件本身具有一个 span 和一个 input。如果正在编辑,则显示输入框,否则显示 span。单击开始编辑,失去焦点停止编辑。当编辑开始时,将焦点设置在输入框上。
它接受一个 value 属性。其输入元素会发出一个 input 事件来表示更改(根据 组件 v-model 规范)。

new Vue({
  el: '#app',
  data: {
    stuff: ['one', 'two', 'three']
  },
  components: {
    inlineEditor: {
      template: '#inline-editor-template',
      props: ['value'],
      data() {
        return {
          editing: false
        }
      },
      methods: {
        startEditing() {
          this.editing = true;
          this.$nextTick(() => this.$refs.input.focus());
        },
        stopEditing() {
          this.editing = false;
        }
      }
    }
  }
});
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <inline-editor v-for="item, index in stuff" v-model="stuff[index]"></inline-editor>
</div>

<template id="inline-editor-template">
  <div>
    <span @click="startEditing" v-show="!editing">{{value}}</span>
    <input ref="input" :value="value" @input="e => $emit('input', e.target.value)" @blur="stopEditing" v-show="editing">
  </div>
</template>


组件标签上的 v-for 应该有一个 key。另外,为什么不使用 v-model="item"?还有,非常好的答案 ;) - Phil
1
它应该有一个键,但它没有改变,我不想去重构来拥有一个 id:key="index" 也没有改善,虽然它隐藏了警告。至于 v-model="item",你不能在 v-for 别名上使用 v-model(参见此链接) - Roy J
这是一个非常好的替代方案! - John Durand
@RoyJ 哦,我不知道那个 v-for / v-model 的问题。谢谢! - Phil

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