树形数据结构实现平铺展示
后端返回的数据是树形结构要实现这种类似平铺树的结构
基本思路:取出最后两级,取出每一级的所有祖先节点

// 只获取最后两级得数据
lastLevelData (data) {
let that = this
let arr = []
data = that._.cloneDeep(data) || []
data.forEach(el => {
// el是二级
if (el.children && el.children.length > 0) {
if (el.children[0].selectAble && el.children[0].isBottomLevel) {
that.addAllCheck(el)
}
go(el)//递归
} else {
arr.push(el)
}
})
function go (item) {
let p = item
item.children.forEach(child => {
child.parent = p
if (child.children && child.children.length > 0) {
if (child.children[0].isBottomLevel) {
that.addAllCheck(child)
}
go(child)
} else {
let key = child.parent && child.parent.key // 第三级无子节点
let str = ''
if (key) {
str = key.replace('_', '')
}
if (child.isBottomLevel && str.indexOf('_') === -1) {
let deep = that._.cloneDeep(p)
deep.children = []
deep.children.push(child)
that.addAllCheck(deep) //
arr.push(deep)
} else {
arr.push(p)
}
}
})
}
let obj = {}
//去掉第一级的标签路径名
let firstlabel = [
'定制标签_',
'设备信息_',
'自然属性_',
'社会属性_',
'兴趣偏好_',
'资产信息_',
'消费信息_',
'位置信息_',
'产品功能偏好'
]
function removeFirst (str) {
firstlabel.forEach(item => {
if (str.startsWith(item)) {
str = str.replace(item, '')
return str
}
})
return str
}
arr = arr.reduce((cur, next) => {
next.fullName = removeFirst(next.fullTagName)
if (next.fullName.indexOf('_') === -1) {
next.firstLevel = true
} else {
next.firstLevel = false
}
if (!obj[next.key]) {
obj[next.key] = true
cur.push(next)
}
return cur
}, [])
arr.forEach(element => {
let result = []
let data = element
while (data.parent) {
data.parent.children = []
result.push(data.parent) // 把它父亲的label存在
data = data.parent
}
result = result.filter(obj => {
if (obj && obj.key) {
return obj
}
})
element.parent = result.reverse()
})
this.finalShowData = arr
console.log(arr)
},
祖父组件
<right-childs-tree
:treeData="finalShowData"
v-model="ids"
@checkAll-label="checkAllLabel"
@addLabelChange="getAddLabelKeys"
:addLabelDataKeys="addLabelDataKeys"
:collectDataKeys="collectDataKeys"
@collection-change="
() => {
getCollectionKeys();
}
"
></right-childs-tree>
Bus.js
//由于孙子组件采用了模版递归并有复杂的交互操作只能通过Bus的方式向祖父组件传递事件
import Vue from "vue"; export default new Vue();
父组件
<template>
<ul>
<treenode
v-for="(model, index) in treeData"
:model="model"
:key="index"
:ids="ids"
:addLabelDataKeys="addLabelDataKeys"
:collectDataKeys="collectDataKeys"
>
</treenode>
</ul>
</template>
<script>
import rightChilds from "./RightChilds.vue";
import Bus from "@/data/bus.js";
export default {
name: "Tree",
model: {
prop: "ids",
event: "change"
},
props: {
treeData: {
type: Array,
default: function() {
return [];
}
},
ids: {
type: Array,
default: function() {
return [];
}
},
collectDataKeys: {
type: Array,
default: function() {
return [];
}
},
addLabelDataKeys: {
type: Array,
default: function() {
return [];
}
}
},
components: {
treenode: rightChilds
},
created() {
let that = this;
Bus.$on("check-allData", target => {
that.$emit("checkAll-label", target);
});
Bus.$on("addLabel-change", target => {
that.$emit("addLabelChange", target);
});
Bus.$on("collectionChange", target => {
that.$emit("collection-change", target);
});
}
};
</script>
孙子组件
//模版递归
<template> <li class="tree choicenesChilds" :class="{ sub_tree_all: model.children.length == 0 ? true : false }"> <div v-if="model.children && model.children.length == 0" class="label-container"> <!-- 这里显示第一级的标签名 --> <span v-if="model.firstLevel"> <span class="parent-name">{{ model.label }}</span> </span> <span v-else class="third-label"> <span class="third-line" v-if="model.label !== '全选'">|</span> <span v-if="model.label === '全选'" class="child-name" @click.stop.prevent="allLabel(model)">{{ model.label }}</span> <span v-else> <span slot="reference" class="child-name">{{ model.label }}</span> </span> </span> </div> <div v-else class="label-container"> <ul v-if="model.parent.length > 0"> <li v-for="p in model.parent" :key="p.key" class="parent-name">// <span class="">{{ p.label }}</span> <img src="~@/assets/images/choicenes/right.png" width="12" height="12" class="direction" /> </li> <li class="parent-name"> <span slot="reference" class="">{{ model.label }}</span> </li> </ul> <span v-else> <span slot="reference" class="parent-name">{{ model.label }}</span> </span> <!-- 这里显示父节点 --> </div> <ul> <tree-node v-for="(subModel, index) in model.children" :model="subModel" :ids="ids" :key="index" ></tree-node> </ul> </li> </template> <script> import Bus from "@/data/bus.js"; import apis from "@/api/apis"; import network from "@/api/network"; import { choicenesMixin } from "@/data/choicenesTreeStructureMixin.js"; export default { name: "TreeNode", mixins: [choicenesMixin], props: { ids: { type: Array, default: function() { return []; } }, model: { type: Object, default: function() { return {}; } } }, methods: { allLabel(data) { //去掉第一个全选数据 if (data.otherBrother && data.otherBrother.length > 1) { let brother = [...data.otherBrother]; let allData = brother.splice(1); Bus.$emit("check-allData", allData); } }, addHotLabel(labelData) { Bus.$emit("addLabel-change", labelData); }, collectionChangeFunc() { Bus.$emit("collectionChange"); // 收藏后调用获取所有收藏的key }, } } }; </script> <style lang="scss" scoped="scoped"> @import "~@/styles/variables.scss"; .choicenesChilds { color: #000; height: 100%; .label-container { font-size: 14px; font-weight: 500; height: 100%; color: rgba(142, 142, 163, 1); .selectedLabelRow { background: #d1d9ff; } .el-row { margin-bottom: 0; } li { text-decoration: none; list-style: none; //去掉li前面的圆点 display: inline; //让li横向排列 } .parent-name { font-family: MicrosoftYaHei; font-size: 16px; color: #33353f; line-height: 16px; margin-top: 24px; display: inline-block; &:hover { color: $colorPrimary; cursor: pointer; } .direction { margin: 0 12px; } } .child-name { display: inline-block; font-size: 14px; color: #626574; margin-top: 16px; &:hover { color: $colorPrimary; cursor: pointer; } } .third-label { width: 100%; display: -webkit-box; -webkit-box-orient: vertical; padding-left: 16px; // -webkit-line-clamp: 4; // text-emphasis: none; // text-overflow: ellipsis; max-height: 150px; overflow: hidden; font-weight: 500; line-height: 21px; .third-line { padding: 0 16px 0 0; } } } } </style> <style lang="scss"> .popover { box-shadow: 1px 2px 13px 0px rgba(221, 237, 224, 0.35); .popover-item { cursor: pointer; padding: 5px 0; color: #bebed7; } .popover-item:hover { color: #415fff; } } .choicenesChilds { .el-card__body { padding: 0; } .el-row { margin-bottom: 20px; &:last-child { margin-bottom: 0; } } .el-col { border-radius: 4px; padding: 0; margin: 0; } } .tree { margin-top: 5px; .sub_tree_all { content: ""; display: inline-block; clear: both; .single_btn { float: left; } } } </style>
浙公网安备 33010602011771号