VUE中遞歸算法實現樹形菜單的寫法:
<template>
<div>
<!-- 父組件將數據傳入子組件 -->
<tree :msg='msg' />
</div>
</template>
<script>
export default {
data (){ //模擬數據
return{
n:0,
msg: [{name:'北京',
sub:[{name:'東城區',
sub:[
{name:'朝陽區'}
]
},{name:'西城區',
sub:[
{name:'關虎屯'}
]
},{name:'南城區'},{name:'北城區'}]
}
,{
name:'廣東',
sub:[{name:'廣州',
sub:[{name:'越秀區'},{name:'白雲區'},{name:'海珠區'}]
},
{name:'深圳',
sub:[{name:'蛇口區'},{name:'保安區'},{name:'鹽田區'}]
},
]
},{
name:'湖北',
sub:[{name:'武漢',
sub:[{name:'江夏區'},{name:"洪山區"},{name:'江漢區'}]
},
{name:'天門市',
sub:[{name:'精靈'},{name:"小班"},{name:'打扮'}]
}]
}],
}
},
// 注冊父組件
components: {
tree:{
name:'gs',//遞歸的構造函數名
//父組件模板,相當於構造函數return的值
template:`
<ul>
<li v-for="(v,i) in msg" :key=i @click.stop.self='n=i'> //第一層的數據,點擊之后,子集菜單會展開,其他子集菜單會關閉
{{v.name}}
<gs :msg=v.sub v-if="i==n"/>//將下一層數據傳入構造函數,進行調用,形成遞歸,相當於自己調用自己,這一步是最關鍵的一步,
</li>
</ul>
`,
props: ['msg'],//接受父組件傳的值
data(){
return{
n:0 //默認展開的菜單下標
}
}
},
}
}
</script>
JS遞歸方法實現:
<!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>
</head>
<body>
<button onclick="fun()">遞歸測試</button>
<div id="div">
</div>
<script>
//模擬數據
var data = [{
name: 1,
sub: [{
name: '1-1',
sub: []
}]
}, {
name: 2,
sub: [{
name: "2-1",
sub: [{
name: '2-1-1',
sub: []
}, {
name: '2-1-2',
sub: []
}
]
}, {
name: "2-2",
sub: [{
name: '2-2-1',
sub: []
}, {
name: '2-2-2',
sub: [{
name: '2-2-2-1',
sub: []
}]
}]
}
]
}, {
name: 3,
sub: []
}]
var div = document.getElementById('div')
var str = '';
//遞歸函數function list(data) {
if (data) {
if (data.length > 0) {
str += "<ul>";
for (let v = 0; v < data.length; v++) {
const item = data[v];
str += '<li>' + item.name;
list(item.sub)
str += '</li>';
}
str += "</ul>";
}
}
}
list(data)
console.log(str)
div.innerHTML = str;
//以下是遞歸測試函數,與樹形菜單無關
var arr = [];
function fun() {
var num = parseFloat(prompt("輸入數字:"));
if (typeof(num) == 'number') {
while (num > 0) {
arr.push(num)
num--;
}
//console.log(arr)
}
}
var arrlist = [];
// var data=[1,[2,3],[4,[5,6,[8]]],9,[10]];
var fun3 = arr => [...arr].map((item) => Array.isArray(item) ? fun3(item) : arrlist.push(item));
fun3(data)
// console.log( fun3(data))
</script>
</body>
</html>
使用VUE + element-ui 實現樹形菜單:
<template>
<div class="custom-tree-container">
<div class="block">
<p>使用 render-content</p>
<el-tree
:data="data"
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false"
:render-content="renderContent"
></el-tree>
</div>
<div class="block">
<p>使用 scoped slot</p>
<el-tree
:data="data"
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false"
>
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button type="text" size="mini" @click="() => append(data)">Append</el-button>
<el-button type="text" size="mini" @click="() => remove(node, data)">Delete</el-button>
</span>
</span>
</el-tree>
</div>
<button @click="getAdd">+</button>
<button @click="getjian">-</button>
</div>
</template>
<script>
let id = 1000;
export default {
data() {
const data = [
{
name: "北京",
sub: [
{
name: "北京",
sub: [
{ name: "東城區" },
{ name: "西城區" },
{ name: "南城區" },
{ name: "北城區" }
]
}
]
},
{
name: "廣東",
sub: [
{
name: "廣州",
sub: [{ name: "越秀區" }, { name: "白雲區" }, { name: "海珠區" }]
},
{
name: "深圳",
sub: [{ name: "蛇口區" }, { name: "保安區" }, { name: "鹽田區" }]
}
]
},
{
name: "湖北",
sub: [
{
name: "武漢",
sub: [{ name: "江夏區" }, { name: "洪山區" }, { name: "江漢區" }]
},
{
name: "天門市",
sub: [{ name: "精靈" }, { name: "小班" }, { name: "打扮" }]
}
]
}
];
//關鍵部分
let _data = function(data) {
return data.map(v => {
if (v.sub) { // 遍歷數據,將菜單數據賦值給 ui框架指定屬性名
v.label = v.name;
v.children = v.sub;
return _data(v.sub);
}
if (v.name && !v.sub) {
v.label = v.name;
return 123;
}
});
};
_data(data);
return {
data: JSON.parse(JSON.stringify(data)), //將處理過的數據進行深刻隆
data: JSON.parse(JSON.stringify(data))
};
},
methods: {
append(data) {
const newChild = { id: id++, label: "testtest", children: [] };
if (!data.children) {
this.$set(data, "children", []);
}
data.children.push(newChild);
},
remove(node, data) {
const parent = node.parent;
const children = parent.data.children || parent.data;
const index = children.findIndex(d => d.id === data.id);
children.splice(index, 1);
},
renderContent(h, { node, data, store }) {
return (
<span class="custom-tree-node">
<span>{node.label}</span>
<span>
<el-button
size="mini"
type="text"
on-click={() => this.append(data)}
>
Append
</el-button>
<el-button
size="mini"
type="text"
on-click={() => this.remove(node, data)}
>
Delete
</el-button>
</span>
</span>
);
},
getAdd() {
this.$store.commit("increment");
console.log("我是加法" + this.$store.state.count);
},
getjian() {
this.$store.commit("jian", 2);
console.log("我是加Z法" + this.$store.state.count);
}
},
mounted() {
console.log(this.$store.state.count);
}
};
</script>
<style>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
</style>
js 實現無極限目錄樹完整版
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div { margin-left: 20px; cursor: pointer; } .has-child { position: relative; } .has-child::before { content: '+'; position: absolute; left: -20px; } .has-child > div { display: none; } .has-child.expend > div { display: block; } .has-child.expend::before { content: '-'; } </style> </head> <body> <div id="demo"></div> <script> var data = [{ name: '一級標題1', children: [{ name: '二級標題1', children: [{ name: '三級標題' }] }, { name: '二級標題2', children: [{ name: '三級標題' }] }] }, { name: '一級標題2', children: [{ name: '二級標題1', children: [{ name: '三級標題', children: { name: '四級標題' } }] }] }, { name: '一級標題3', children: [{ name: '二級標題1', children: [{ name: '三級標題' }] }, { name: '二級標題2', children: [{ name: '三級標題' }] }, { name: '二級標題3' }] }] // 用來創建目錄樹結構的函數 /** * data 目錄樹的數據 * parentNode: 將目錄樹結構插入到哪個節點下 */ function dTree(data, parentNode) { // 做一個兼容 如果當前沒有傳遞父節點則創建一個父節點 if (!parentNode) { parentNode = document.createElement('div'); parentNode.className = 'root'; } // 遍歷數據中的每一項創建目錄樹的結構 data.forEach(function (item) { var node = document.createElement('div'); node.innerText = item.name; // 阻止事件冒泡 node.onclick = function (e) { e.stopPropagation(); } // 判斷當前標題下面是否含有子標題如果含有的話繼續創建標題結構 if(item.children && item.children.length > 0) { // 如果含有子標題則添加一個has-child的類名 node.className = 'has-child'; // 如果含有子標題則當前的標題可以點擊展開 node.onclick = function (e) { e.stopPropagation(); if (this.classList.contains('expend')) { this.classList.remove('expend') } else { this.classList.add('expend') } } // 如果有子標題的話 需要繼續創建子標題的結構 dTree(item.children, node); } parentNode.appendChild(node); }) // 當前函數直接返回創建出來的目錄樹結構 由於所有的結構都插入到了父節點當中,因此可以返回父節點 return parentNode } var demo = document.getElementById('demo'); dTree(data, demo); </script> </body> </html>
...
