JavaScript实现WordPress二级导航菜单的完整指南

作者:函数茶馆时间:2026-10-29 18:49:32浏览:609

本文详细讲解如何在WordPress中通过JavaScript实现二级导航菜单。内容涵盖页面与分类菜单的基础构建,利用wp_list_pages和wp_list_categories函数控制深度与排序,并结合CSS样式与JavaScript面向对象编程实现悬停交互及透明效果,适用于需要动态交互的WordPress主题开发。

导航菜单在博客中的应用日益广泛且重要,其形式也愈发多样。本系列将从基础入手,逐步探讨如何在WordPress中构建并增强导航菜单功能,各章节内容相互关联,难度循序渐进。

WordPress导航菜单基础类型与状态处理

WordPress导航菜单基础类型与状态处理

WordPress中的导航菜单主要分为两类:页面导航菜单和分类导航菜单。页面导航菜单由首页及各个独立页面组成,而分类导航菜单则由首页及各文章分类构成。实现此类菜单需处理两个核心环节:首页菜单项与其他菜单项。此外,还需处理菜单项的三种状态:一般状态、当前菜单项状态(如在首页中首页链接的状态)以及选中菜单项状态。具体而言,需解决三个问题:1. 首页外的其他菜单项处理;2. 首页菜单项处理;3. 不同状态下的视觉效果呈现。

预期的菜单结构如下所示。


<div id="menubar">
 <ul class="menus">
 <li class="..."><a href="http://.../">Home</a></li>
 <li class="..."><a href="http://.../">菜单项1</a></li>
 <li class="..."><a href="http://.../">菜单项2</a></li>
 <li class="..."><a href="http://.../">菜单项3</a></li>
 ...
 </ul>
</div>

页面导航菜单实现细节

页面导航菜单的实现方案。

首先,将独立页面列表作为菜单项。通过调用wp_list_pages函数获取页面列表,并设置以下参数:depth(列表深度,本文讨论一级菜单,故设为1)、title_li(标题字符串,此处不需要,设为0)、sort_column(排序方式,按创建页面时设定的order升序排列)。打印独立页面菜单项的代码如下:


<?php wp_list_pages('depth=1&title_li=0&sort_column=menu_order'); ?>

其次,处理首页菜单项。由于普通独立页面的class为page_item,当前页面为current_page_item,当页面为首页时,其class应为current_page_item,否则为page_item。因此,需要一段分支代码来确定其class:


<?php
 
// 如果是首页, class 是 current_page_item
if (is_home()) {
 $home_menu_class = 'current_page_item';
// 如果不是首页, class 是 page_item
} else {
 $home_menu_class = 'page_item';
}
 
?>

打印首页菜单项的代码如下:


<li class="<?php echo($home_menu_class); ?>">
 <a title="Home" href="<?php echo get_settings('home'); ?>/">Home</a>
</li>

最后,设置菜单样式。这是一个从通用到特殊的过程,一般菜单项的样式定义在前,当前和选中菜单项的样式定义在后。当满足后者的条件时,会覆盖前者的样式,从而改变外观。


/* 菜单项 */
#menubar ul.menus li {
 float:left; /* 靠左浮动 */
 list-style:none; /* 清空列表风格 */
 margin-right:1px; /* 右侧的间隔 */
}
/* 菜单项链接 */
#menubar ul.menus li a {
 padding:5px 10px; /* 内边距 */
 display:block; /* 显示为块 */
 color:#FFF; /* 文字颜色 */
 background:#67ACE5; /* 背景颜色 */
 text-decoration:none; /* 没有下横线 */
}
/* 当前菜单项链接 */
#menubar ul.menus li.current_page_item a {
 background:#5495CD; /* 背景颜色 */
}
/* 选中菜单项链接 */
#menubar ul.menus li a:hover {
 background:#4281B7; /* 背景颜色 */
}

分类导航菜单实现细节

接下来介绍分类导航菜单的实现。

首先,将分类列表作为菜单项。调用wp_list_categories函数获取分类列表,并设置以下参数:depth(列表深度,一级菜单设为1)、title_li(标题字符串,设为0)、orderby(排序方式,按创建页面时设定的order升序排列)、show_count(是否显示文章数量,此处不需要,设为0)。打印分类菜单项的代码如下:


<?php wp_list_categories('depth=1&title_li=0&orderby=name&show_count=0'); ?>

其次,处理首页菜单项。与页面导航菜单类似,但菜单项的class有所不同:page_item需更改为cat-item,current_page_item需更改为current-cat。

最后,调整菜单样式。由于菜单项的class略有不同,需对样式进行相应修改,将current_page_item更改为current-cat。

二级导航菜单的JavaScript实现

本节重点介绍二级导航菜单的实现。

WordPress导航菜单基础类型与状态处理

在掌握基础菜单创建后,我们将利用分类列表构建二级导航菜单。核心工作是在原有基础上扩展二级菜单,并对二级菜单进行特殊处理(请确保分类中包含子分类,否则无法调用二级菜单)。具体需解决三个问题:1. 调出二级菜单(子分类);2. 二级菜单的样式设置;3. 二级菜单的交互效果。

预期的二级菜单结构如下。


<div id="menubar">
 <ul class="menus">
 <li class="..."><a href="http://.../">Home</a></li>
 <li class="...">
  <a href="http://.../">菜单1</a>
  <ul class="children">
  <li class="..."><a href="http://.../">菜单项1</a></li>
  <li class="..."><a href="http://.../">菜单项2</a></li>
  <li class="..."><a href="http://.../">菜单项3</a></li>
  </ul>
 </li>
 <li class="...">
  <a href="http://.../">菜单2</a>
  <ul class="children">
  <li class="..."><a href="http://.../">菜单项4</a></li>
  </ul>
 </li>
 <li class="...">
  <a href="http://.../">菜单3</a>
  <ul class="children">
  <li class="..."><a href="http://.../">菜单项5</a></li>
  <li class="..."><a href="http://.../">菜单项6</a></li>
  </ul>
 </li>
 ...
 </ul>
</div>

具体实施步骤如下。

首先,调出二级菜单(子分类)。回顾之前设定列表深度的方法,当时设为1以隐藏子分类,现在为了显示二级菜单,需将深度设为2。参数设置:depth(列表深度,二级菜单设为2)。打印分类菜单项的代码如下:


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

其次,设置二级菜单样式。在原有样式基础上进行修改,增加子分类的特定样式。


/* 二级菜单 */
#menubar ul.children {
 display:none; /* 初始化页面时不显示出来 */
 padding:0;
 margin:0;
}
/* 二级菜单的菜单项 */
#menubar ul.children li {
 float:none; /* 垂直排列 */
 margin:0;
 padding:0;
}
/* 二级菜单的当前菜单项链接 */
#menubar ul.children li a {
 width:100px; /* 对 IE6 来说十分很重要 */
}

打印首页菜单项的代码如下:


<li class="<?php echo($home_menu_class); ?>">
 <a title="Home" href="<?php echo get_settings('home'); ?>/">Home</a>
</li>

最后,实现二级菜单效果。全部使用JavaScript实现,为便于理解,采用面向对象方式编写代码,并借鉴了部分Prototype框架的代码。由于代码量较大,此处未逐句解释,但已添加大量注释。代码逻辑并不复杂,具备JS基础即可理解。此外,为了提升视觉效果,还添加了透明效果,供参考使用。


/*
 
Author: mg12
Feature: MenuList with second-level menus
Update: 2008/08/30
Tutorial URL: http://www.neoease.com/wordpress-menubar-2/
 
*/
 
/** 类 */
var Class = {
 create: function() {
 return function() {
  this.initialize.apply(this, arguments);
 }
 }
}
 
/** 菜单列表 */
var MenuList = Class.create();
MenuList.prototype = {
 
 /**
 * 构造方法
 * id: 菜单列表
 * opacity: 透明度 (0.0 - 1.0, 0.0 为全透明, 1.0 为不透明)
 */
 initialize: function(id, opacity) {
 // 获取菜单列表
 this.obj = document.getElementById(id);
 if (!this.obj) { return; }
 
 // 对菜单列表内的所有菜单进行处理
 var menus = this.obj.childNodes;
 for (var i = 0; i < menus.length; i++) {
  var menu = menus[i];
  if (menu.tagName == 'LI') {
  // 构建菜单
  new Menu(menu, opacity);
  }
 }
 }
}
 
/** 菜单 */
var Menu = Class.create();
Menu.prototype = {
 
 /**
 * 构造方法
 * target: 目标菜单
 * opacity: 透明度 (0.0 - 1.0, 0.0 为全透明, 1.0 为不透明)
 */
 initialize: function(target, opacity) {
 this.util = new MenuUtil();
 
 // 获取目标菜单 (没多余元素)
 this.obj = this.util.cleanWhitespace(target);
 // 定义透明度, 默认为不透明
 this.opacity = opacity || 1;
 
 // 获取菜单
 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');
 this.util.setStyle(this.body, 'overflow', 'hidden');
 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);
 },
 
 /**
 * 激活方法
 * 当鼠标移动到菜单标题是激活
 */
 activate: function() {
 // 获取当前菜单体的位置
 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, 'left', left + 'px');
 this.util.setStyle(this.body, 'top', top + 'px');
 this.util.setStyle(this.body, 'visibility', 'visible');
 this.util.setStyle(this.body, 'opacity', this.opacity);
 this.util.setStyle(this.body, 'filter', 'alpha(opacity=' + this.opacity * 100 + ')');
 },
 
 /**
 * 解除方法
 * 当鼠标移动出菜单标题是激活
 */
 deactivate: function(){
 // 定义解除时样式
 this.util.setStyle(this.body, 'visibility', 'hidden');
 },
 
 /**
 * 监听方法
 * element: 监听对象
 * name: 监听方法
 * observer: 执行的方法
 * useCapture: 浏览器调用事件的方式 (true 为 Capture 方式, false 为 Bubbling 方式)
 */
 addListener: function(element, name, observer, useCapture) {
 if(element.addEventListener) {
  element.addEventListener(name, observer, useCapture);
 } else if(element.attachEvent) {
  element.attachEvent('on' + name, observer);
 }
 }
}
 
/** 一些实用的方法 */
var MenuUtil = Class.create();
MenuUtil.prototype = {
 initialize: function() {
 },
 
 $: function(id) {
 return document.getElementById(id);
 },
 
 $A: function(iterable) {
 if(!iterable) {
  return [];
 }
 if(iterable.toArray) {
  return iterable.toArray();
 } else {
  var results = [];
  for(var i = 0; i < iterable.length; i++) {
  results.push(iterable[i]);
  }
  return results;
 }
 },
 
 bind: function() {
 var array = this.$A(arguments);
 var func = array[array.length - 1];
 var _method = func, args = array, object = args.shift();
 return function() {
  return _method.apply(object, args.concat(array));
 }
 },
 
 getHeight: function(element) {
 return element.offsetHeight;
 },
 
 setStyle: function(element, key, value) {
 element.style[key] = value;
 },
 
 getStyle: function(element, key) {
 return element.style[key];
 },
 
 cleanWhitespace: function(list) {
 var node = list.firstChild;
 while (node) {
  var nextNode = node.nextSibling;
  if(node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
  list.removeChild(node);
  }
  node = nextNode;
 }
 return list;
 },
 
 cumulativeOffset: function(element) {
 var valueT = 0, valueL = 0;
 do {
  valueT += element.offsetTop || 0;
  valueL += element.offsetLeft || 0;
  element = element.offsetParent;
 } while (element);
 return [valueL, valueT];
 }
}
 
/** 添加到页面加载事件 */
window.onload = function(e) {
 new MenuList('menus', 0.9);
}

作者最新文章