今天在處理遞歸無限層級菜單時,遇到一個稍微燒腦的問題,如何顯示當前節點所在的層級數。
廢話很少說,咱們先看個直觀的無限層級:php
<?php // 這裏的arr是直接從數據庫取出的,僅做爲測試數據 $arr = array( array('id' => 1, 'name' => '一級菜單a', 'pid' => 0),// pid 父級id array('id' => 2, 'name' => '一級菜單b', 'pid' => 0), array('id' => 3, 'name' => '二級菜單a', 'pid' => 1), array('id' => 4, 'name' => '二級菜單b', 'pid' => 1), array('id' => 5, 'name' => '二級菜單c', 'pid' => 2), array('id' => 6, 'name' => '二級菜單d', 'pid' => 2), array('id' => 7, 'name' => '三級菜單a', 'pid' => 3), array('id' => 8, 'name' => '三級菜單b', 'pid' => 3), array('id' => 9, 'name' => '四級菜單a', 'pid' => 8), ); /** 獲取全部子節點 * @param $data 全部節點數組 * @param $id $pid 父級節點id * @param $level 層級 * @return array */ function getTree($data, $pid, $level = 0) { $list = array(); foreach ($data as $k => $v) { if ($v['pid'] == $pid) { $v['level'] = $level; $v['name'] = $v['name'].'('.($level+1).'級)'; // 這裏能夠加個層級次數 $v['children'] = getTree($data, $v['id'], $level + 1); if ($v['children'] == null){ unset($v['children']); } $list[] = $v; } } return $list; } $menu = getTree($arr, 0, 0); $json = json_encode($menu); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <style> *{ box-sizing: border-box; margin: 0;padding: 0; } *:before,*:after{ box-sizing: border-box; } ul, li { list-style: none; } .l_tree_container { width: 100%; height: 100%; box-shadow: 0 0 3px #ccc; margin: 13px; position: relative; } .l_tree { width: calc(100% - 44px); height: 100%; padding-left: 42px; } .l_tree_branch { width: 100%; height: 100%; display: block; padding: 13px; position: relative; } .l_tree_branch .l_tree_children_btn { width: 19px; height: 19px; background-color: #23b1f0; font-size: 14px; text-align: center; color: #ffffff; outline: none; border: 0; cursor: pointer; } ul.l_tree:before { content: ''; border-left: 1px dashed #999999; height: calc(100%); position: absolute; left: 10px; top: 0px; } .l_tree .l_tree_branch:last-child::before { content: ''; width: 3px; height: calc(100% - 24px); display: block; background-color: #ffffff; position: absolute; bottom: 0; left: -34px; } .l_tree, .l_tree_branch { position: relative; } .l_tree_branch::after { content: ''; width: 40px; height: 0; border-bottom: 1px dashed #000; position: absolute; right: calc(100% - 9px); top: 22px; } .l_tree_container>.l_tree::before, .l_tree_container>.l_tree>.l_tree_branch::after { display: none; } </style> </head> <body> <div id="demo"> <div class="l_tree_container"> <ew-tree :model="testdata"></ew-tree> </div> </div> <script> // 樹組件 Vue.component('ew-tree', { template: ` <ul class="l_tree"> <li class="l_tree_branch" v-for="item in model" :key="item.id"> <div class="l_tree_click"> <button type="button" class="l_tree_children_btn" v-if="item.children" @click="toggle(item)">{{ !item.show ? '-' : '+' }}</button> <span class="l_folder">{{ item.name }}</span> </div> <ew-tree v-show="!item.show" v-if="item.children" :model="item.children"></ew-tree> </li> </ul>`, props: { model: {} }, methods: { toggle: function (item) { var idx = this.model.indexOf(item) Vue.set(this.model[idx], 'show', !item.show) } } }); new Vue({ el: "#demo", data() { return { testdata: <?php echo $json?> } } }) </script> </body> </html>
咱們看到全部節點層級數沒問題,那麼我如何查看節點中pid=3的全部節點層級關係呢html
$menu = getTree($arr, 3, 0);
顯然不對,何況菜單展現並不友好,pid=3的父節點至少要顯示在頂層吧。層級數暫且無論,咱們先解決如何顯示頂層pid=3的樹形結構:
pid=3對應的節點是:二級菜單a。這個能夠直接根據數據id查詢出來,此處僅作演示哈。調整下代碼:vue
$menu = getTree($arr, 3, 0); $menu = array(['name' => '二級菜單a','children'=> $menu]); $json = json_encode($menu);
OK,完美,一樣要顯示全部pid=1的節點層級關係,同樣,pid=1對應的節點是 一級菜單a數據庫
$menu = getTree($arr, 1, 0); $menu = array(['name' => '一級菜單a','children'=> $menu]); $json = json_encode($menu);
好,回到 剛纔的話題,如何正確的顯示每一個節點所在的層級數呢? 這裏我也思考了好久,也沒找到快捷的方法。
最終我仍是遞歸的查詢本節點全部的父節點id集合:完整代碼以下:npm
<?php // 這裏的arr是直接從數據庫取出的,僅做爲測試數據 $arr = array( array('id' => 1, 'name' => '一級菜單a', 'pid' => 0),// pid 父級id array('id' => 2, 'name' => '一級菜單b', 'pid' => 0), array('id' => 3, 'name' => '二級菜單a', 'pid' => 1), array('id' => 4, 'name' => '二級菜單b', 'pid' => 1), array('id' => 5, 'name' => '二級菜單c', 'pid' => 2), array('id' => 6, 'name' => '二級菜單d', 'pid' => 2), array('id' => 7, 'name' => '三級菜單a', 'pid' => 3), array('id' => 8, 'name' => '三級菜單b', 'pid' => 3), array('id' => 9, 'name' => '四級菜單a', 'pid' => 8), ); /** 獲取全部子節點 * @param $data 全部節點數組 * @param $id $pid 父級節點id * @param $level 層級 * @return array */ function getTree($data, $pid, $level = 0) { $list = array(); foreach ($data as $k => $v) { if ($v['pid'] == $pid) { $v['level'] = $level; $v['name'] = $v['name'] . '(' . ($level + 1) . '級)'; // 這裏能夠加個層級次數 $v['children'] = getTree($data, $v['id'], $level + 1); if ($v['children'] == null) { unset($v['children']); } $list[] = $v; } } return $list; } /** 根據子節點獲取父節點id * @param $data 全部節點數組 * @param $id id 主鍵id * @return array */ function getParentid($data, $id) { $arr = array(); foreach ($data as $v) { if ($v['id'] == $id) { $arr[] = $v; //$arr[$v['id']]=$v['name']; $arr = array_merge(getParentid($data, $v['pid']), $arr); } } return $arr; } $id = 8 ; // 對應的節點是: 三級菜單b 對應的pid 是 3 $pid = 3; // 對應的節點是 二級菜單a $toparr = getParentid($arr, $id); // 節點爲8的全部父節點 id: 1 3 8 這裏包含了自身,注意剔除 $level = count($toparr); // 節點所在的層級數 $menu = getTree($arr, $pid, $level-1); if($pid) $menu = array(['name' => '二級菜單a' . '(' . ($level-1) . '級)', 'children' => $menu]); $json = json_encode($menu); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <style> * { box-sizing: border-box; margin: 0; padding: 0; } *:before, *:after { box-sizing: border-box; } ul, li { list-style: none; } .l_tree_container { width: 100%; height: 100%; box-shadow: 0 0 3px #ccc; margin: 13px; position: relative; } .l_tree { width: calc(100% - 44px); height: 100%; padding-left: 42px; } .l_tree_branch { width: 100%; height: 100%; display: block; padding: 13px; position: relative; } .l_tree_branch .l_tree_children_btn { width: 19px; height: 19px; background-color: #23b1f0; font-size: 14px; text-align: center; color: #ffffff; outline: none; border: 0; cursor: pointer; } ul.l_tree:before { content: ''; border-left: 1px dashed #999999; height: calc(100%); position: absolute; left: 10px; top: 0px; } .l_tree .l_tree_branch:last-child::before { content: ''; width: 3px; height: calc(100% - 24px); display: block; background-color: #ffffff; position: absolute; bottom: 0; left: -34px; } .l_tree, .l_tree_branch { position: relative; } .l_tree_branch::after { content: ''; width: 40px; height: 0; border-bottom: 1px dashed #000; position: absolute; right: calc(100% - 9px); top: 22px; } .l_tree_container > .l_tree::before, .l_tree_container > .l_tree > .l_tree_branch::after { display: none; } </style> </head> <body> <div id="demo"> <div class="l_tree_container"> <ew-tree :model="testdata"></ew-tree> </div> </div> <script> // 樹組件 Vue.component('ew-tree', { template: ` <ul class="l_tree"> <li class="l_tree_branch" v-for="item in model" :key="item.id"> <div class="l_tree_click"> <button type="button" class="l_tree_children_btn" v-if="item.children" @click="toggle(item)">{{ !item.show ? '-' : '+' }}</button> <span class="l_folder">{{ item.name }}</span> </div> <ew-tree v-show="!item.show" v-if="item.children" :model="item.children"></ew-tree> </li> </ul>`, props: { model: {} }, methods: { toggle: function (item) { var idx = this.model.indexOf(item) Vue.set(this.model[idx], 'show', !item.show) } } }); new Vue({ el: "#demo", data() { return { testdata: <?php echo $json?> } } }) </script> </body> </html>
一樣要顯示全部節點:直接把pid賦值0,好比:json
$id = 2 ; // 對應的節點是: 一級菜單b 對應的pid 是 0 $pid = 0; // 對應的節點是 0 爲 一級節點 顯示全部節點,上面的$id用不到 $toparr = getParentid($arr, $id); // $level = count($toparr); // 節點所在的層級數 $menu = getTree($arr, $pid, $level-1); if($pid) $menu = array(['name' => '二級菜單a' . '(' . ($level-1) . '級)', 'children' => $menu]); $json = json_encode($menu);
看起來沒毛病,博友們若是有好的辦法獲取任意一個節點所處的層級數,歡迎拍磚留言哈。數組