在前端實現樹目錄,首先我們要想想好數據結構,分單級與多級兩種情況如圖所示:

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在復雜業務場景下為首選
