树目录、vue树目录
在前端实现树目录,首先我们要想想好数据结构,分单级与多级两种情况如图所示:

json数据
{ "code": "00000", "data": [ { "uniq": "chap2022012113252715", "type": "0", "cname": "米国8", "parent_uniq": "root", "file_type": "", "file_uniq": "", "knowledge_point": "米国", "introduction": "米国", "created_time": "2022-01-21 13:25:27", "children": [] }, { "uniq": "chap2022012113260216", "type": "0", "cname": "米国18", "parent_uniq": "root", "file_type": "", "file_uniq": "", "knowledge_point": "米国", "introduction": "米国", "created_time": "2022-01-21 13:26:02", "children": [] }, { "uniq": "chap2022012113261017", "type": "0", "cname": "乌拉", "parent_uniq": "root", "file_type": "", "file_uniq": "", "knowledge_point": "乌拉", "introduction": "乌拉", "created_time": "2022-01-21 13:26:10", "children": [ { "uniq": "chap2022012113265020", "type": "0", "cname": "2", "parent_uniq": "chap2022012113261017", "file_type": "", "file_uniq": "", "knowledge_point": "28", "introduction": "2", "created_time": "2022-01-21 13:26:50", "children": [ { "uniq": "chap2022012113294121", "type": "0", "cname": "8", "parent_uniq": "chap2022012113265020", "file_type": "", "file_uniq": "", "knowledge_point": "8", "introduction": "8", "created_time": "2022-01-21 13:29:41", "children": [] }, { "uniq": "chap2022012113303222", "type": "0", "cname": "9", "parent_uniq": "chap2022012113265020", "file_type": "", "file_uniq": "", "knowledge_point": "9", "introduction": "9", "created_time": "2022-01-21 13:30:32", "children": [ { "uniq": "chap2022012113323824", "type": "0", "cname": "88", "parent_uniq": "chap2022012113303222", "file_type": "", "file_uniq": "", "knowledge_point": "8", "introduction": "8", "created_time": "2022-01-21 13:32:38", "children": [] } ] }, { "uniq": "chap2022012113304323", "type": "0", "cname": "7", "parent_uniq": "chap2022012113265020", "file_type": "", "file_uniq": "", "knowledge_point": "7", "introduction": "7", "created_time": "2022-01-21 13:30:43", "children": [ { "uniq": "chap2022012113332225", "type": "0", "cname": "6", "parent_uniq": "chap2022012113304323", "file_type": "", "file_uniq": "", "knowledge_point": "6", "introduction": "6", "created_time": "2022-01-21 13:33:22", "children": [ { "uniq": "chap2022012113332826", "type": "0", "cname": "5", "parent_uniq": "chap2022012113332225", "file_type": "", "file_uniq": "", "knowledge_point": "5", "introduction": "5", "created_time": "2022-01-21 13:33:28", "children": [] } ] } ] }, { "uniq": "file2113295507", "type": "1", "cname": "西溪碧桂园.pdf", "parent_uniq": "chap2022012113265020", "file_type": "1", "file_uniq": "0038654742", "knowledge_point": "88", "introduction": "", "created_time": "2022-01-21 13:29:54", "children": [] } ] }, { "uniq": "file2113330308", "type": "1", "cname": "朱飞-评估表-", "parent_uniq": "chap2022012113261017", "file_type": "0", "file_uniq": "0038654743", "knowledge_point": "8", "introduction": "", "created_time": "2022-01-21 13:33:03", "children": [] } ] } ], "msg": "接口调用成功" }
children是我们判断单级还是多级的字段
梳理好业务及数据结构,在动手写代码前我们要考虑代码的逻辑复杂度、维护性、可读性等等,
在树目录这个需求中。1)、我们用vue来开发按照以往开发习惯写一堆Dom结构,在Dom中需要写许多v-if判断,代码可读性不高,维护性不高
2)、如果你用过react或了解果vue3.0或在vue2.0用过jsx,jsx是做复杂业务的首选
总上此需求采用jsx作为子组件完成树目录的业务开发
代码如下:
父级:
<template> <!-- 知识库 --> <div class="box"> <a-row class="simpleImage" v-if="visited"> <a-empty :image="simpleImage" /> </a-row> <a-row class="main_box" v-if="!visited"> <a-col span='7' class="main left_box"> <div class="catalogue">目录</div>
// 树目录
<div class="a_table"> <s-tree ref='s_tree' :dataSource="orgTree" :search="true" @click="handleClick" @add="handleAdd" @defaultTitleClick="defaultTitleClick "> </s-tree> </div> </a-col> </a-row> </div> </template>
<script> import { Empty } from 'ant-design-vue' import { query_knowledge_base_catalogue } from '@/api/factory' import STree from '@/components/ZF/menuTree.jsx' export default { name: 'Knowledge', components: { STree // pdf }, data () { return { visited: false, orgTree: [], openKeys: [] } }, beforeCreate () { this.simpleImage = Empty.PRESENTED_IMAGE_SIMPLE }, created () { }, watch: {}, mounted () { this.base_catalogue() }, methods: { base_catalogue () { const params = {} query_knowledge_base_catalogue(params).then(res => { if (res.code === '00000') { // console.log(res) this.orgTree = res.data this.openKeys.push(res.data[0].uniq) // 默认展示第一项 this.$refs.s_tree.openKeys(this.openKeys) } else { this.$message.error(res.msg) } }) }, // 父级 defaultTitleClick (e) { }, // 单级触发 handleClick (e) { }, // 单级触发 handleAdd (item) { } }, beforeDestroy () { } } </script>
子组件jsx
import { Menu, Tooltip, Input } from 'ant-design-vue'
import './menuTree.less'
const { Item, ItemGroup, SubMenu } = Menu
const { Search } = Input
export default {
name: 'Tree',
props: {
dataSource: {
type: Array,
required: true
}
// search: {
// type: Boolean,
// default: false
// }
},
mounted () {
},
data () {
return {
localOpenKeys: []
}
},
methods: {
// 默认项
openKeys (val) {
this.localOpenKeys = val
},
defaultSelectedKeys (item) {
this.$emit('add', item)
},
defaultTitleClick (item) {
this.$emit('defaultTitleClick', item)
},
// 搜索框
// renderSearch () {
// return (
// <Search
// placeholder="input search text"
// style="width: 100%; margin-bottom: 1rem"
// />
// )
// },
// 图标
renderIcon (type) {
return type && type === '0' ? (<span class='limit img_one'></span>) : (<span class="limit img_two"></span>)
},
// 单级
renderMenuItem (item) {
return (
<Item key={item.uniq} {...{ on: { click: () => this.defaultSelectedKeys(item) } }}>
<span class="father">
{ this.renderIcon(item.type) }
<Tooltip placement="topLeft">
<template slot="title">
{ item.cname }
</template>
<span class="cname">{ item.cname }</span>
</Tooltip>
{/* <a class="btn" style="width: 20px;z-index:1300" {...{ on: { click: () => this.handlePlus(item) } }}></a> */}
</span>
</Item>
)
},
// 判断是多级还是单级菜单
renderItem (item) {
return item.children.length > 0 ? this.renderSubItem(item, item.uniq) : this.renderMenuItem(item, item.uniq)
},
// 多级结构
renderSubItem (item, uniq) {
// console.log(item)
const childrenItems = item.children.length > 0 && item.children.map(o => {
return this.renderItem(o, o.uniq)
})
const title = (
<span slot="title" class="father">
{ this.renderIcon(item.type) }
<Tooltip placement="topLeft">
<template slot="title">
{ item.cname }
</template>
<span class="cname">{ item.cname }</span>
</Tooltip>
</span>
)
return (
<SubMenu key={uniq} {...{ on: { titleClick: () => this.defaultTitleClick(item) } }}>
{ title }
{ childrenItems }
</SubMenu>
)
}
},
render () {
const { dataSource, search } = this.$props
// this.localOpenKeys = openKeys.slice(0)
const list = dataSource.map(item => {
return this.renderItem(item)
})
return (
<div class="tree-wrapper">
{/* { search ? this.renderSearch() : null } 搜索框 */}
<Menu mode="inline" class="custom-tree" {...{ on: { click: item => this.$emit('click', item), 'update:openKeys': val => { this.localOpenKeys = val } } }} openKeys={this.localOpenKeys}>
{ list }
</Menu>
</div>
)
}
}
css 注:在使用jsx时图片用img加载不出来时,可以采用背景图片加载,写代码条条道路通罗马,
.img_one { background-image: url(../../assets/img/pdf.png); } .img_two { background-image: url(../../assets/img/file.png); } .limit { display: inline-block; width: 16px; height: 16px; background-repeat: no-repeat; background-size: 16px 16px; margin-right:3px } .father { display: flex; align-items: center; } .cname { display: inline-block; width: 95%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
由此发现jsx在复杂业务场景下为首选

浙公网安备 33010602011771号