封装递归tree组件
效果
treeCom.vue组件
<template>
<div class="treeStyle">
<div
class="treeOne"
v-for="(item,inx) in treeDataNew"
:key="inx"
@click.stop.prevent="openShow(item)"
>
<div
:class="curNameId == item.id ? 'treeTitles activeStyles' : 'treeTitles'"
@click.prevent="hClickTreeItem(item)">
<i v-if="item.children && item.children.length > 0" :class="item.isOpen ? 'el-icon-arrow-down iconR' : 'el-icon-arrow-right iconR'"></i>
<i v-if="item.children && item.children.length > 0" :class="item.isOpen ? 'el-icon-folder-opened file_icon' : 'el-icon-folder file_icon'"></i>
<i v-else class="el-icon-folder file_icon"></i>
<span class="treeName">{
{
item.name }}</span>
</div>
<div v-show="item.isOpen && item.children && item.children.length > 0" class="childStyle">
<treeCom
:treeData="item.children"
:current="curNameId"
@tree-node-click="$emit('tree-node-click', $event)"/>
</div>
</div>
</div>
</template>
<script>
import treeCom from './treeCom.vue'
export default {
props: {
treeData: {
type: Array,
default: () => [],
},
current: String,
},
name: 'treeCom',
data(){
return {
treeDataNew: [],
curNameId: ''
}
},
watch: {
//监听当前点击节点的id
current: {
handler(num) {
this.curNameId = num
},
deep: true,
immediate: true
}
},
components: {
treeCom,
},
mounted(){
this.treeDataNew = this.treeData
},
methods: {
openShow(item) {
this.$nextTick(() => {
item.isOpen = !item.isOpen;
});
},
hClickTreeItem(item){
this.$emit('tree-node-click', item)
},
},
}
</script>
<style lang="less" scoped>
.treeName {
width: 118px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
position: relative;
top: 7px;
}
.treeStyle {
.treeOne,
.childStyle {
cursor: pointer;
// padding-left: 10px; // 放开,需要注释 ***** 里的代码,会出现选中border距离左边有距离的问题
}
.treeTitles {
padding-left: 15px;
font-size: 16px;
color: #000000;
box-sizing: border-box;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
}
.activeStyles {
border: #409EFF 2px solid;
border-radius: 2px;
color: #409EFF;
}
.file_icon {
margin: 8px 8px 8px 0;
}
.iconR {
margin-right: 6px;
}
// ***********************************************
.childStyle {
.treeTitles {
position: relative;
}
.file_icon {
margin-left: 29px;
}
.iconR {
position: absolute;
top: 8px;
left: 25px;
}
}
.treeStyle {
.treeStyle {
.file_icon {
margin-left: 39px;
}
}
}
// ***********************************************
}
</style>
父组件
<template>
<div class="cont_c">
<div class="cont_l">
<div class="tree">
<tree-com
:treeData="treeData"
:current="curNameId"
@tree-node-click="nodeClick"
/>
</div>
</div>
<div class="cont_r rightSty">
<div style="padding: 20px;">{
{
clickData}}</div>
</div>
</div>
</template>
<script>
import treeCom from '../model/treeCom.vue'
export default {
data(){
return {
treeData: [
{
"id": "1402903753264885762",
"isOpen": true,
"name": "一级父层",
"status": true,
"level": "一级菜单",
"parentId": "0",
"sortOrder": 7,
"children": [
{
"id": "1402904547628376065",
"isOpen": false,
"name": "123",
"status": true,
"level": "二级菜单",
"parentId": "1402903753264885762",
"sortOrder": 5,
"children": [
]
},
{
"id": "1402904663936425985",
"isOpen": false,
"name": "456",
"status": true,
"level": "二级菜单",
"parentId": "1402903753264885762",
"sortOrder": 12,
"children": [
{
"id": "1402904949253955585",
"isOpen": false,
"name": "测试1",
"status": true,
"level": "三级菜单",
"parentId": "1402904663936425985",
"sortOrder": 2,
"children": [
]
},
{
"id": "1402904920229371906",
"isOpen": false,
"name": "测试2",
"status": true,
"level": "三级菜单",
"parentId": "1402904663936425985",
"sortOrder": 10,
"children": [
]
},
{
"id": "1402904973903880194",
"isOpen": false,
"name": "测试3",
"status": true,
"level": "三级菜单",
"parentId": "1402904663936425985",
"sortOrder": 10,
"children": [
]
}
]
},
{
"id": "1402904645955444738",
"isOpen": false,
"name": "888-2",
"status": true,
"level": "二级菜单",
"parentId": "1402903753264885762",
"sortOrder": 14,
"children": [
]
},
{
"id": "1402904723365519361",
"isOpen": false,
"name": "999-3",
"status": true,
"level": "二级菜单",
"parentId": "1402903753264885762",
"sortOrder": 30,
"children": [
]
}
]
}
],
curNameId: '',
clickData: null,
}
},
components: {
treeCom,
},
mounted(){
this.curNameId = this.treeData[0].id
},
methods: {
nodeClick(val) {
this.curNameId = val.id
this.$set(val, 'curNameId', this.curNameId)
this.clickData = val;
},
},
}
</script>
<style lang="less" scoped>
.headerTit {
color: #444;
font-size: 18px;
}
.cont_header {
margin-bottom: 18px;
margin-top: 20px;
border-bottom: 1px solid #ddd;
margin-left: 0;
p {
margin-left: 20px;
}
}
.cont_c {
display: flex;
border-radius: 20px;
height: 85vh;
}
.cont_l {
width: 223px;
flex-shrink: 0;
background-color: #fff;
border-radius: 10px 0 0 10px;
}
.cont_r {
flex-grow: 1;
overflow: hidden;
background-color: #fafafa;
border-radius: 10px;
}
.rightSty {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
</style>