vue的自定义树形列表组件(及数据格式转换)

 
  • 组件定义

子组件:

<template>
<div>
<!-- <h5>{{temp.tital}}</h5> -->
<el-button class="filter-item" style="margin-left: 1px;" size="small" type="primary" >{{temp.tital}}</el-button>
<el-input
size="small"
placeholder="输入关键字过滤分类"
v-model="filterText">
</el-input>
 

 

<el-tree
class="filter-tree"
:data="treeData"
:props="defaultProps"
:node-key="id"
default-expand-all
:filter-node-method="filterNode"
ref="tree2"
@node-click="sendData"
>
</el-tree>
</div>
</template>

 

<script>
export default {
watch: {
filterText(val) {
this.$refs.tree2.filter(val);
}
},

 

methods: {
filterNode(value, data) {
if (!value) return true;
return data.name.indexOf(value) !== -1;
},
setTreeData(datass){//接收父组件的参数
this.temp.tital = datass.tital
this.treeData = datass;
},
sendData(obj, node, data){//向父组件发送参数
this.$emit("sendTreeData", obj)//"sendTreeData"这是父组件引用时定义的
 

 

}
},

 

data() {
return {
temp:{
tital:"哈哈哈"
},
filterText: '',
data2: [{//这是tree型数据格式
id: 1,
label: '一级 1',
children: [{
id: 4,
label: '二级 1-1',
children: [{
id: 9,
label: '三级 1-1-1'
}, {
id: 10,
label: '三级 1-1-2'
}]
}]
}, {
id: 2,
label: '一级 2',
children: [{
id: 5,
label: '二级 2-1'
}, {
id: 6,
label: '二级 2-2'
}]
}, {
id: 3,
label: '一级 3',
children: [{
id: 7,
label: '二级 3-1'
}, {
id: 8,
label: '二级 3-2'
}]
}],
treeData:[],
defaultProps: {
children: 'children',
label: 'name'

 

}
};
}
};
</script>
 
父组件调用子组件
<Mytreetable ref="mytreedata" v-model="temp.icon" @sendTreeData="sendTreeObj" />
 
import Mytreetable from '@/components/MyTreeTable/index'
 
export default {
name: 'ComplexTable',
components: { Mytreetable },
 
//向子组件传递数据
this.$refs.mytreedata.setTreeData(treesss);
 
  • 以下内容为普通扁平化格式转换成树形对象的方法
  • 其中list的格式为
  • [
    {
    "id": 100,
    "pId": 0,
    "name": "科技",
    "title": "科技",
    "checked": false,
    "open": false,
    "nocheck": false
    },
    {
    "id": 101,
    "pId": 100,
    "name": "深圳总公司",
    "title": "深圳总公司",
    "checked": false,
    "open": false,
    "nocheck": false
    },
    {
    "id": 102,
    "pId": 100,
    "name": "长沙分公司",
    "title": "长沙分公司",
    "checked": false,
    "open": false,
    "nocheck": false
    },
    {
    "id": 103,
    "pId": 101,
    "name": "研发部门",
    "title": "研发部门",
    "checked": false,
    "open": false,
    "nocheck": false
    },
    {
    "id": 104,
    "pId": 101,
    "name": "市场部门",
    "title": "市场部门",
    "checked": false,
    "open": false,
    "nocheck": false
    },
    {
    "id": 105,
    "pId": 101,
    "name": "测试部门",
    "title": "测试部门",
    "checked": false,
    "open": false,
    "nocheck": false
    },
    {
    "id": 106,
    "pId": 101,
    "name": "财务部门",
    "title": "财务部门",
    "checked": false,
    "open": false,
    "nocheck": false
    },
    {
    "id": 107,
    "pId": 101,
    "name": "运维部门",
    "title": "运维部门",
    "checked": false,
    "open": false,
    "nocheck": false
    },
    {
    "id": 108,
    "pId": 102,
    "name": "市场部门",
    "title": "市场部门",
    "checked": false,
    "open": false,
    "nocheck": false
    },
    {
    "id": 109,
    "pId": 102,
    "name": "财务部门",
    "title": "财务部门",
    "checked": false,
    "open": false,
    "nocheck": false
    }
    ]

  • buildTree(list){
    let pidStr = 'pId';
    let idStr = 'id';
    let childrenStr = 'children';

    let listOjb = {}; // 用来储存{key: obj}格式的对象
    let treeList = []; // 用来储存最终树形结构数据的数组

    // 将数据变换成{key: obj}格式,方便下面处理数据
    for (let i = 0; i < list.length; i++) {
    listOjb[list[i][idStr]] = list[i]
    }

    for (let j = 0; j < list.length; j++) {
    // 判断父级是否存在
    let haveParent = listOjb[list[j][pidStr]]
    if (haveParent) {
    // 如果有没有父级children字段,就创建一个children字段
    !haveParent[childrenStr] && (haveParent[childrenStr] = [])
    // 在父级里插入子项
    haveParent[childrenStr].push(list[j])
    } else {
    // 如果没有父级直接插入到最外层
    treeList.push(list[j])
    }
    }
    return treeList
    },
 
 
另一种扁平化转树形格式的转换方式(据说效率极高,有兴趣的可以试试)
 

实现算法buildTree

算法思想:

先将数组中的每一个节点放到temp对象中(创建map)
即数组中有{id: '2-3', parent_id: '2',...}这样一个节点,需要将他放到temp中变成 '2-3': {id: '2-3', parent_id: '2',...}这种JSON结构
直接遍历整个temp对象,通过这句代码   temp[temp[i].parent_id].children[temp[i].id] = temp[i];   将当前子节点与父节点建立连接。是因为我们保证了父节点一定在子节点前,那么当子节点出现的时候就直接可以用temp[temp[i].parent_id]来查找到父节点这个时候先父节点的children对象中添加一个引用即可。
/**
* 将一维的扁平数组转换为多层级对象
* @param {[type]} list 一维数组,数组中每一个元素需包含id和parent_id两个属性
* @return {[type]} tree 多层级树状结构
*/
function buildTree(list){
let temp = {};
let tree = {};
for(let i in list){
temp[list[i].id] = list[i];
}
for(let i in temp){
if(temp[i].parent_id) {
if(!temp[temp[i].parent_id].children) {
temp[temp[i].parent_id].children = new Object();
}
temp[temp[i].parent_id].children[temp[i].id] = temp[i];
} else {
tree[temp[i].id] = temp[i];
}
}
return tree;
}
测试结果:

可以看到函数成功地构建了多级的树状结构

 

 

这个算法的效率是极高的,比多重for循环来的好得多。

 

 

 

 

以下是测试数据,用时只需5毫秒左右:


var menu_list = [{
id: '1',
menu_name: '设置',
menu_url: 'setting',
parent_id: 0
}, {
id: '1-1',
menu_name: '权限设置',
menu_url: 'setting.permission',
parent_id: '1'
}, {
id: '1-1-1',
menu_name: '用户管理列表',
menu_url: 'setting.permission.user_list',
parent_id: '1-1'
}, {
id: '1-1-2',
menu_name: '用户管理新增',
menu_url: 'setting.permission.user_add',
parent_id: '1-1'
}, {
id: '1-1-3',
menu_name: '角色管理列表',
menu_url: 'setting.permission.role_list',
parent_id: '1-1'
}, {
id: '1-1-4',
menu_name: '角色管理新增',
menu_url: 'setting.permission.role_add',
parent_id: '1-1'
}, {
id: '1-2',
menu_name: '菜单设置',
menu_url: 'setting.menu',
parent_id: '1'
}, {
id: '1-2-1',
menu_name: '菜单列表',
menu_url: 'setting.menu.menu_list',
parent_id: '1-2'
}, {
id: '1-2-2',
menu_name: '菜单添加',
menu_url: 'setting.menu.menu_add',
parent_id: '1-2'
}, {
id: '2',
menu_name: '订单',
menu_url: 'order',
parent_id: 0
}, {
id: '2-1',
menu_name: '报单审核',
menu_url: 'order.orderreview',
parent_id: '2'
}, {
id: '2-2',
menu_name: '退款管理',
menu_url: 'order.refundmanagement',
parent_id: '2'
}, {
id: '2-3',
menu_name: '实物订单',
menu_url: 'order.realorder',
parent_id: '2'
}, {
id: '2-1-1',
menu_name: '全部报单',
menu_url: 'order.orderreview.all',
parent_id: '2-1'
}, {
id: '2-2-1',
menu_name: '所有记录',
menu_url: 'order.refundmanagement.all',
parent_id: '2-2'
}, {
id: '2-2-2',
menu_name: '待处理',
menu_url: 'order.refundmanagement.wait',
parent_id: '2-2'
}, {
id: '2-2-3',
menu_name: '退款原因',
menu_url: 'order.refundmanagement.result',
parent_id: '2-2'
}, {
id: '2-3-1',
menu_name: '实物订单管理',
menu_url: 'order.realorder.list',
parent_id: '2-3'
}, {
id: '3',
menu_name: '商品',
menu_url: 'commodity',
parent_id: 0
}, {
id: '3-1',
menu_name: '分类管理',
menu_url: 'commodity.classifieldmanagement',
parent_id: '3'
}, {
id: '3-1-1',
menu_name: '管理',
menu_url: 'commodity.classifieldmanagement.management',
parent_id: '3-1'
}, {
id: '3-1-2',
menu_name: '编辑或新增',
menu_url: 'commodity.classifieldmanagement.edit',
parent_id: '3-1'
}, {
id: '3-2',
menu_name: '品牌管理',
menu_url: 'commodity.brandmanagement',
parent_id: '3'
}, {
id: '3-2-1',
menu_name: '管理',
menu_url: 'commodity.brandmanagement.management',
parent_id: '3-2'
}, {
id: '3-2-2',
menu_name: '编辑或新增',
menu_url: 'commodity.brandmanagement.edit',
parent_id: '3-2'
}, {
id: '3-3',
menu_name: '商品管理',
menu_url: 'commodity.commoditymanagement',
parent_id: '3'
}, {
id: '3-3-1',
menu_name: '管理',
menu_url: 'commodity.commoditymanagement.management',
parent_id: '3-3'
}, {
id: '3-3-2',
menu_name: '编辑或新增',
menu_url: 'commodity.commoditymanagement.edit',
parent_id: '3-3'
}, {
id: '3-4',
menu_name: '类型管理',
menu_url: 'commodity.typeManagement',
parent_id: '3'
}, {
id: '3-4-1',
menu_name: '管理',
menu_url: 'commodity.typeManagement.management',
parent_id: '3-4'
}, {
id: '3-4-2',
menu_name: '编辑或新增',
menu_url: 'commodity.typeManagement.edit',
parent_id: '3-4'
}]

 
 
 
 
 
 
posted @ 2019-07-16 18:10  源l  阅读(8317)  评论(0编辑  收藏  举报