Vue.jsでv-forディレクティブを使用するときは、ユニークな(他要素と被らない)key属性をつけるようにします。
v-forディレクティブで要素を追加する
v-forディレクティブは、配列などを反復させるディレクティブです。
ディレクティブとは? ディレクティブとは、指示や指定を与えるための記述です。Vue.jsには、属性を指定できたり、イベント発火時に実行されるコードを指定でたり、多くのディレクティブが用意されています。
inputフィールドの名前を複数定義して、それをv-forディレクティブで表示させる例です。
<div id="app">
<ul>
<li v-for="field in fields">
{{ field }}<br><input type="text" :name="field">
</li>
</ul>
</div>
new Vue({
el: '#app',
data: {
fields: ['name', 'mail', 'tel']
}
});

最初の要素を削除するメソッドを追加する
fieldsプロパティに配列でフィールドの名前を定義していますが、この配列を順番に消すメソッドを追加してみます。
<div id="app">
<ul>
<li v-for="field in fields">
{{ field }}<br><input type="text" :name="field">
</li>
</ul>
<!-- ここから追加 -->
<button @click="remove">フィールドを消す</button>
<!-- ここまで追加 -->
</div>
new Vue({
el: '#app',
data: {
fields: ['name', 'mail', 'tel']
},
// ここから追加
methods: {
remove: function(){
this.fields.shift();
}
}
// ここまで追加
});
「@click」は「v-on:click」の省略表記です。
フィールドを消すボタンをクリックすると、removeメソッドが実行されてfieldsプロパティの配列の最初の要素を消してくれます。正常に機能してるように見えますが、フィールドに値を入力した状態でremoveメソッドを実行すると、inputタグは最後の要素が消えているのがわかります。

Vue.jsはできる限り要素を再利用する
Vue.jsは要素の移動を最小限にするために、再描画するときにできる限り要素を再利用しようとします。
v-forディレクティブによってinputタグは3個生成されましたが、結果として同じものなので再描画するときは最後の要素が削られます。
つまり、要素数が3個から2個になったという判定だけで、何番目が削除されたかという判定は行われていません。
key属性をつけて反復要素に固有性をもたせる
これを回避するために、v-forディレクティブを使用するときはkey属性をつけます。
<div id="app">
<ul>
<li v-for="field in fields" :key="field"> <!-- この要素にkey属性をつける -->
{{ field }}<br><input type="text" :name="field">
</li>
</ul>
<button @click="remove">フィールドを消す</button>
</div>
3行目でliにkey属性にfruitの値を設定しています。ちなみに、「:key」は「v-bind:key」の省略表記でinputの「:name」も同じことです。
これによってliの要素がそれぞれユニークな存在となり、removeメソッドで配列の最初の要素を消したとき、inputタグを含めた最初のliが削除されます。

このような理由から、v-forディレクティブを使用するときは、各要素をユニークな存在にするためにkey属性をつけるようにします。