动态树形菜单的几种递归写法小结
vue递归方法实现:
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>
方法二:
APP.vue
<template>
<div id="app">
<Home :items="items"></Home>
</div>
</template>
<script>
import Home from "./components/Home.vue";
export default {
name: "App",
data() {
return {
items: [
{
name: "IT互联网",
child: [
{
name: "编辑语言",
child: [
{ name: "java" },
{ name: "c#/ .net" },
{ name: "python" },
],
},
{
name: "前端开发",
child: [{ name: "jq" }, { name: "vue " }, { name: "react " }],
},
{
name: "移动开发",
child: [{ name: " android开发" }, { name: "IOS开发" }],
},
{
name: "游戏开发",
child: [
{ name: " phaser游戏开发" },
{ name: "webGL游戏开发", child: [{ name: "3D游戏" }] },
],
},
],
},
],
};
},
components: {
Home,
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Home.vue
<template>
<div class="lists">
<Item v-for="(v, i) in items" :key="i" :item="v"></Item>
</div>
</template>
<script>
import Item from "./Item";
export default {
name: "",
components: { Item },
data() {
return {};
},
props: ["items"],
};
</script>
<style></style>
Item.vue
<template>
<ul>
<li>
<div>{{ item.name }}</div>
<Item v-for="(v, i) in item.child" :key="i" :item="v"></Item>
</li>
</ul>
</template>
<script>
export default {
name: "Item",
components: {},
data() {
return {};
},
props: ["item"],
};
</script>
<style></style>
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>
...

浙公网安备 33010602011771号