树形数据结构实现平铺展示

后端返回的数据是树形结构要实现这种类似平铺树的结构

基本思路:取出最后两级,取出每一级的所有祖先节点

 // 只获取最后两级得数据
    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>

  

posted on 2020-03-21 18:49  ihuangqing  阅读(3222)  评论(1编辑  收藏  举报