【问题标题】:proper use of Vue $refs正确使用 Vue $refs
【发布时间】:2018-08-09 00:03:43
【问题描述】:

我试图在我的 vue 组件中重新创建 this exact 内联编辑功能。但是,我可能错了,我看到 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 is not an object (评估'ev.$refs.input')"

【问题讨论】:

  • 为什么要绑定ref?您的组件似乎没有 input dataprop 属性。您可能只想使用ref="input" :ref="input"
  • 仅供参考,您的 JSFiddle 示例使用的是 Vue 0.12.15。那是对的吗?如果没有,你想用什么版本?
  • 请原谅我没有粘贴我正确/当前的代码,我更新了问题代码
  • 我想使用最新的 Vue 2

标签: javascript vue.js


【解决方案1】:

从 Vue.js 1.x 到 2.x 发生了很多变化。我将引导您完成您的 sn-p 中必要的更改:

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

【讨论】:

    【解决方案2】:

    如果您想要功能而不是代码设计,我建议您重新设计它。我认为你想编辑数据,数据不应该知道它是否正在被编辑。这就是组件的作用。

    所以让我们制作一个组件,让您v-model 数据。组件本身有一个跨度和一个输入。如果您正在编辑,它会显示输入,否则会显示跨度。单击开始编辑,模糊停止编辑。开始编辑时,将焦点放在输入上。

    它需要一个value 属性。它的输入元素发出一个input 事件来表示更改(根据component v-model spec

    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"?另外,很好的答案;)
    • 它应该有一个密钥,但它并没有改变,我不想为了拥有一个id 而进行重组。 :key="index" 也好不到哪里去,尽管它隐藏了警告。至于v-model="item"you can't v-model a v-for alias
    • 这是一个很好的选择!
    • @RoyJ 哦,不知道v-for / v-model 的问题。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2018-05-04
    • 2021-06-18
    • 1970-01-01
    • 2019-12-16
    • 2021-01-04
    • 1970-01-01
    • 1970-01-01
    • 2021-01-09
    相关资源
    最近更新 更多