WordPress 多级导航菜单

WordPress 多级导航菜单

多级导航菜单, 是指菜单存在多个层次, 层层嵌套, 当鼠标移动到某个菜单时, 如果其包含子菜单则将相应的子菜单显示出来. 本文将提供此功能在 WordPress 的实现方法, 一般的 HTML 页面和其他程序也可以加工套用.

时隔 9 个多月, 关于导航菜单的话题又回来了. 上次写到三级菜单就不写了是因为我发现自己根本用不上, 就没去研究. 最近我在做一个小玩意儿用到了这个, 所以把它给做了出来并集成到 iNove 主题上. 因为内容繁多, 所以还是以之前的文章和代码作为基础来展开讲解, 希望这个文章会对大家有所帮助.

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

这是效果演示

相关话题:

WordPress 导航菜单
二级导航菜单
淡出淡入导航菜单
滚动导航菜单
jQuery 导航菜单
多级导航菜单
点选式导航菜单 (待定话题)

作业分析:

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

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

预想结构:

实施操作:

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

 wp_list_pages('depth=2&title_li=0&sort_column=menu_order'); ?>

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

/* 子菜单的菜单项 */
#menubar ul.children li {
	float:none; /* 垂直排列 */
	margin:0;
	padding:0;
	/* multi 2009/06/11 ADD START */
	display:inline; /* 对 IE 来说十分很重要 */
	/* multi 2009/06/11 ADD END */
}

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

#menubar ul.children li a.subtitle {
	border-right:3px solid #4281B7;
	width:97px;
}

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

#menubar ul.menus li a:hover, 
/* multi 2009/06/11 ADD START */
#menubar ul.menus li a.current {
/* multi 2009/06/11 ADD END */
	background:#4281B7; /* 背景颜色 */
}

3. 加载菜单
加载菜单是应该分开处理, 对于对层次的菜单, 菜单显示有两种状态. (1) 作为二级菜单显示在上一级菜单的下方; (2) 而三级和以上层次的菜单则会显示在上一级菜单的右侧.

// 找到所有的菜单
var menus = this.obj.getElementsByTagName('ul');
for (var i = 0; i < menus.length; i++) {
	// 找到菜单的父节点 (包括标题链接部分)
	var menu = menus[i].parentNode;
 
	// 如果菜单的父节点就是根菜单, 显示一般的菜单
	if(menu.parentNode === this.obj) {
		new Menu(menu, opacity);
 
	// 如果菜单的父节点不是根菜单, 说明当前菜单是子菜单
	} else {
		new Menu(menu, opacity, 1);
		// 在子菜单的标题链接上加上 class 名, 以便定义样式
		menu.firstChild.className += ' subtitle';
	}
}

4. 菜单的初始化
添加一个参数, 以识别是否为子菜单 (三级以上的菜单); 去除 overflow:hidden; 的设置, 否则子菜单无法显示出来.

initialize: function(target, opacity, sub) {
	this.util = new MenuUtil();
 
	// 获取目标菜单 (没多余元素)
	this.obj = this.util.cleanWhitespace(target);
 
	// 定义透明度, 默认透明
	this.opacity = opacity || 1;
 
	/* multi 2009/06/11 ADD START */
	// 是否为子菜单
	this.sub = sub || -1;
	/* multi 2009/06/11 ADD START */
 
	// 获取菜单
	this.menu = this.obj.childNodes
 
	// 重要! 如果菜单不包含菜单项, 则不进行处理
	if (this.menu.length < 2) { return; }
 
	// 菜单标题和菜单体
	this.title = this.menu[0];
	this.body = this.menu[1];
 
	// 定义初始样式
	this.util.setStyle(this.body, 'visibility', 'hidden');
	this.util.setStyle(this.body, 'position', 'absolute');
	/* multi 2009/06/11 DELETE START */
	//this.util.setStyle(this.body, 'overflow', 'hidden');
	/* multi 2009/06/11 DELETE END */
	this.util.setStyle(this.body, 'display', 'block');
 
	// 添加监听器
	this.addListener(this.obj, 'mouseover', this.util.bind(this, this.activate), false);
	this.addListener(this.obj, 'mouseout', this.util.bind(this, this.deactivate), false);
	}

5. 对菜单和子菜单分开处理
菜单 (二级菜单) 的位置是相对于窗口的, 而子菜单 (三级或以上菜单) 是的位置是相对于上一级菜单的, 所以必须判断是哪种菜单类型, 并以不同的方法来确定位置. 另外, 两者要显示的位置也不相同, 所以在激活方法内还需要以不同的方式将 top 和 left 位置计算出来.

// 获取当前菜单体的位置 (子菜单)
if(this.sub == 1) {
	var pos = this.util.currentOffset(this.title);
	var left = this.util.getWidth(this.body);
	var top = pos[1];
 
// 获取当前菜单体的位置 (菜单)
} else {
	var pos = this.util.cumulativeOffset(this.title);
	var left = pos[0];
	var top = pos[1] + this.util.getHeight(this.title);
	// 子菜单不需要设置不透明度, 否则会形成多重透明, 效果不好.
	this.util.setStyle(this.body, 'opacity', this.opacity);
}

6. 添加当前菜单的 className
为了更好的表示当前菜单的上级菜单, 在激活菜单的时候为当前菜单加上 className.

// 当前选中菜单加上 class 名为, 以便定义样式
this.title.className += ' current';

并且在解除菜单的时候移除菜单上的 className.

// 离开菜单时取消当前菜单上的 class 名, 恢复原本的样式
this.title.className = this.title.className.replace('current', '');

演示主题:

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

下载主题: default_with_menubar_5.zip

你可能感兴趣的:(WordPress)