找回密码
 加入
搜索

多级导航菜单

[复制链接]
发表于 2006-7-3 15:37:32 | 显示全部楼层 |阅读模式

难度: ★★★★
多级导航菜单, 是指菜单存在多个层次, 层层嵌套, 当鼠标移动到某个菜单时, 如果其包含子菜单则将相应的子菜单显示出来.

为了简化处理, 明确目标, 这次我们会以二级导航菜单作为原型进行扩展. 本文只对多级菜单相关处理进行讨论, 其他内容请参考以前的几篇关于菜单导航的文章, 文章链接你可以在本文相关话题中找到.
这是效果演示

因为菜单由本来的二级菜单变成了多级菜单, 所以菜单结构会有些变化 (会有新的更深层的子菜单加入). 另外, 页面的样式和脚本都会有相应的变更, 重点在于对 JavaScript 的加工.

主要操作如下:
1. 鼠标移动到一级菜单的菜单项时, 如果该菜单项包含了二级菜单, 那么在下方显示其子菜单.
2. 鼠标移动到 N (N >= 2) 级菜单的菜单项时, 如果该菜单项包含了 N+1 级菜单, 那么在右侧显示其子菜单.

预想结构:
  1. <div id="menubar">
  2.         <ul class="menus">
  3.                 <li class="..."><a href="http://.../">Home</a></li>
  4.                 <li class="...">
  5.                         <a href="http://.../">菜单1</a>
  6.                         <ul class="children">
  7.                                 <li class="..."><a href="http://.../">菜单11</a></li>
  8.                                 <li class="...">
  9.                                         <a href="http://.../">菜单12</a>
  10.                                         <ul class="children">
  11.                                                 <li class="..."><a href="http://.../">菜单121</a></li>
  12.                                                 <li class="..."><a href="http://.../">菜单122</a></li>
  13.                                                 <li class="..."><a href="http://.../">菜单123</a></li>
  14.                                                 <li class="..."><a href="http://.../">菜单124</a></li>
  15.                                         </ul>
  16.                                 </li>
  17.                                 <li class="...">
  18.                                         <a href="http://.../">菜单13</a>
  19.                                         <ul class="children">
  20.                                                 <li class="..."><a href="http://.../">菜单131</a></li>
  21.                                                 <li class="..."><a href="http://.../">菜单132</a></li>
  22.                                         </ul>
  23.                                 </li>
  24.                         </ul>
  25.                 </li>
  26.                 <li class="...">
  27.                         <a href="http://.../">菜单2</a>
  28.                         <ul class="children">
  29.                                 <li class="..."><a href="http://.../">菜单21</a></li>
  30.                         </ul>
  31.                 </li>
  32.                 <li class="...">
  33.                         <a href="http://.../">菜单3</a>
  34.                         <ul class="children">
  35.                                 <li class="..."><a href="http://.../">菜单31</a></li>
  36.                                 <li class="...">
  37.                                         <a href="http://.../">菜单32</a>
  38.                                         <ul class="children">
  39.                                                 <li class="..."><a href="http://.../">菜单321</a></li>
  40.                                                 <li class="..."><a href="http://.../">菜单322</a></li>
  41.                                         </ul>
  42.                                 </li>
  43.                         </ul>
  44.                 </li>
  45.                 ...
  46.         </ul>
  47. </div>
复制代码


实施操作:1. 调出无限级菜单 (子分类)
是否还记得如何设定列表的深度? 可以通过参数 depth 来进行设定. 当我们将深度设为 1 时不显示子分类, 将深度设为 2 时显示二级菜单. 现在我们要无限制层数的菜单, 所以可以去除这个参数, 系统会自动返回所有菜单. 所以显示菜单的代码如下:

  1. <?php wp_list_pages('depth=2&title_li=0&sort_column=menu_order'); ?>
复制代码


2. 修改菜单的样式
在子菜单项添加 display:inline; 以免在 IE (IE6/IE7/IE8) 中发生错位.

  1. /* 子菜单的菜单项 */
  2. #menubar ul.children li {
  3. float:none; /* 垂直排列 */
  4. margin:0;
  5. padding:0;
  6. /* multi 2009/06/11 ADD START */
  7. display:inline; /* 对 IE 来说十分很重要 */
  8. /* multi 2009/06/11 ADD END */
  9. }
复制代码

追加包含子菜单的菜单项的样式

  1. #menubar ul.children li a.subtitle {
  2. border-right:3px solid #4281B7;
  3. width:97px;
  4. }
复制代码

添加当前菜单的效果, 以明确当前路径.

  1. #menubar ul.menus li a:hover,
  2. /* multi 2009/06/11 ADD START */
  3. #menubar ul.menus li a.current {
  4. /* multi 2009/06/11 ADD END */
  5. background:#4281B7; /* 背景颜色 */
  6. }
复制代码

3. 加载菜单
加载菜单是应该分开处理, 对于对层次的菜单, 菜单显示有两种状态. (1) 作为二级菜单显示在上一级菜单的下方; (2) 而三级和以上层次的菜单则会显示在上一级菜单的右侧.
  1. // 找到所有的菜单
  2. var menus = this.obj.getElementsByTagName('ul');
  3. for (var i = 0; i < menus.length; i++) {
  4. // 找到菜单的父节点 (包括标题链接部分)
  5. var menu = menus[i].parentNode;

  6. // 如果菜单的父节点就是根菜单, 显示一般的菜单
  7. if(menu.parentNode === this.obj) {
  8. new Menu(menu, opacity);

  9. // 如果菜单的父节点不是根菜单, 说明当前菜单是子菜单
  10. } else {
  11. new Menu(menu, opacity, 1);
  12. // 在子菜单的标题链接上加上 class 名, 以便定义样式
  13. menu.firstChild.className += ' subtitle';
  14. }
  15. }
复制代码

4. 菜单的初始化
添加一个参数, 以识别是否为子菜单 (三级以上的菜单); 去除 overflow:hidden; 的设置, 否则子菜单无法显示出来.
  1. initialize: function(target, opacity, sub) {
  2. this.util = new MenuUtil();

  3. // 获取目标菜单 (没多余元素)
  4. this.obj = this.util.cleanWhitespace(target);

  5. // 定义透明度, 默认透明
  6. this.opacity = opacity || 1;

  7. /* multi 2009/06/11 ADD START */
  8. // 是否为子菜单
  9. this.sub = sub || -1;
  10. /* multi 2009/06/11 ADD START */

  11. // 获取菜单
  12. this.menu = this.obj.childNodes

  13. // 重要! 如果菜单不包含菜单项, 则不进行处理
  14. if (this.menu.length < 2) { return; }

  15. // 菜单标题和菜单体
  16. this.title = this.menu[0];
  17. this.body = this.menu[1];

  18. // 定义初始样式
  19. this.util.setStyle(this.body, 'visibility', 'hidden');
  20. this.util.setStyle(this.body, 'position', 'absolute');
  21. /* multi 2009/06/11 DELETE START */
  22. //this.util.setStyle(this.body, 'overflow', 'hidden');
  23. /* multi 2009/06/11 DELETE END */
  24. this.util.setStyle(this.body, 'display', 'block');

  25. // 添加监听器
  26. this.addListener(this.obj, 'mouseover', this.util.bind(this, this.activate), false);
  27. this.addListener(this.obj, 'mouseout', this.util.bind(this, this.deactivate), false);
  28. }
复制代码

5. 对菜单和子菜单分开处理
菜单 (二级菜单) 的位置是相对于窗口的, 而子菜单 (三级或以上菜单) 是的位置是相对于上一级菜单的, 所以必须判断是哪种菜单类型, 并以不同的方法来确定位置. 另外, 两者要显示的位置也不相同, 所以在激活方法内还需要以不同的方式将 top 和 left 位置计算出来.
  1. // 获取当前菜单体的位置 (子菜单)
  2. if(this.sub == 1) {
  3. var pos = this.util.currentOffset(this.title);
  4. var left = this.util.getWidth(this.body);
  5. var top = pos[1];

  6. // 获取当前菜单体的位置 (菜单)
  7. } else {
  8. var pos = this.util.cumulativeOffset(this.title);
  9. var left = pos[0];
  10. var top = pos[1] + this.util.getHeight(this.title);
  11. // 子菜单不需要设置不透明度, 否则会形成多重透明, 效果不好.
  12. this.util.setStyle(this.body, 'opacity', this.opacity);
  13. }
复制代码

6. 添加当前菜单的 className
为了更好的表示当前菜单的上级菜单, 在激活菜单的时候为当前菜单加上 className.
  1. // 当前选中菜单加上 class 名为, 以便定义样式
  2. this.title.className += ' current';
复制代码

并且在解除菜单的时候移除菜单上的 className.
  1. // 离开菜单时取消当前菜单上的 class 名, 恢复原本的样式
  2. this.title.className = this.title.className.replace('current', '');
复制代码

演示主题:以 WordPress 自带主题 default 为基础, 仅做学习参考使用, 修改过的文件有 header.php 和 style.css, 添加了文件 js/menu.js
下载主题: default_with_menubar_5.zip

Archiver|手机版|小黑屋|乱弹琴|重庆网址之家|多来米发 |

GMT+8, 2026-10-14 12:00 AM

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表