空痕博客

光年模板(V5)侧边栏菜单js修改

KongHen02
3天前发布 /正在检测是否收录...

主要修改了初始化JSON结构,使菜单层级更清晰。

修改后的代码

// 侧边栏列表
var menu_list = [
  {
    "name": "首页",
    "url": ["/", "/index/index"],
    "icon": "mdi mdi-home-variant-outline",
    "is_out": 0
  },
  {
    "name": "链接管理",
    "url": ["#!"],
    "icon": "mdi mdi-cookie-outline",
    "is_out": 0,
    "children": [
      {
        "name": "链接列表",
        "url": ["/link/list", "/link/data"],
        "is_out": 0
      },
      {
        "name": "创建链接",
        "url": ["/link/create", "/link/edit"],
        "is_out": 0
      }
    ]
  },
  {
    "name": "财务管理",
    "url": ["#!"],
    "icon": "mdi mdi-credit-card-chip-outline",
    "is_out": 0,
    "children": [
      {
        "name": "余额充值",
        "url": ["/finance/recharge"],
        "is_out": 0
      },
      {
        "name": "账单列表",
        "url": ["/finance/bills"],
        "is_out": 0
      }
    ]
  },
  {
    "name": "用户管理",
    "url": ["/user/list"],
    "icon": "mdi mdi-account-outline",
    "is_out": 0,
  },
  {
    "name": "系统设置",
    "url": ["#!"],
    "icon": ["mdi mdi-cog-outline"],
    "is_out": 0,
    "children": [
      {
        "name": "个人资料",
        "url": ["/system/user"],
        "is_out": 0,
      },
      {
        "name": "操作日志",
        "url": ["/system/logs"],
        "is_out": 0,
        "children": [
          {
            "name": "账单日志",
            "url": ["/system/logs/bills"],
            "is_out": 0,
          },
          {
            "name": "登录日志",
            "url": ["/system/logs/login"],
            "is_out": 0,
          },
          {
            "name": "链接日志",
            "url": ["/system/logs/link"],
            "is_out": 0,
          }
        ]
      }
    ]
  },
  {
    "name": "退出登录",
    "url": ["/user/logout"],
    "icon": "mdi mdi-location-exit",
    "is_out": 0
  }
];

setSidebar(menu_list);

/**
 * 菜单
 * @param data 菜单JSON数据
 *        name      菜单名称          string
 *        url       菜单链接地址       array    首个为跳转地址。当路由为其中一个时,激活当前菜单选中状态。
 *        icon      图标
 *        is_out    是否外链0否|1是    int      外链a标签没有class='multitabs'
 *        children  子菜单            array
 */
function setSidebar(data) {
  if (data.length == 0) return false;
  processMenu(data);
  console.log(data);
  html = createMenu(data, true);
  $('.sidebar-main').append(html);
}

// 创建html数据
function createMenu(data, is_frist) {
  var menu_body = is_frist ? '<ul class="nav-drawer">' : '<ul class="nav nav-subnav">';
  for (var i = 0; i < data.length; i++) {
    iframe_class = data[i].is_out == 1 ? 'target="_blank"' : 'class="multitabs"';
    icon_div = data[i].is_root == 1 ? '<i class="' + data[i].icon + '"></i>' : '';
    menuName = data[i].is_root == 1 ? '<span>' + data[i].name + '</span>' : data[i].name;

    if (data[i].children && data[i].children.length > 0) {
      selected = data[i].is_active == 1 ? 'active open' : '';
      menu_body += '<li class="nav-item nav-item-has-subnav ' + selected + '"><a href="javascript:void(0)">' + icon_div + menuName + '</a>';
      menu_body += createMenu(data[i].children);
    } else {
      selected = data[i].is_active == 1 ? 'active' : '';
      menu_body += '<li class="nav-item ' + selected + '"><a href="' + data[i].url[0] + '" ' + iframe_class + '>' + icon_div + menuName + '</a>';
    }
    menu_body += '</li>';
  }
  menu_body += '</ul>';
  return menu_body;
};


// 添加 is_active 和 is_root 属性到所有层级
function addProperties(menu) {
    menu.forEach(item => {
        item.is_active = 0;
        item.is_root = 0;
        if (item.children && item.children.length > 0) {
            addProperties(item.children);
        }
    });
}

// 标记激活状态和父级路径
function markActivePath(menu, currentPath, parentChain = []) {
    for (let i = 0; i < menu.length; i++) {
        const item = menu[i];
        const newParentChain = [...parentChain, item];
        
        // 检查当前路径是否匹配
        const isMatch = item.url.some(url => url === currentPath);
        
        if (isMatch) {
            // 标记当前节点为激活
            item.is_active = 1;
            
            // 标记整个父链为激活
            newParentChain.forEach(node => {
                node.is_active = 1;
                node.is_root = 1;
            });
            return true; // 找到匹配路径
        }
        
        // 递归检查子节点
        if (item.children && item.children.length > 0) {
            const foundInChildren = markActivePath(item.children, currentPath, newParentChain);
            if (foundInChildren) {
                // 标记当前节点为激活(因为子节点已激活)
                item.is_active = 1;
                item.is_root = 1;
                return true;
            }
        }
    }
    return false; // 当前分支未找到匹配
}

// 主处理函数
function processMenu(menu) {
    // 1. 添加初始属性
    addProperties(menu);
    
    // 2. 标记第一层级为根节点
    menu.forEach(item => {
        item.is_root = 1;
    });
    
    // 3. 获取当前页面路径
    const currentPath = window.location.pathname;
    
    // 4. 标记激活路径
    markActivePath(menu, currentPath);
}

光年模板原代码

var menu_list = [
    {
        "id": "1",
        "name": "后台首页",
        "url": "lyear_main_1_v5.html",
        "pid": 0,
        "icon": "mdi mdi-home",
        "is_out": 0,
        "is_home": 1
    },
    {
        "id": "2",
        "name": "布局示例",
        "url": "#!",
        "pid": 0,
        "icon": "mdi mdi-palette",
        "is_out": 0,
        "is_home": 0
    },
    {
        "id": "3",
        "name": "表单布局示例",
        "url": "lyear_layout_form.html",
        "pid": 2,
        "icon": "",
        "is_out": 0,
        "is_home": 0
    },
    {
        "id": "4",
        "name": "聊天页面示例",
        "url": "lyear_layout_chat.html",
        "pid": 2,
        "icon": "",
        "is_out": 0,
        "is_home": 0
    },
    {
        "id": "5",
        "name": "logo处使用文字",
        "url": "lyear_layout_logo_text.html",
        "pid": 2,
        "icon": "",
        "is_out": 1,
        "is_home": 0
    },
    {
        "id": "6",
        "name": "多级菜单",
        "url": "#!",
        "pid": 0,
        "icon": "mdi mdi-menu",
        "is_out": 0,
        "is_home": 0
    },
    {
        "id": "7",
        "name": "一级菜单",
        "url": "#!",
        "pid": 6,
        "icon": "",
        "is_out": 0,
        "is_home": 0
    },
    {
        "id": "8",
        "name": "一级菜单",
        "url": "#!",
        "pid": 6,
        "icon": "",
        "is_out": 0,
        "is_home": 0
    },
    {
        "id": "9",
        "name": "二级菜单",
        "url": "#!",
        "pid": 8,
        "icon": "",
        "is_out": 0,
        "is_home": 0
    },
    {
        "id": "10",
        "name": "二级菜单",
        "url": "#!",
        "pid": 8,
        "icon": "",
        "is_out": 0,
        "is_home": 0
    },
    {
        "id": "11",
        "name": "三级菜单",
        "url": "#!",
        "pid": 10,
        "icon": "",
        "is_out": 0,
        "is_home": 0
    },
    {
        "id": "12",
        "name": "三级菜单",
        "url": "#!",
        "pid": 10,
        "icon": "",
        "is_out": 0,
        "is_home": 0
    }
];
setSidebar(menu_list);
/**
 * 菜单
 * @param data 菜单JSON数据
 *        id 菜单唯一ID
 *        name 菜单名称
 *        url 菜单链接地址
 *        icon 图标
 *        pid  父级ID
 *        is_out 是否外链0否|1是,外链a标签没有class='multitabs'
 *        is_home 是否首页
 */
function setSidebar(data){
    if (data.length == 0) return false;
    var treeObj = getTrees(data, 0, 'id', 'pid', 'children');
    html = createMenu(treeObj, true);
    $('.sidebar-main').append(html);
}
function createMenu(data, is_frist) {
    var menu_body = is_frist ? '<ul class="nav-drawer">' : '<ul class="nav nav-subnav">';
    for(var i = 0; i < data.length; i++){
        iframe_class = data[i].is_out == 1 ? 'target="_blank"' : 'class="multitabs"';
        icon_div     = data[i].pid == 0 ? '<i class="' + data[i].icon + '"></i>' : '';
        selected     = (data[i].pid == 0) && (data[i].is_home == 1) ? 'active' : '';
        menuName     = data[i].pid == 0 ? '<span>' + data[i].name + '</span>' : data[i].name;
        homeIdName   = (data[i].pid == 0) && (data[i].is_home == 1) ? 'id="default-page"' : '';
        if (data[i].children && data[i].children.length > 0) {
            menu_body += '<li class="nav-item nav-item-has-subnav"><a href="javascript:void(0)">' + icon_div + menuName + '</a>';
            menu_body += createMenu(data[i].children);
        } else {
            menu_body += '<li class="nav-item ' + selected + '"><a href="' + data[i].url + '" '+ iframe_class + homeIdName + '>' + icon_div + menuName + '</a>';
        }
        menu_body += '</li>';
    }
    menu_body += '</ul>';
    return menu_body;
};
/**
 * 树状的算法
 * @params list     代转化数组
 * @params parentId 起始节点
 * @params idName 主键ID名
 * @params parentIdName 父级ID名称
 * @params childrenName 子级名称
 * @author CSDN博主「伤包子」
 */
function getTrees(list, parentId, idName, parentIdName, childrenName) {
    let items= {};
    // 获取每个节点的直属子节点,*记住是直属,不是所有子节点
    for (let i = 0; i < list.length; i++) {
         let key = list[i][parentIdName];
         if (items[key]) {
             items[key].push(list[i]);
         } else {
             items[key] = [];
             items[key].push(list[i]);
         }
     }
     return formatTree(items, parentId, idName, childrenName);
}
/**
 * 利用递归格式化每个节点
 */
function formatTree(items, parentId, idName, childrenName) {
    let result = [];
    if (!items[parentId]) {
        return result;
    }
    for (let t in items[parentId]) {
        items[parentId][t][childrenName] = formatTree(items, items[parentId][t][idName], idName, childrenName)
        result.push(items[parentId][t]);
    }
    return result;
}

参考文献

侧边栏菜单的JS初始化 - 光年模板(V5)

© 版权声明
THE END
喜欢就支持一下吧
点赞 0 分享 收藏
评论 抢沙发
取消
易航博客