以JavaScript来实现WordPress中的二级导航菜单的方法


Posted in Javascript onDecember 14, 2015

导航菜单
导航菜单早已 "深入民心", 在博客上的应用日益重要且多样. 从本文开始, 我将开展几个关于 WordPress 导航菜单的话题, 讨论如何在 WordPress 上使用和加强导航菜单, 话题间有一定的承接关系, 难度也会逐步增加.

以JavaScript来实现WordPress中的二级导航菜单的方法

WordPress 上的导航菜单一般有两种, 页面导航菜单和分类导航菜单.
可曾记得? WordPress 是可以撰写独立页面的, 页面导航菜单就是以首页和各个独立页面组成的菜单. 而分类导航菜单则是以首页和各个分类组成的菜单.
这是效果演示
既然菜单由首页和独立页面列表或首页和分类列表所组成, 我们就需要处理两个环节, 即首页菜单项和其他菜单项.
另外, 我们还需要处理菜单项的三个状态, 即一般状态, 当前菜单项状态 (如: 在首页中, 首页菜单项就是当前菜单项) 和选中菜单项状态.
也就是说, 我们共需要处理 3 个事情:
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>

页面导航菜单

1. 独立页面列表作为菜单项
调用 wp_list_pages 获取独立页面列表, 并使用以下参数:
depth: 列表深度(层的最大数量), 本文讨论的是一级菜单, 故最大深度为 1
title_li: 标题字符串, 这里不需要, 设为 0
sort_column: 列表项的排序方式, 根据创建页面时所设定的 order 进行升序排列
打印独立页面菜单项的语句是:

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

2. 首页菜单项
由于一般独立页面的 class 是 page_item, 当前独立页面的 class 是 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>

3. 菜单的样式
这是一个从普遍到特殊的处理过程, 一般菜单项的样式放前面, 当前和选中菜单项的样式放在后面, 当后者条件满足就会覆盖前者的样式, 从而改变外观.

/* 菜单项 */
#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; /* 背景颜色 */
}

分类导航菜单

1. 分类列表作为菜单项
调用方法 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'); ?>

2. 首页菜单项
与页面导航菜单相似, 只是菜单项的 class 有所不同.
page_item 更改为 cat-item
current_page_item 更改为 current-cat

3. 菜单的样式
因为菜单项的 class 略有不同, 所以也需稍作修改.
current_page_item 更改为 current-cat

二级导航菜单

以JavaScript来实现WordPress中的二级导航菜单的方法

我们已经知道菜单如何创建了, 这回我们要使用分类列表做成二级导航菜单. 我们要做的其实是在原有的基础上改出二级菜单, 以及对二级菜单进行处理. (请确保的的分类中包含子分类, 否则调不出二级菜单.)
我们共需要处理 3 个事情:
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. 调出二级菜单 (子分类)
是否还记得制作导航菜单时是如何设定列表深度的? 当时将深度设为 1 是为了不显示子分类, 现在要二级子分类当然要将深度设为 2 了.
depth: 列表深度(层的最大数量), 本文讨论的是二级菜单, 故最大深度为 2.
打印分类菜单项的语句是:

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

2. 二级菜单的样式
也只是在本来的样式上进行修改, 加上子分类的样式.

/* 二级菜单 */
#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>

3. 二级菜单的效果
全部使用 JavaScript 实现, 为便于理解, 使用面向对象方式编写代码, 借鉴了部分 Prototype 框架的代码. 因为代码比较多, 不适合逐句解说, 所以我已标上了大量注释. 代码不是很复杂, 有 JS 基础的话应该不会存在障碍.
另外为了迎合个别人的口味, 加上透明效果. Enjoy!

/*
 
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);
}
Javascript 相关文章推荐
js 实现打印网页中定义的部分内容的代码
Apr 01 Javascript
快速排序 php与javascript的不同之处
Feb 22 Javascript
jquery ajax学习笔记2 使用XMLHttpRequest对象的responseXML
Oct 16 Javascript
node.js中的fs.writeFile方法使用说明
Dec 14 Javascript
javascript面向对象之对象的深入理解
Jan 13 Javascript
js实现浏览本地文件并显示扩展名的方法
Aug 17 Javascript
JS实现的最简Table选项卡效果
Oct 14 Javascript
AngularJS基础 ng-mouseenter 指令示例代码
Aug 02 Javascript
从零开始做一个pagination分页组件
Mar 15 Javascript
详解React-Native解决键盘遮挡问题(Keyboard遮挡问题)
Jul 13 Javascript
Vue v-bind动态绑定class实例方法
Jan 15 Javascript
JavaScript中的几种继承方法示例
Dec 06 Javascript
JS实现DIV容器赋值的方法
Dec 14 #Javascript
JavaScript中eval()函数用法详解
Dec 14 #Javascript
JS实现单击输入框弹出选择框效果完整实例
Dec 14 #Javascript
JavaScript实现点击按钮就复制当前网址
Dec 14 #Javascript
JavaScript 实现的 zip 压缩和解压缩工具包Zip.js使用详解
Dec 14 #Javascript
JS+JSP通过img标签调用实现静态页面访问次数统计的方法
Dec 14 #Javascript
基于JavaScript实现一定时间后去执行一个函数
Dec 14 #Javascript
You might like
PHP 图片文件上传实现代码
2010/12/29 PHP
PHP开发中常用的字符串操作函数
2011/02/08 PHP
php获取通过http协议post提交过来xml数据及解析xml
2012/12/16 PHP
CodeIgniter实现更改view文件夹路径的方法
2014/07/04 PHP
typecho插件编写教程(三):保存配置
2015/05/28 PHP
php生成静态页面并实现预览功能
2019/06/27 PHP
JS连连看源码完美注释版(推荐)
2013/12/09 Javascript
JavaScript判断用户是否对表单进行了修改的方法
2015/03/18 Javascript
JS实现横向拉伸动感伸缩菜单效果代码
2015/09/04 Javascript
jQuery实现仿QQ头像闪烁效果的文字闪动提示代码
2015/11/03 Javascript
JavaScript 事件对内存和性能的影响
2017/01/22 Javascript
Javascript之深入浅出prototype
2017/02/06 Javascript
jQueryeasyui 中如何使用datetimebox 取两个日期间相隔的天数
2017/06/13 jQuery
KOA+egg.js集成kafka消息队列的示例
2018/11/09 Javascript
微信小程序城市选择及搜索功能的方法
2019/03/22 Javascript
使用vue实现多规格选择实例(SKU)
2019/08/23 Javascript
Vue 实现复制功能,不需要任何结构内容直接复制方式
2019/11/09 Javascript
python批量修改文件后缀示例代码分享
2013/12/24 Python
python 文件转成16进制数组的实例
2018/07/09 Python
详解Python 正则表达式模块
2018/11/05 Python
python使用response.read()接收json数据的实例
2018/12/19 Python
python基于递归解决背包问题详解
2019/07/03 Python
使用OpenCV实现仿射变换—旋转功能
2019/08/29 Python
python中的subprocess.Popen()使用详解
2019/12/25 Python
基于python+selenium的二次封装的实现
2020/01/06 Python
jupyter notebook 调用环境中的Keras或者pytorch教程
2020/04/14 Python
Python matplotlib图例放在外侧保存时显示不完整问题解决
2020/07/28 Python
GIVENCHY纪梵希官方旗舰店:高定彩妆与贵族护肤品
2018/04/16 全球购物
英国Iceland杂货店:网上食品购物
2020/12/16 全球购物
项目投资建议书
2014/05/16 职场文书
2015年党员承诺书
2015/01/21 职场文书
信息技术教研组工作总结
2015/08/13 职场文书
2016银行求职自荐信
2016/01/28 职场文书
Python绘制分类图的方法
2021/04/20 Python
教你怎么用python实现字符串转日期
2021/05/24 Python
浅析Python OpenCV三种滤镜效果
2022/04/11 Python