Существует множество решений для решения этой проблемы, но давайте придерживаться 3. Варианты 2 и 3 - лучшие практики, но вариант 1 работает, и Vue был разработан для этого подхода, даже если хардкорные разработчики нахмурились, но придерживайтесь комфорта level.
Вариант 1: манипуляция DOM
Ваши данные из клика, asyn c, prop устанавливает условие для v-if или v-show и ваш Компонент показан. Примечание v-if удаляет элемент DOM, где v-show скрывает видимость, но элемент все еще находится в потоке. Если вы удалите элемент и добавите его полностью новый init, который иногда работает в вашу пользу, когда дело доходит до реактивности, но на практике старайтесь не манипулировать DOM, поскольку это всегда будет дороже, чем циклы, фильтры, карты и др. c.
<template >
<div>
<div v-for="(d, i) in getData"
:key="i">
<div v-if="d.active">
<child-one></child-one>
</div>
<div v-else-if="d.active">
<child-two></child-two>
</div>
</div>
</div>
</template>
<script>
import ChildOne from "./ChildOne";
import ChildTwo from "./ChildTwo";
export default {
components: {
ChildOne,
ChildTwo
},
data() {
return {
data: [],
}
},
computed: {
getData() {
return this.data;
},
},
mounted() {
// assume thsi woudl come from async but for now ..
this.data = [
{
id: 1,
comp: 'ChildOne',
active: false
},
{
id: 2,
comp: 'ChildTwo',
active: true
},
];
}
}
</script>
Опция 2: Vue * <component>
компонент
Всегда лучше использовать Vue встроенный компонент компонента Vue со специальным атрибутом is
: <component v-bind:is="currentTabComponent"></component>
В этом примере мы передаем слаг или какой-либо атрибут данных для активации компонента. Обратите внимание, что мы должны загружать компоненты заранее с помощью свойства components: {},
, чтобы это работало, т. Е. Оно должно быть ChildOne или ChildTwo в качестве строки slug. Это часто используется с вкладками и представлениями для управления и поддержки состояний.
Преимущество этого подхода состоит в том, что если у вас есть 3 вкладки формы, и вы вводите данные на одной и переходите к следующей, а затем обратно, состояние / данные сохраняются, в отличие от v, если все будет перерисовано / потеряно .
Vue
<template >
<div>
<component :is="comp"/>
</div>
</template>
<script>
import ChildOne from "./ChildOne";
import ChildTwo from "./ChildTwo";
export default {
components: {
ChildOne,
ChildTwo
},
props: ['slug'],
data() {
return {
comp: 'ChildOne',
}
},
methods: {
setComponent () {
// assume prop slug passed from component or router is one of the components e.g. 'ChildOne'
this.comp = this.slug;
}
},
mounted() {
this.nextTick(this.setModule())
}
}
</script>
Опция 3: Vue и компоненты Webpack Asyn c и Dynami c.
Когда речь идет о более крупных приложениях или если вы используете Vuex и Vue Route, где у вас есть Dynami c и большое количество компонентов, тогда есть ряд подходов, но я остановлюсь на одном. Подобно варианту 2, мы используем элемент компонента, но мы используем WebPack для рекурсивного поиска всех Vue файлов с ключевым словом «модуль». Затем мы загружаем их динамически / асинхронно - это означает, что они будут загружаться только при необходимости, и вы можете увидеть это в действии в сетевой консоли браузера. Это означает, что я могу динамически создавать компоненты (фабричный шаблон) и отображать их по мере необходимости. Например, это может быть, если пользователь добавляет проекты, и вам необходимо динамически создавать и настраивать представления для проектов, созданных, например, используя маршрутизатор vue, которому вы передали ему идентификатор для нового проекта, тогда вам потребуется динамически загрузить существующий компонент или построить и загрузить заводской.
Примечание: я буду использовать v-if на элементе компонента, если у меня много компонентов, и я не уверен, что они понадобятся пользователю. Я не хочу поддерживать состояние больших коллекций компонентов, потому что у меня останется память, а при большом количестве наблюдателей / наблюдений / анимаций, скорее всего, возникнут проблемы с процессором
<template >
<div>
<component :is="module" v-if="module"/>
</div>
</template>
<script>
const requireContext = require.context('./', true, /\.module\.vue$/);
const modules = requireContext.keys()
.map(file =>
[file.replace(/(.*\/(.+?)\/)|(\.module.vue$)/g, ''), requireContext(file)]
)
.reduce((components, [name, component]) => {
// console.error("components", components)
components[name] = component.default || component
return components
}, {});
export default {
data() {
return {
module: [],
}
},
props: {
slug: {
type: String,
required: true
}
},
computed: {
getData() {
return this.data;
},
},
methods: {
setModule () {
let module = this.slug;
if (!module || !modules[module]) {
module = this.defaultLayout
}
this.module = modules[module]
}
},
mounted() {
this.nextTick(this.setModule())
}
}
</script>