问题描述
问题的发生总是源于需求。所以我先描述下我的业务场景:
左右布局的页面,左侧是一列Tabs 标签页,右侧是一棵树,点击tab的每一项,右侧树的勾选状态发生变化。左侧的tab项可以动态的增加删除。特殊说明一下,右侧的树,是同一棵树,只是勾选状态不一样。
问题出现的环境背景及自己尝试过哪些方法
看到这个需求后,其实这就是典型的Tabs 标签页。点击tab标签,内容区进行切换。左侧一个tab对应右侧一棵树。
所以我这里会有2个list,一个TabList(左侧),一个TreeList(右侧).
开发思路:
左侧TabList添加一个tab,右侧TreeList添加一棵树,tab切换时,右侧树v-show去隐藏显示,但是这样的问题就是dom节点在tab不断增加的情况下也不断增加,树本来就dom节点多,所以v-show的方案就直接放弃了。那么v-if去切换,这样就可以解决了dom节点数多的问题。但是也会引入另外一个问题,就是如何保持树的状态,例如一个数,有自己的勾选状态、展开状态、滚动条的状态,虽然使用了element ui的树,可以解决勾选状态、展开状态,但是滚动状态就需要自己去维护,说不定以后还有其他状态,干脆一不做二不休,为什么不使用keep-alive方案呢?既可以解决dom节点多的问题,又可以保持状态,简直完美。就用keep-alive方案。
相关代码
这是目前的实现方案:代码是简化过的代码,为了更好的说明,删除了其他业务逻辑。
<template>
<div class="hello">
<button @click="onAdd">+</button>
<span class='num'
:class='{active:item.id==activeTab}'
@click='onShowTree(item)'
v-for="(item,index) in TabList"
v-if='!item.isDel'
:key="index">
{{item.id}}
<button @click.stop="onDel(item)">-</button>
</span>
<keep-alive>
<tree v-for="(item,index) in TabList"
v-if="item.id==activeTab"
:key='index'></tree>
</keep-alive>
</div>
</template>
<script>
import axios from "axios";
import _ from "lodash";
import tree from "./tree";
let components = {};
export default {
name: "parent-component",
components: {
tree
},
data() {
return {
activeTab: "",
TabList: []
};
},
computed: {
},
methods: {
onShowTree(item) {
this.activeTab = item.id;
},
onAdd() {
let id = this.TabList.length;
let isDel = false;
this.TabList.push({ id,isDel });
},
onDel(item) {
item.isDel = true;
}
}
};
</script>
这个方案,目前是解决了我的问题,但是却存在2个问题。
1.我需要多加一个字段(这里的isDel)用来标识是否进行了删除。有代码洁癖的人估计会有点难受。
2.被标记为isDel=true的tree组件依然缓存在内存中并未销毁。如果用户频繁操作,将在内存中占据更多空间。
那么我重新思考新的方案?怎么能让删除的tree销毁掉?sf有相关的帖子,采用了直接去操作this.$vnode.parent.componentInstance.cache;的方案,是可以解决,但是我这里还是暂时不考虑,毕竟觉得这个方案有点剑走偏锋。所以我又回到了官方的文档中,有没有可能采用动态组件(其实我上面的方案也类似动态组件,只不过组件名称都是相同的)的方案去解决呢?配合keep-alive的include的和exclude去更完美的去解决这个问题?这里有个关键点就是include的和exclude,但是看下官方关于这2个属性的描述,看到了什么?name,组件名称。
但是我的业务和上面的代码已经明确就只有一个组件就是tree组件,那么我们怎么动态去创建多个名字?动态组件,is主要是感觉组件名称去进行切换的,那么有一个最致命的问题,就是我这个组件命要怎么创建(这句话听起来有点懵吧)?
我们先来看看正常的情况
这里特殊说明一下,我使用的是单文件组件,非单文件组件的方式不再此讨论(例如这个不是在此谈论https://jsfiddle.net/jingkaiz...)
可以从截图中看到,一开始在components属性中就已经注册了可用的组件名称和对应的组件,那么此处如何才能在用户添加tab的事件中动态的给components属性添加一个新的组件?其实还是tree组件,但是要做一个深度拷贝,这样保证它保存的状态是和新创建的tab是唯一对应的。但是名字要怎么弄?思路到此,就断了,求大神帮忙