我在vue中有树层次结构和制表符的组合。到目前为止,我已经或多或少地开始工作了。
我需要在关闭时完全删除dom中的内容,因为我所谈论的数据足够大,如果它只是留在dom中的display:none
,它就会让浏览器瘫痪
看一下这个例子:
Vue.component('tabs', {
template: '#tabs',
data(){
return {
tabs: [],
expanded:true,
defaultExpanded:true,
activeTab: null,
hasChildren:false,
};
},
methods: {
toggle() {
this.expanded = !this.expanded;
},
activate(tab) {
if (this.activeTab) {
this.activeTab.active = false;
}
tab.active = true;
this.activeTab = tab;
},
},
mounted(){
for (i = 0; i < this.$slots.default.length; i++) {
let t = this.$slots.default[i];
if (t.componentOptions && t.componentOptions.tag == 'tab') {
this.tabs.push(t.componentInstance);
}
}
if (this.tabs.length) {
this.activeTab = this.tabs[0];
this.activeTab.active = true;
}
this.expanded = this.defaultExpanded;
},
});
Vue.component('tab', {
template: '#tab',
data() {
return {
active: false,
};
},
props: ['label'],
});
app = new Vue({
'el': '#inst',
});
<!-- templates -->
<script type="text/x-template" id="tabs">
<div @click.stop="toggle">
<h1><slot name="h" /></h1>
<div v-show="expanded" class="children">
<ul><li v-for="tab in tabs" @click.stop="activate(tab)">{{tab.label}}</li></ul>
<div style="border:1px solid #F00"><slot /></div>
</div>
</script>
<script type="text/x-template" id="tab">
<strong v-show="active"><slot /></strong>
</script>
<!-- data -->
<tabs id="inst">
<div slot="h">Woot</div>
<tab label="label">
<tabs>
<div slot="h">Weet</div>
<tab label="sub">Weetley</tab>
</tabs>
</tab>
<tab label="label2">Woot3</tab>
</tabs>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
这样可以正常使用,但是如果我将v-show
更改为v-if
以获得性能,则会丢失状态,制表符按钮会停止显示 - 基本上会有很多内容中断。
问题是,只要我将v-if
添加到tab
模板的插槽中,整个组件在关闭时就会被删除。这意味着父组件的tabs
列表是一组完全不同的对象,而不是第二次打开时显示的对象。
这意味着我无法单击标签来打开选项卡,因为在我到达选项卡时,选项卡将是不同的实例,并且每次关闭并打开父选项时,所有选项卡都将默认关闭。
我真正需要的是类似<keep-alive>
的东西 - 我可以告诉vue将组件保留在内存中而不将它们呈现给dom。但是,当我补充说,整个事情都停止了。它似乎真的不适用于插槽,只适用于单个组件。
因此。 tl; dr:在使用v-if
保持dom光线时,如何保持混合树和标签的状态?
答案 0 :(得分:2)
在Bert Evans' codepen的基础上,我创建了一个只是一个插槽的组件。我创建了一个keep-alive
包装的动态组件,is
插槽组件处于活动状态时,空白组件处于活动状态时。现在没有v-if
,当您关闭并重新打开父项时,子项中会保留状态。
console.clear();
Vue.component('keepableSlot', {
template: '#keepable-slot'
});
Vue.component('tabs', {
template: '#tabs',
data() {
return {
tabs: [],
expanded: true,
activeTab: null,
};
},
methods: {
addTab(tab) {
this.tabs.push(tab)
},
toggle() {
this.expanded = !this.expanded;
},
activate(tab) {
if (this.activeTab) {
this.activeTab.active = false;
}
tab.active = true;
this.activeTab = tab;
},
},
watch: {
expanded(newValue) {
console.log(this.$el, "expanded=", newValue);
}
}
});
Vue.component('tab', {
props: ["label"],
template: '#tab',
data() {
return {
active: false
}
},
created() {
this.$parent.$parent.addTab(this)
}
});
app = new Vue({
'el': '#inst',
});
&#13;
.clickable-tab {
background-color: cyan;
border-radius: 5px;
margin: 2px 0;
padding: 5px;
}
.toggler {
background-color: lightgray;
border-radius: 5px;
margin: 2px 0;
padding: 5px;
}
&#13;
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<script type="text/x-template" id="tabs">
<div>
<h1 class="toggler" @click.stop="toggle">
<slot name="h"></slot>
(expanded={{expanded}})
</h1>
<keep-alive>
<component :is="expanded && 'keepableSlot'">
<div class="children">
<ul>
<li class="clickable-tab" v-for="tab in tabs" @click.stop="activate(tab)">{{tab.label}}</li>
</ul>
<div>
<slot></slot>
</div>
</div>
</component>
</keep-alive>
</div>
</script>
<script type="text/x-template" id="keepable-slot">
<div>
<slot></slot>
</div>
</script>
<script type="text/x-template" id="tab">
<strong>
<component :is="active && 'keepableSlot'"><slot></slot></component>
</div>
</script>
<!-- data -->
<tabs id="inst">
<div slot="h">Woot</div>
<tab label="label">
<tabs>
<div slot="h">Weet</div>
<tab label="sub">Weetley</tab>
</tabs>
</tab>
<tab label="label2">Woot3</tab>
</tabs>
&#13;