Как в Vue Js отключить режим "Обновления на месте"
<component v-for="(element,key) in bloks[key_block]" :is="element" :key_block="key_block":key="key"></component>
делаю цикл компонентов, цикл нормально отображается, но при попытке удалить один из элементов цикла, удаляется последний, а не выбранный. Если циклить просто html код то эту проблему можно обойти просто добавив :key, но при цикле компонентов это не работает, подскажите пожалуйста как быть?
Ответы (2 шт):
При манипуляциях с массивами следуйте рекомендациям в руководстве, а именно:
- используйте методы изменения массива, которые
vueдополняет(оборачивает) системой реактивности, чтобы запускать обновления представления (push, pop, shift, unshift, splice, sort, reverse). - Обратите внимание, на особенности отслеживания изменений массива, а именно следует учитывая, что
vueне может отследить изменения в массиве, если вы совершаете прямую установку элемента по индексу или явно изменяете длину массива.
Полезные ссылки:
Вам достаточно при манипуляциях с данными из массива, явно задавать индекс или другое свойство объекта, по которому вы сможете идентифицировать объект из массива и удалить его.
И чтобы vue вел себя более предсказуемо при обновлении представлений и рендеринге, используйте v-for с v-bind:key
Приведу пример, может будет вам полезен:
Vue.component('Test', {
props: ['title'],
template: `
<div>Компонент - {{ title }}</div>
`
})
new Vue({
el: '#app',
data: {
components: [{
id: 1,
name: 'Test',
title: 'component 1'
},
{
id: 2,
name: 'Test',
title: 'component 2'
},
]
},
computed: {
allIds() {
return this.components.map(x => x.id)
}
},
methods: {
removeComponent(id) {
const index = this.components.findIndex(x => x.id === id)
this.components.splice(index, 1)
},
addComponent() {
const id = this.allIds.length ? Math.max(...this.allIds) + 1 : 1
this.components.push({
id,
title: `component ${id}`,
name: 'Test'
})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<template v-for="element in components">
<component :is="element.name" :key="element.id" :title="element.title"></component>
<button @click="removeComponent(element.id)">удалить {{ element.id }} компонент</button>
</template>
<hr>
<button @click="addComponent">+ компонент</button>
</div>
И еще пример с использованием vue3 (обратите внимание, 2 и 3 версии во много отличаются. Все отличия и правила миграции вы можете просмотреть в Миграция с vue2 ):
const ob = {
data() {
return {
components: [{
id: 1,
name: 'element-link',
title: 'test'
}]
}
},
computed: {
allIds() {
return this.components.map(x => x.id)
}
},
methods: {
removeComponent(id) {
const index = this.components.findIndex(x => x.id === id)
this.components.splice(index, 1)
},
addComponent() {
const id = this.allIds.length ? Math.max(...this.allIds) + 1 : 1
this.components.push({
id,
title: `component ${id}`,
name: 'element-link'
})
}
}
};
const app = Vue.createApp(ob);
app.component('element-link', {
props: ['title'],
template: `
<div>Компонент - {{ title }} <input type="text" :value="title"></div>
`
})
app.mount('#app');
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
<template v-for="element in components" :key="element.id">
<component :is="element.name" :title="element.title"></component>
<button @click="removeComponent(element.id)">удалить {{ element.id }} компонент</button>
</template>
<hr>
<button @click="addComponent">+ компонент</button>
</div>
</body>
</html>
пробую, по примеру, но увы
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://unpkg.com/vue@next" ></script>
</head>
<body>
<div id="app">
<template v-for="element in components">
<component :is="element.name" :key="element.id" :title="element.title"></component>
<button @click="removeComponent(element.id)">удалить {{ element.id }} компонент</button>
</template>
<hr>
<button @click="addComponent">+ компонент</button>
</div>
</body>
</html>
<script>
const ob = {
data () { return {
components: [{
id: 1,
name: 'element-link',
title: 'test' }]
} },
el: '#app',
computed: {
allIds() {
return this.components.map(x => x.id)
}
},
methods: {
removeComponent(id) {
const index = this.components.findIndex(x => x.id === id)
this.components.splice(index, 1)
},
addComponent() {
const id = this.allIds.length ? Math.max(...this.allIds) + 1 : 1
this.components.push({
id,
title: `component ${id}`,
name: 'test'
})
}
}
};
const app = Vue.createApp(ob);
const test = app.component('test', {
props: ['title'],
template: `
<div>Компонент - {{ title }} <input type="text"></div>
`
})
app.mount('body');
</script>