树形数据结构实现平铺展示
后端返回的数据是树形结构要实现这种类似平铺树的结构
基本思路:取出最后两级,取出每一级的所有祖先节点
// 只获取最后两级得数据 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>