尽管使用了唯一键,但 v-for 在使用数组拼接时删除了错误的元素
v-for deletes the wrong element when using array splice despite the use of a unique key
我目前正在使用 v-for
打印出 'parties' 元素的列表,其中每个 'party' 由一个 <base-card>
表示。当我在代表 'parties' 数组的 additionalInfoList
数组上使用 splice()
并在控制台上记录输出时,我看到正确的元素已从数组中删除。然而,当我观察屏幕上的输出时,Vue 设法删除了数组的最后一个元素或列表中的相邻元素。根据各种建议和研究,我使用了独特的 :key
来帮助 Vue,但它仍然给我这个致命的错误。
BaseCardList.vue
<template>
<div>
<ul>
<base-card v-once
@add-parties="updateAdditionalInfoList"
@delete-party="deleteParty">
<template v-slot:title>
<slot></slot>
</template>
</base-card>
<base-card
v-for="(data) in additionalInfoListComputed" :key="JSON.stringify(data.id)"
ref="childComponent"
@add-parties="updateAdditionalInfoList"
@delete-party="deleteParty">
<!-- Wrapper for the `Parties Being Served` component-->
<template v-slot:title>
<slot></slot>
</template>
</base-card>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
selectedComponent: 'base-card',
additionalInfoList : [],
clearForm: false,
counter: 0
}
},
computed : {
additionalInfoListComputed(){
console.log('state changed');
return this.additionalInfoList;
}
},
methods: {
updateAdditionalInfoList(additionalInfo){
this.additionalInfoList.push(additionalInfo);
this.counter++;
console.log('The length is'+this.additionalInfoList.length);
},
deleteParty(resId){
const resIndex = this.additionalInfoList.findIndex(
res => res.id === resId
);
this.additionalInfoList.splice(resIndex, 1);
console.log('Index is '+resIndex);
console.log(this.additionalInfoList);
}
}
}
</script>
<style scoped>
ul{
align-content: left;
padding: 0
}
</style>
BaseCard.vue
<template>
--something
</template>
<script>
import { EventBus } from './bus.js';
export default {
emits:['add-parties','delete-party'],
data() {
return {
additionalInfo:
{
id: new Date().toISOString(),
fullName: '',
preAuthorize: '',
serviceAddress: ''
},
validation: {
fullNameIsValid: true,
serviceAddressIsValid: true
},
hideAddButton: false,
formIsValid: true,
addServiceButtonText: '+ Add Service Notes (Optional)',
serviceNotes: [],
showServiceNotes: false,
showDeleteButton: true,
enteredServiceNote: '', //service notes addendum
}
},
computed : {
showServiceNotex(){
if(!this.showServiceNotes){
return '+Add Service Notes (Optional)'
}else{
return '- Remove Service Notes';
}
}
},
methods: {
setServiceNotes(){
this.showServiceNotes = !this.showServiceNotes;
},
addAnotherParty(){
this.validateForm();
if(!this.formIsValid){
return;
}
let emitObj = JSON.parse(JSON.stringify(this.additionalInfo));
this.$emit('add-parties', emitObj); //event
this.hideAddButton = !this.hideAddButton;
console.log(this.hideAddButton);
},
deleteParty(){
this.$emit('delete-party', this.additionalInfo.id);
},
validateForm(){
this.formIsValid = true;
if(this.additionalInfo.fullName === ''){
this.validation.fullNameIsValid = false;
this.formIsValid = false;
}
if(this.additionalInfo.serviceAddress === ''){
this.validation.serviceAddressIsValid = false;
this.formIsValid = false;
}
},
clearValidity(input){
this.validation[input] = true;
},
clearForm(){
this.additionalInfo.fullName = '';
this.additionalInfo.serviceAddress = '';
this.additionalInfo.preAuthorize = false;
}
},
created(){
console.log('created');
console.log(this.hideAddButton);
}
}
</script>
输出画面
你应该将索引传递给删除方法deleteParty
<base-card v-for="(data,index) in additionalInfoListComputed" :key="JSON.stringify(data.id)" ref="childComponent"
@add-parties="updateAdditionalInfoList" @delete-party="deleteParty(index)">
<!-- Wrapper for the `Parties Being Served` component-->
<template v-slot:title>
<slot></slot>
</template>
</base-card>
在子组件中生成 ID 的代码可能会创建重复的 ID。在足够快的机器上,所有的 ID 都将相同:
id: new Date().toISOString()
删除它并使用真正独特的东西,比如基于 v-for
索引的东西。
我目前正在使用 v-for
打印出 'parties' 元素的列表,其中每个 'party' 由一个 <base-card>
表示。当我在代表 'parties' 数组的 additionalInfoList
数组上使用 splice()
并在控制台上记录输出时,我看到正确的元素已从数组中删除。然而,当我观察屏幕上的输出时,Vue 设法删除了数组的最后一个元素或列表中的相邻元素。根据各种建议和研究,我使用了独特的 :key
来帮助 Vue,但它仍然给我这个致命的错误。
BaseCardList.vue
<template>
<div>
<ul>
<base-card v-once
@add-parties="updateAdditionalInfoList"
@delete-party="deleteParty">
<template v-slot:title>
<slot></slot>
</template>
</base-card>
<base-card
v-for="(data) in additionalInfoListComputed" :key="JSON.stringify(data.id)"
ref="childComponent"
@add-parties="updateAdditionalInfoList"
@delete-party="deleteParty">
<!-- Wrapper for the `Parties Being Served` component-->
<template v-slot:title>
<slot></slot>
</template>
</base-card>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
selectedComponent: 'base-card',
additionalInfoList : [],
clearForm: false,
counter: 0
}
},
computed : {
additionalInfoListComputed(){
console.log('state changed');
return this.additionalInfoList;
}
},
methods: {
updateAdditionalInfoList(additionalInfo){
this.additionalInfoList.push(additionalInfo);
this.counter++;
console.log('The length is'+this.additionalInfoList.length);
},
deleteParty(resId){
const resIndex = this.additionalInfoList.findIndex(
res => res.id === resId
);
this.additionalInfoList.splice(resIndex, 1);
console.log('Index is '+resIndex);
console.log(this.additionalInfoList);
}
}
}
</script>
<style scoped>
ul{
align-content: left;
padding: 0
}
</style>
BaseCard.vue
<template>
--something
</template>
<script>
import { EventBus } from './bus.js';
export default {
emits:['add-parties','delete-party'],
data() {
return {
additionalInfo:
{
id: new Date().toISOString(),
fullName: '',
preAuthorize: '',
serviceAddress: ''
},
validation: {
fullNameIsValid: true,
serviceAddressIsValid: true
},
hideAddButton: false,
formIsValid: true,
addServiceButtonText: '+ Add Service Notes (Optional)',
serviceNotes: [],
showServiceNotes: false,
showDeleteButton: true,
enteredServiceNote: '', //service notes addendum
}
},
computed : {
showServiceNotex(){
if(!this.showServiceNotes){
return '+Add Service Notes (Optional)'
}else{
return '- Remove Service Notes';
}
}
},
methods: {
setServiceNotes(){
this.showServiceNotes = !this.showServiceNotes;
},
addAnotherParty(){
this.validateForm();
if(!this.formIsValid){
return;
}
let emitObj = JSON.parse(JSON.stringify(this.additionalInfo));
this.$emit('add-parties', emitObj); //event
this.hideAddButton = !this.hideAddButton;
console.log(this.hideAddButton);
},
deleteParty(){
this.$emit('delete-party', this.additionalInfo.id);
},
validateForm(){
this.formIsValid = true;
if(this.additionalInfo.fullName === ''){
this.validation.fullNameIsValid = false;
this.formIsValid = false;
}
if(this.additionalInfo.serviceAddress === ''){
this.validation.serviceAddressIsValid = false;
this.formIsValid = false;
}
},
clearValidity(input){
this.validation[input] = true;
},
clearForm(){
this.additionalInfo.fullName = '';
this.additionalInfo.serviceAddress = '';
this.additionalInfo.preAuthorize = false;
}
},
created(){
console.log('created');
console.log(this.hideAddButton);
}
}
</script>
输出画面
你应该将索引传递给删除方法deleteParty
<base-card v-for="(data,index) in additionalInfoListComputed" :key="JSON.stringify(data.id)" ref="childComponent"
@add-parties="updateAdditionalInfoList" @delete-party="deleteParty(index)">
<!-- Wrapper for the `Parties Being Served` component-->
<template v-slot:title>
<slot></slot>
</template>
</base-card>
在子组件中生成 ID 的代码可能会创建重复的 ID。在足够快的机器上,所有的 ID 都将相同:
id: new Date().toISOString()
删除它并使用真正独特的东西,比如基于 v-for
索引的东西。