proper use of Vue $refs

Many things changed from Vue.js 1.x to 2.x. I will walk you through the changes necessary in that snippet of yours:

  • v-repeat should be v-for
  • Replace v-el="input" with ref="input"
    • Since you are using ref="input" inside a v-for, then this.$refs.input will be an array of elements, not a single element.
    • To access each single element, you will need an index (for the array), that's why you should include the index variable in the v-for: v-for="(number, index) in numbers"
    • Pass the index instead of the ev to the functions, so you can get the<input>s later using vm.$refs.input[index].focus();

And that's pretty much it. After changes you'll get:

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/[email protected]/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>

If you want the functionality and not the code design, I'd recommend you redesign it. I think you want to edit data, and the data shouldn't have to know whether it's being edited. That is the role of a component.

So let's make a component that lets you v-model data. The component itself has a span and an input. If you're editing, it shows the input, otherwise, the span. Click starts editing, blur stops editing. When editing starts, set focus on the input.

It takes a value prop. Its input element emits an input event to signal changes (per 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>