layui中推荐使用tree组件实现动态异步导航菜单,通过async懒加载子节点、loadfilter转换数据格式、click跳转,并由后端控制权限与树形结构。

layui 导航菜单实现动态异步加载 JSON 树,核心是用 layui.nav(或更常用的是 layui.tree)配合 AJAX 请求后端数据,再将返回的树形结构渲染为可点击、可展开的侧边栏菜单。注意:layui 官方并未提供专门的「导航菜单组件」,实际项目中多用 tree 组件模拟导航菜单,或结合 ul>li 手动渲染,推荐使用 tree —— 更简洁、支持异步加载子节点、自带图标和展开收起逻辑。
1. 后端返回标准树形 JSON 格式
确保后端接口(如 /api/menu)返回符合 layui.tree 要求的数组格式,每个节点至少包含:id、title、children(可选)、href(跳转地址,用于菜单链接):
[
{
"id": "1",
"title": "控制台",
"href": "/home",
"icon": "layui-icon-home"
},
{
"id": "2",
"title": "系统管理",
"icon": "layui-icon-set",
"children": [
{ "id": "2-1", "title": "用户管理", "href": "/user/list" },
{ "id": "2-2", "title": "角色管理", "href": "/role/list" }
]
}
]
⚠️ 注意:children 字段为空数组 [] 表示无子节点;为 null 或缺失时 tree 默认不显示展开箭头;若需懒加载(点击才拉子菜单),则不返回 children,改用 isParent: true + id 触发异步加载。
2. 前端用 layui.tree 异步加载(推荐懒加载)
在 HTML 中预留容器,JS 初始化 tree 并配置 click 和 oncheck(如需选中态),关键在于设置 loadFilter 和 async:
- 使用
async: { enable: true, url: '/api/menu/children', type: 'get' }开启懒加载,点击父节点时自动携带id请求子项 -
loadFilter用于转换后端返回数据为 tree 识别格式(例如把name→title、url→href) -
click回调中用location.href = data.href实现菜单跳转(或用 iframe 切换内容)
layui.use(['tree'], function(){
var tree = layui.tree;
tree.render({
elem: '#menuTree',
data: [], // 初始空数据,靠 async 加载根节点
showCheckbox: false,
click: function(obj){
if(obj.data.href){
location.href = obj.data.href;
}
},
async: {
enable: true,
url: '/api/menu/children', // 请求子菜单接口,自动带 id 参数:?id=2
type: 'get'
},
loadFilter: function(data){
// 后端返回 [{name:'用户管理',url:'/user'}] → 转为 [{title:'用户管理',href:'/user'}]
return data.map(function(item){
return {
title: item.name || item.title,
href: item.url || item.href,
id: item.id,
isParent: item.hasChildren // 控制是否显示展开箭头
};
});
}
});
});
3. 若用 ul+li 手动渲染(兼容旧版或需高度定制)
适合需要自定义图标、徽标、权限控制 class 的场景。流程为:先请求全部菜单 → 递归生成 HTML → 插入 DOM → 绑定事件:
- 用
$.getJSON('/api/menu')获取完整树形数据 - 写一个递归函数
buildMenu(items),拼接<li>@#@#@#@#@#@#@#@#@#@0<ul>...</ul> </li> - 插入到
<ul class="layui-nav layui-nav-tree"></ul>中 - 调用
layui.element.render('nav')激活 layui 导航样式和折叠行为
4. 权限与高亮同步处理
菜单高亮当前页面需后端返回时标记 spread: true(展开)和 checked: true(选中),或前端根据 location.pathname 匹配 href 后调用 tree.setChecked(id, true);权限过滤建议在后端完成——只返回当前用户有权限的菜单节点,避免前端隐藏带来安全隐患。
不复杂但容易忽略:后端接口要支持按 parent_id 查询子项(懒加载)、字段命名与前端约定一致、树形数据必须保证无环、首层节点不能嵌套在 children 里。









