为什么 Vue 渲染组件不正确?
Why does Vue render component incorrectly?
下面是一个错误示例。
重现问题:添加 3 项并删除第二项。
里面的所有内容都被正确删除了。从下面文字的渲染中可以看出这一点。但是组件显示不正确。为什么?这是一个错误吗?
我尝试使用额外的 属性 进行条件渲染,尝试覆盖对元素数组和数组内部的引用 - 没有结果。
Vue.component('selected-material', {
props: [
'value'
],
template: `
<div>
<v-autocomplete
v-model="local"
:items="materials"
item-text="name"
return-object
autocomplete="new-password"
@change="input"
/>
</div>
`,
data() {
return {
local: this.value,
materials: [{
id: 1,
name: 'mat-1',
q: 1
},
{
id: 2,
name: 'mat-2',
q: 1
},
],
};
},
methods: {
input() {
this.$emit('input', this.local);
},
},
})
Vue.component('add-board', {
props: [
'value'
],
template: `
<div>
<v-container fluid class="my-0 py-0">
<v-row class="my-0 py-0">
<v-col class="my-0 py-0">
<selected-material
v-model="local.material"
/>
</v-col>
<v-col class="my-0 py-0">
<v-text-field
class="my-0 py-0"
v-model="local.material.q"
/>
</v-col>
<v-col class="my-0 py-0">
<v-row class="my-0 py-0">
<v-col class="my-0 py-0">
<v-btn
class="my-0 py-0"
color="success"
icon
@click="append"
>
<v-icon>mdi-plus</v-icon>
</v-btn>
</v-col>
<v-col class="my-0 py-0">
<v-btn
class="my-0 py-0"
color="error"
icon
@click="remove"
>
<v-icon>mdi-minus</v-icon>
</v-btn>
</v-col>
</v-row>
</v-col>
</v-row>
</v-container>
</div>
`,
data() {
return {
local: this.value,
};
},
methods: {
input() {
this.$emit('input', this.local);
},
append() {
this.$emit('append');
},
remove() {
this.$emit('remove', this.local.id);
},
},
})
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
boards: [],
};
},
mounted() {
this.append();
},
methods: {
append() {
this.boards.push({
id: Date.now(),
material: {
id: 1,
name: 'mat-1',
q: 1
},
});
},
remove(id) {
if (this.boards.length !== 1) {
const index = this.boards.findIndex(board => board.id === id);
this.boards.splice(index, 1);
}
},
},
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Material+Icons" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
<div id="app">
<v-app>
<v-main>
<v-row v-for="(board, index) in boards" :key="index">
<v-col>
<add-board :key="index" v-model="boards[index]" @append="append" @remove="remove" />
</v-col>
</v-row>
<v-row v-for="(board, index) in boards" :key="`_${index}`">
<v-col>
{{ board.id }} | {{ board.material.q }}
</v-col>
</v-row>
</v-main>
</v-app>
</div>
UPD:
替换为ID后:
从 v-for
列表中删除项目时,如果您不希望 DOM 被重复使用,请务必使用每个项目唯一的 key
。如果您使用 index
并删除一个项目,下一个项目将采用其索引,因此 Vue 会重用已删除项目的 DOM。
使用 id
作为键,因为它似乎是唯一的:
<v-row v-for="(board, index) in boards" :key="board.id">
此外,检查 <v-text-field>
上的 v-model
,您可能打算使用 local.material.q
而不是 local.q
:
<v-text-field
class="my-0 py-0"
v-model="local.material.q"
/>
下面是一个错误示例。
重现问题:添加 3 项并删除第二项。
里面的所有内容都被正确删除了。从下面文字的渲染中可以看出这一点。但是组件显示不正确。为什么?这是一个错误吗?
我尝试使用额外的 属性 进行条件渲染,尝试覆盖对元素数组和数组内部的引用 - 没有结果。
Vue.component('selected-material', {
props: [
'value'
],
template: `
<div>
<v-autocomplete
v-model="local"
:items="materials"
item-text="name"
return-object
autocomplete="new-password"
@change="input"
/>
</div>
`,
data() {
return {
local: this.value,
materials: [{
id: 1,
name: 'mat-1',
q: 1
},
{
id: 2,
name: 'mat-2',
q: 1
},
],
};
},
methods: {
input() {
this.$emit('input', this.local);
},
},
})
Vue.component('add-board', {
props: [
'value'
],
template: `
<div>
<v-container fluid class="my-0 py-0">
<v-row class="my-0 py-0">
<v-col class="my-0 py-0">
<selected-material
v-model="local.material"
/>
</v-col>
<v-col class="my-0 py-0">
<v-text-field
class="my-0 py-0"
v-model="local.material.q"
/>
</v-col>
<v-col class="my-0 py-0">
<v-row class="my-0 py-0">
<v-col class="my-0 py-0">
<v-btn
class="my-0 py-0"
color="success"
icon
@click="append"
>
<v-icon>mdi-plus</v-icon>
</v-btn>
</v-col>
<v-col class="my-0 py-0">
<v-btn
class="my-0 py-0"
color="error"
icon
@click="remove"
>
<v-icon>mdi-minus</v-icon>
</v-btn>
</v-col>
</v-row>
</v-col>
</v-row>
</v-container>
</div>
`,
data() {
return {
local: this.value,
};
},
methods: {
input() {
this.$emit('input', this.local);
},
append() {
this.$emit('append');
},
remove() {
this.$emit('remove', this.local.id);
},
},
})
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
boards: [],
};
},
mounted() {
this.append();
},
methods: {
append() {
this.boards.push({
id: Date.now(),
material: {
id: 1,
name: 'mat-1',
q: 1
},
});
},
remove(id) {
if (this.boards.length !== 1) {
const index = this.boards.findIndex(board => board.id === id);
this.boards.splice(index, 1);
}
},
},
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Material+Icons" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
<div id="app">
<v-app>
<v-main>
<v-row v-for="(board, index) in boards" :key="index">
<v-col>
<add-board :key="index" v-model="boards[index]" @append="append" @remove="remove" />
</v-col>
</v-row>
<v-row v-for="(board, index) in boards" :key="`_${index}`">
<v-col>
{{ board.id }} | {{ board.material.q }}
</v-col>
</v-row>
</v-main>
</v-app>
</div>
UPD:
替换为ID后:
从 v-for
列表中删除项目时,如果您不希望 DOM 被重复使用,请务必使用每个项目唯一的 key
。如果您使用 index
并删除一个项目,下一个项目将采用其索引,因此 Vue 会重用已删除项目的 DOM。
使用 id
作为键,因为它似乎是唯一的:
<v-row v-for="(board, index) in boards" :key="board.id">
此外,检查 <v-text-field>
上的 v-model
,您可能打算使用 local.material.q
而不是 local.q
:
<v-text-field
class="my-0 py-0"
v-model="local.material.q"
/>