【Vue】vue/树形结构利用递归组件生成无限极联动按钮组件DEMO
使用方法:
组件属性
:data => [Array] 需要的数据格式(数据库id,pid那种,见示例代码)
:activies => [Array] 当前全部的选中值
组件事件
@click => 点击事件
<bch-nav :data="list" @click="navItemClick" :activies="activies"></bch-nav>
使用示例代码:
new Vue({ name: 'app', template: ` <bch-nav :data="list" @click="navItemClick" :activies="activies"></bch-nav> `, components: { bchNav }, data() { return { list: [ { id: 1, name: "广东", pid: 0 }, { id: 2, name: "广州", pid: 1 }, { id: 3, name: "深圳", pid: 1 }, { id: 4, name: "龙岗", pid: 3 }, { id: 5, name: "福田", pid: 3 }, { id: 6, name: "宝龙", pid: 4 }, { id: 7, name: "山西", pid: 0 }, { id: 8, name: "太原", pid: 7 }, { id: 9, name: "临汾", pid: 7 }, ], activies: [] } }, methods: { navItemClick(item) { console.log(item); } } }).$mount('#div')
样式源码:
<style> #app { position: relative; } .button { width: 100px; padding: 4px 10px; border: 1px solid #ccc; border-radius: 4px; text-align: center; } .button:hover { cursor: default; } .item-box { position: absolute; top: 180px; } .button.active { background-color: #666; color: #fff; } </style>
模板代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> </head> <body> <div id="div"></div> </body> </html>
JS代码:
const bchNav = { name: 'bch-nav', props: { data: { type: Array, default: () => { return [] } }, activies: { type: Array, default: () => { return [] } } }, template: ` <div> <h2>{{activies}}</h2> <bch-nav-item :list="list" @click="itemClick" :activies="activies" ref="bchNavItemRef"></bch-nav-item> </div> `, components: { bchNavItem: { name: 'dfc-nav', template: ` <div> <div v-for="(item, index) in list" :key="index"> <p v-show="item.show" class="button" :class="{active: activies[item.level] == item.name}" @click="itemClick(item, index)"> {{ item.name }} </p> <div v-if="item.children && item.children.length"> <dfc-nav class="item-box" :activies="activies" :class="['item-box-' + item.level]" :list="item.children"> </dfc-nav> </div> </div> </div>`, props: { list: { type: Array, default: () => { return [] } }, activies: { type: Array, default: () => { return [] } } }, data() { return {}; }, mounted() { }, methods: { itemClick(item, index) { this.itemHide(this.list) this.list.forEach(v => v.show = true) this._itemClick(item) this.$emit('click', item) }, _itemClick(item) { item.show = true this.$set(this.activies, item.level, item.name) this.activies.splice(item.level + 1) if (item.children && item.children.length > 0) { item.children.forEach((v, k) => { if (k == 0) this._itemClick(v) v.show = true }) } }, itemHide(array, name) { array.forEach((v, k) => { v.show = false if (v.children) this.itemHide(v.children, v.name) }) } } } }, data() { return { list: [], } }, methods: { itemClick(item) { this.$emit('click', item) }, calculationLevel(arr) { let maxLevel = 0; ! function multiArr(arr, level) { ++level; maxLevel = Math.max(level, maxLevel); for (let i = 0; i < arr.length; i++) { let item = arr[i]; item.level = level; if (item.children && item.children.length > 0) { multiArr(item.children, level); } else { delete item.children; } } }(arr, 0); return maxLevel; }, formatToT2ree(items) { let res = [] let getChildren = (res, pid, level = -1) => { items.forEach((v, k) => { if (v.pid === pid) { const newItem = { ...v, show: false, children: [] } if (newItem.pid === 0) { newItem.show = true } newItem.level = level res.push(newItem) getChildren(newItem.children, newItem.id, ++newItem.level) } }) } getChildren(res, 0) return res }, }, mounted() { this.list = this.formatToTree(this.data) setTimeout(() => { this.$refs.bchNavItemRef.itemClick(this.list[0]) }, 0) } }