我正在尝试根据用户输入将组件动态添加到 DOM。我实际上遇到了 ±200 个按钮/触发器的情况,单击时需要创建/显示childComponent
实例(这是一种信息窗口/模态(。
然后,我还需要在以后用户"关闭"组件时能够删除/隐藏它们。
我在想象这样的事情?
<template>
<div ref="container">
<button @click="createComponent(1)" />
...
<button @click="createComponent(n)" />
<childComponent ref="cc53" :num="53" v-on:kill="destroyComponent" />
...
<childComponent ref="ccn" :num="n" v-on:kill="destroyComponent"/>
</div>
</template>
<script>
import childComponent from '@/components/ChildComponent'
export default {
components: {childComponent},
methods: {
createComponent (num) {
// How do I create an instance of childComponent with prop 'num' and add it to this.$refs.container?
},
destroyComponent (vRef) {
// How do I destroy an instance of childComponent?
this.vRef.$destroy();
}
}
}
</script>
所需的可能childComponent
实例的数量是有限的、不可变的,并且在渲染之前是已知的,所以我可以循环和v-show
它们,但您的典型用户可能只需要查看几个,当然也只需要同时查看几个。
我的问题:
首先,鉴于其中有 ±200 个,仅在需要时动态创建实例是否有任何性能优势,而不是v-for
循环childComponents
,让 Vue 管理 DOM?
其次,即使对于这种特殊情况v-for
要走的路,如果可能的子组件总数未知或动态,如何处理?这是渲染函数和JSX的工作吗?
如果我理解,您想显示将:num
作为道具的相同组件的列表。
首先,你必须记住 Vue 是一个"数据驱动的应用程序",这意味着你需要将你的列表表示为array
或object
中的数据,在这种情况下,你可以使用myList
数组和v-for
循环在模板中显示你的子组件列表。
添加和删除操作必须在它自己的myList
数组上进行,一旦完成,它将自动应用于您的模板。
- 要添加新实例,只需使用
myList.push(n)
-
要删除实例,请使用
myLsit.splice(myLsit.indexOf(n), 1);
结果应如下所示:
<template>
<input v-model="inputId" />
<button @click="addItem(inputId)">Add Item</button>
<childComponent
v-for="itemId in myList"
:key="itemId"
:ref="'cc' + itemId"
:num="itemId"
@kill="removeItem(itemId)"
/>
</template>
<script>
data(){
return{
inputId : 0,
myList : []
}
},
methods:{
addItem(id){
this.myList.push(id)
},
removeItem(id){
this.myLsit.splice(this.myLsit.indexOf(id), 1)
}
}
</script>
附言 :
- 没有测试代码,如果有任何错误,请告诉我
@kill
方法必须由childComponent
发出,$emit('kill', this.num)
- 这是一个很好的教程,可以更好地了解
v-for
性能惩罚
由于 ±200 个元素的可能性有限,我非常怀疑它会导致任何性能问题,并且为了进一步微调,您可以使用v-if
而不是使用v-show
它会减少总内存占用,但如果您要不断更改项目,则会增加渲染时间。
其他方法
如果x
元素的可能性没有限制,那么它仍然v-for
包含v-if
指令的项目。
但是如果用户只能同时看到一个项目(或多个但有限的项目(,而不是v-for
,则最好直接将属性绑定到childComponent
。
例如,如果子组件是当用户单击表行的编辑按钮时应用程序将显示的模式。我们可以拥有一个模态并将表单属性绑定到它,而不是拥有x
数量的模态,每个模态都有一行的可编辑内容并显示与编辑按钮相关的模态。这种方法通常通过拥有像vuex
这样的状态管理库来实现。
最后,这是一个基于vuex
的实现,可以使用,如果用户只能同时看到一个childComponent
,它可以很容易地扩展以支持同时查看多个childComponent
。
商店.js
export Store {
state: {
childComponentVisible: false,
childComponentNumber: 0
},
mutations: {
setChildComponentNumber(state, value) {
if(typeof value !== 'number')
return false;
state.childComponentNumber = value;
},
setChildComponentVisibility(state, value) {
if(typeof value !== 'boolean')
return false;
state.childComponentVisible = value;
}
}
}
child-component.vue
<template>
<p>
{{ componentNumber }}
<span @click="close()">Close</span>
</p>
</template>
<script>
export default {
methods: {
close() {
this.$store.commit('setChildComponentVisibility', false);
}
}
computed: {
componentNumber() {
return this.$store.state.childComponentNumber;
}
}
}
</script>
list-component.vue
<template>
<div class="list-component">
<button v-for="n in [1,2,3,4,5]" @click="triggerChildComponent(n)">
{{ n }}
</button>
<childComponent v-if="childComponentVisible"/>
</div>
</template>
<script>
export default {
methods: {
triggerChildComponent(n) {
this.$store.commit('setChildComponentNumber', n);
this.$store.commit('setChildComponentVisibility', true);
}
},
computed: {
childComponentVisible() {
return this.$store.state.childComponentVisible;
}
}
}
</script>
注意:上面编写的代码只是抽象的,未经测试,您可能需要对其进行一些更改以使其适用于您自己的情况。
有关vuex
的更多信息,请在此处查看其文档。