1、效果图如下所示:
2、网络请求的数据结构如下:
3、新建插件文件:menu-tree.vue,插件代码如下:
<template>
<div class="root">
<div class="parent" @click="onParentClick(parentItem)">
<div class="parent-rectangle" :style="{ 'width': i == 1 ? '24px' : '32px' }" v-for="i in currentLevel - 1" :key="i"></div>
<div class="parent-right">
<img class="parent-icon" :src="getParentIconUrl()" @click.stop="changeExpandStatus()"/>
<div class="parent-title" v-html="parentItem.text"></div>
</div>
</div>
<div class="child" v-if="isShowChildList()">
<MenuTree :parentItem="item" v-for="(item, index) in parentItem.children" :currentLevel="currentLevel + 1"
:key="index" @onMenuTreeItemConfirm="onMenuTreeItemConfirm"></MenuTree>
</div>
</div>
</template>
<script>
export default {
components: {
MenuTree: () => import('./menu-tree.vue') // 引入自身作为子组件
},
props: {
parentItem: {
type: Object,
default: {}
},
currentLevel: {
type: Number,
default: 1
},
},
mounted() {},
data() {
return {
treeMinUnitIconUrl: require('@/assets/images/icon-file.svg'),
treeFoldedIconUrl: require('@/assets/images/icon-to-fold.svg'),
treeExpandedIconUrl: require('@/assets/images/icon-to-expand.svg'),
}
},
watch: {},
methods: {
isShowChildList() {
return this.parentItem.expanded;
},
changeExpandStatus() {
console.log("this.parentItem.childQty = " + this.parentItem.childQty);
if (this.parentItem.childQty && this.parentItem.childQty > 0) {
this.parentItem.expanded = !this.parentItem.expanded;
}
},
getParentIconUrl() {
if (this.currentLevel == 1) {
return this.treeMinUnitIconUrl;
}
if (!this.parentItem.childQty || this.parentItem.childQty == 0) {
return this.treeMinUnitIconUrl;
}
return this.parentItem.expanded ? this.treeFoldedIconUrl : this.treeExpandedIconUrl;
},
onParentClick(item) {
if (this.currentLevel > 1) {
item.currentLevel = this.currentLevel;
}
this.$emit("onMenuTreeItemConfirm", item);
},
onMenuTreeItemConfirm(item) {
this.onParentClick(item);
},
},
}
</script>
<style scoped>
.root {
width: 100%;
min-height: 48px;
display: flex;
flex-direction: column;
align-items: center;
}
.parent {
min-height: 48px;
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
}
.parent-rectangle {
min-height: 48px;
}
.parent-right {
min-height: 48px;
min-width: 140px;
display: flex;
flex-direction: row;
align-items: center;
}
.parent-icon {
width: 24px;
height: 24px;
}
.parent-title {
width: calc(100% - 24px - 8px);
min-height: 16px;
text-align: left;
line-height: 16px;
font-size: 14px;
margin-left: 8px;
}
.child {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
</style>
4、使用方法如下:
<template>
<div class="root">
<van-popup class="popup" v-model="showMenuTreePop" round position="bottom">
<div class="popup-title">请选择行政区划</div>
<div style="height: 60vh; width: 100%; overflow-y: scroll;">
<MenuTree :parentItem="rootItem" :currentLevel="1" @onMenuTreeItemConfirm="onMenuTreeItemConfirm"></MenuTree>
</div>
<div class="table-bottom">
<div class="table-bottom-btn color-green" @click="showMenuTreePop = false">取消</div>
</div>
</van-popup>
</div>
</template>
<script>
import MenuTree from '@/components/menu-tree.vue';
export default {
components: { MenuTree },
data() {
return {
rootItem: {},
showMenuTreePop: false,
}
},
methods: {
loadMenutreeDataList() {
// 通过网络请求获取数据列表 res
console.log("res = ", res);
this.$set(this.rootItem, "children", res);
this.$set(this.rootItem, "text", "行政区划");
this.$set(this.rootItem, "expanded", true);
this.$set(this.rootItem, "childQty", res ? res.length : 0);
this.showMenuTreePop = true;// 打开弹窗
},
onMenuTreeItemConfirm(clickedItem) {
// clickedItem 就是点击选中的数据项, 其 currentLevel 属性值就是其所处层级,如果层级是1,则表示点击的是根节点
this.showMenuTreePop = false;// 关闭弹窗
},
}
}
</script>
<style scoped>
.root {
width: 100%;
height: 100vh;
}
.popup {
width: 100%;
background: #FFFFFF;
border-radius: 16px;
}
.table-bottom {
width: 100%;
height: 71px;
display: flex;
flex-direction: row;
align-items: center;
border-top: solid 1px #E8E8E8;
}
.table-bottom-btn {
min-width: 50px;
height: 44px;
flex: 1;
color: #FFFFFF;
font-size: 12px;
line-height: 44px;
border-radius: 22px;
margin-left: 3%;
margin-right: 3%;
font-family: PingFangSC-Regular;
font-weight: 400;
text-align: center;
}
.color-green {
color: #FFFFFF;
background-color: #2DA541;
}
</style>
5、插件中使用到的资源文件如下:
1、icon-file.svg
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1716600220842" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="19100" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M815.104 69.632q27.648 25.6 44.032 42.496t25.088 28.672 10.752 19.968 2.048 14.336l0 16.384-151.552 0q-10.24 0-17.92-7.68t-12.8-17.92-7.68-20.992-2.56-16.896l0-126.976 3.072 0q8.192 0 16.896 2.56t19.968 9.728 28.16 20.48 42.496 35.84zM640 129.024q0 20.48 6.144 42.496t19.456 40.96 33.792 31.232 48.128 12.288l149.504 0 0 577.536q0 29.696-11.776 53.248t-31.232 39.936-43.008 25.6-46.08 9.216l-503.808 0q-19.456 0-42.496-11.264t-43.008-29.696-33.28-41.984-13.312-49.152l0-696.32q0-21.504 9.728-44.544t26.624-42.496 38.4-32.256 45.056-12.8l391.168 0 0 128zM704.512 768q26.624 0 45.056-18.944t18.432-45.568-18.432-45.056-45.056-18.432l-384 0q-26.624 0-45.056 18.432t-18.432 45.056 18.432 45.568 45.056 18.944l384 0zM768 448.512q0-26.624-18.432-45.568t-45.056-18.944l-384 0q-26.624 0-45.056 18.944t-18.432 45.568 18.432 45.056 45.056 18.432l384 0q26.624 0 45.056-18.432t18.432-45.056z" p-id="19101" fill="#1296db"></path></svg>
2、icon-to-expand.svg
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1716600138280" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5120" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M880 112a32 32 0 0 1 32 32v736a32 32 0 0 1-32 32H144a32 32 0 0 1-32-32V144a32 32 0 0 1 32-32z m-40 72H184v656h656V184zM536 320c4.416 0 8 3.584 8 8V480h152c4.416 0 8 3.584 8 8v48a8 8 0 0 1-8 8H544v152a8 8 0 0 1-8 8h-48a8 8 0 0 1-8-8V544H328A8 8 0 0 1 320 536v-48c0-4.416 3.584-8 8-8H480V328c0-4.416 3.584-8 8-8z" fill="#1296db" fill-opacity=".65" p-id="5121"></path></svg>
3、icon-to-fold.svg
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1716600168259" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18002" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M880 112a32 32 0 0 1 32 32v736a32 32 0 0 1-32 32H144a32 32 0 0 1-32-32V144a32 32 0 0 1 32-32z m-40 72H184v656h656V184zM696 480c4.416 0 8 3.584 8 8v48a8 8 0 0 1-8 8h-368A8 8 0 0 1 320 536v-48c0-4.416 3.584-8 8-8z" fill="#1296db" fill-opacity=".65" p-id="18003"></path></svg>