学习从实践开始之jQuery插件开发 菜单插件开发

  虽然这不是多么高深的技术,但对于新手来说还是颇有难度。如果你是一个新手,我希望你能从本文中学到东西;如果你是高手,我希望你能留下你宝贵的意见和建议

  一.要做什么插件?

  我想要实现一个可以在网站或WEB应用系统中使用,可以灵活的定制外观、简单、易于使用、方便扩展、稳定的菜单插件。它可以被用在网站主导航条上,亦可以用在管理后台。

  二.想要的效果是什么?

  平时菜单处于收起状态,当鼠标移入显示其下级菜单,以此类推;可以方便的使用html标签设置菜单的结构,也可以使用数组动态生成。

  三.设计一下功能

  

学习从实践开始之jQuery插件开发 菜单插件开发

对图片的说明

  菜单项默认的状态。

  拥有下级菜单且鼠标移入时的状态。

  间隔(起到分组的效果)

  拥有下级菜单,鼠标未移入时的状态。

  竖排拥有下级菜单且鼠标移入时的状态。

  获得焦点时的状态。

  其他功能

  菜单所有状态的样式均通过CSS控制,可以根据需要灵活修改。

  通过HTML和javascript两种方式生成菜单。

  为菜单项指定点击回调函数和跳转地址(当指定回调函数时,不设置URL地址,而是将URL地址传入回调函数)。

  四.如何实现功能?

   1.使用CSS样式控制外观。

     *为了避免CSS命名冲突,我们需要为插件确定一个名字空间,其下所有样式都在该命名空间下。

  2.菜单标签的选择

    *一般来说实现菜单的标签多数会选择列表标签<ul><li></li></ul>来实现,我们也不例外。

    菜单项:<li><a href="链接地址"><span>菜单项显示名称</span></a></li>

  3.控制UL标签的显示方式

    *使用CSS去掉符号和缩进

    *使用CSS横向排列,横向排列有两种方法:

      (1).用的比较多的是浮动排列(float:left;);但是这种方式有个最大的问题是会破坏页面结构,我不是很喜欢这种方式。

      (2).使用内联(display:inline-block)的方式;目前已知的问题是低版本浏览器可能支持的不太好,这个问题网络上有专门的文章讨论,这里我就不再赘述了。

    *当我在使用这种方式是出现了一个小问题,就是块与块之间有大概10px的空隙。我删除掉HTML代码里标签之间的空隙(换行)后,这些空隙消失了;这虽然可以解决问题,但是缺破坏了代码的结构,可读性差;如果是动态生成的还能接受。所以我想到了另一种解决办法,那就是设置每一个块(<li>标签)的的左边距为-10px;同时设置<ul>的左内距为10px,perfect!!!

  五.浏览器兼容

  未在IE6和IE7下进行相关测试。

  六.功能实现和调用

  样式控制

  

复制代码 代码如下:

  View Code

  /*为了避免命名冲突,我们将该插件所有样式都放在该类之下*/

  .ctcx-menu

  {

  font-size:14px;

  }

  .ctcx-menu ul

  {

  list-style-type:none;

  margin:0;

  padding:0;

  }

  /*设置偏移量*/

  .ctcx-menu ul.offset

  {

  position:relative;

  top:-32px;

  left:100px;

  }

  .ctcx-menu ul li /*菜单项样式*/

  {

  width:100px;

  height:30px;

  line-height:30px;

  text-align:center;

  vertical-align:top;

  margin:0;

  padding:0;

  }

  /*菜单项样式*/

  .ctcx-menu a

  {

  display:block;

  height:100%;

  border:1px solid #999;

  background-color:#FFF;

  text-decoration:none;

  color:#000;

  }

  .ctcx-menu a:hover

  {

  background-color:#999;

  color:#FFF;

  }

  .ctcx-menu a:active{}

  /*横向菜单*/

  .ctcx-menu .horizontal

  {

  padding-left:7px;

  }

  .ctcx-menu .horizontal li

  {

  display:inline-block;

  margin-left:-7px;

  }

  .ctcx-menu .horizontal li.item-has-children > a /*拥有子菜单的菜单项样式*/

  {

  }

  .ctcx-menu .horizontal li.spacing /*横向间隔*/

  {

  height:30px;

  width:10px;

  background-color:#000;

  }

  /*竖向菜单*/

  .ctcx-menu .vertical

  {

  }

  .ctcx-menu .vertical li

  {

  margin-left:0px;

  }

  .ctcx-menu .vertical li.item-has-children > a /*拥有子菜单的菜单项样式*/

  {

  }

  .ctcx-menu .vertical li.spacing /*纵向间隔*/

  {

  height:10px;

  width:100px;

  background-color:#000;

  }

  插件代码

  

复制代码 代码如下:

  View Code

  (function ($) {

  $.fn.menu = function (options) {

  if (typeof options != 'undefined' && options.constructor === Array) options = { data: options };

  var opts = $.extend({}, $.fn.menu.defaults, options);

  var _tempMenuData = [];

  //返回数据级别

  function getLevel(id) {

  var _level = 0;

  var _o = getMenuData(id);

  while (_o != null) {

  _level++;

  _o = getMenuData(_o.pid);

  }

  return _level;

  }

  //返回数据对象

  function getMenuData(id) {

  for (var i = 0; i < opts.data.length; i++) {

  if (opts.data[i].id == id)

  return opts.data[i];

  }

  return null;

  }

  //返回生成的HTML

  function getHtml(pid) {

  var _li_data = getData(pid);

  if (_li_data.length == 0) return null;

  var _ul = $('<ul></ul>');

  $.each(_li_data, function (i, _d) {

  var _children = getHtml(_d.id);

  var _li = $('<li></li>').appendTo(_ul);

  if (_d.n == null || _d.n.length == 0) {

  _li.addClass('spacing');

  } else if (typeof _d.fn === 'function') {

  $('<a href="javascript:;"></a>').html(_d.n)

  .click(function () {

  _d.fn(_d.url);

  }).appendTo(_li);

  } else if (_d.url.length > 0) {

  $('<a href="' + _d.url + '"></a>').html(_d.n).appendTo(_li);

  }

  if (_children != null) {

  _li.addClass('item-has-children');

  _children.appendTo(_li);

  _li.bind({

  mouseover: function () {

  _children.show();

  },

  mouseout: function () {

  _children.hide();

  }

  });

  }

  })

  if (pid == null && opts.type == 1) {

  _ul.addClass('horizontal');

  } else {

  var _level = getLevel(pid);

  _level > 0 && _ul.hide();

  _ul.addClass('vertical');

  if (_level > opts.type)

  _ul.addClass('offset');

  }

  return _ul;

  }

  //返回下级数据数组

  function getData(pid) {

  var _data = [];

  _tempMenuData = $.grep(_tempMenuData, function (_d) {

  if (_d.pid == pid) {

  _data.push(_d);

  return true;

  }

  return false;

  }, true);

  return _data;

  }

  return this.each(function () {

  var me = $(this);

  me.addClass('ctcx-menu');

  if (opts.data != null && opts.data.length > 0) {

  $.merge(_tempMenuData, opts.data);

  me.append(getHtml(null));

  } else {

  me.find('.item-has-children').each(function () {

  var self = $(this);

  var _ul = self.children('ul');

  _ul.hide();

  self.bind({

  mouseover: function () {

  _ul.show();

  },

  mouseout: function () {

  _ul.hide();

  }

  });

  });

  }

  });

  }

  //设置默认参数

  $.fn.menu.defaults = {

  type: 1, //菜单的显示方式(主要是指第一级是横向还是纵向,默认横向1,纵向0)

  /*

  data:动态生成菜单的数组数据,如果指定的此数据则会以此数据填充菜单(菜单内原有数据被替代)

  数据格式:[menu,menu,...]

  menu对象格式:{ id: 1, pid: null, n: '菜单名称1', url: '#', fn:回调函数 }

  */

  data: null

  }

  })(jQuery);

  调用JS代码

  

复制代码 代码如下:

  View Code

  $(function () {

  var _menuData = [

  { id: 1, pid: null, n: '菜单名称1', url: '#' },

  { id: 2, pid: null, n: '菜单名称2', url: '#' },

  { id: 3, pid: null, n: '菜单名称3', url: '#' },

  { id: 4, pid: null, n: '菜单名称4', url: '#' },

  { id: 5, pid: null, n: '菜单名称5', url: '#' },

  { id: 6, pid: 3, n: '菜单名称6', url: '#' },

  { id: 7, pid: 3, n: '菜单名称7', url: '#' },

  { id: 8, pid: 3, n: '菜单名称8', url: '#' },

  { id: 9, pid: 3, n: '菜单名称9', url: '#' },

  { id: 10, pid: 9, n: '菜单名称10', url: '#' },

  { id: 11, pid: 9, n: '菜单名称11', url: '#' },

  { id: 12, pid: 9, n: '菜单名称12', url: '#' },

  { id: 13, pid: 9, n: '菜单名称13', url: '#' },

  { id: 14, pid: 13, n: '菜单名称14', url: '#' },

  { id: 15, pid: 1, n: '菜单名称15', url: '#' }

  ];

  $('#dynamic-menu1').menu({ type: 0, data: _menuData });

  $('#dynamic-menu2').menu();

  $('#dynamic-menu3').menu();

  });

  HTML

  

复制代码 代码如下:

  View Code

  <div id="dynamic-menu3" class="ctcx-menu">

  <ul class="horizontal">

  <li><a href="#"><span>一级菜单1</span></a></li>

  <li><a href="#"><span>一级菜单2</span></a></li>

  <li class="item-has-children">

  <a href="#"><span>一级菜单3</span></a>

  <ul class="vertical">

  <li><a href="#"><span>二级菜单1</span></a></li>

  <li><a href="#"><span>二级菜单2</span></a></li>

  <li><a href="#"><span>二级菜单3</span></a></li>

  <li class="item-has-children">

  <a href="#"><span>二级菜单4</span></a>

  <ul class="vertical offset">

  <li><a href="#"><span>三级菜单1</span></a></li>

  <li><a href="#"><span>三级菜单2</span></a></li>

  <li><a href="#"><span>三级菜单3</span></a></li>

  <li><a href="#"><span>三级菜单4</span></a></li>

  <li><a href="#"><span>三级菜单5</span></a></li>

  </ul>

  </li>

  <li><a href="#"><span>二级菜单5</span></a></li>

  </ul>

  </li>

  <li><a href="#"><span>一级菜单4</span></a></li>

  <li><a href="#"><span>一级菜单5</span></a></li>

  </ul>

  </div>

  <div id="dynamic-menu1" class="ctcx-menu" style="margin-top:30px;"></div>

  <div id="dynamic-menu2" class="ctcx-menu" style="margin-top:60px;">

  <ul class="vertical">

  <li><a href="#"><span>一级菜单1</span></a></li>

  <li><a href="#"><span>一级菜单2</span></a></li>

  <li class="item-has-children">

  <a href="#"><span>一级菜单3</span></a>

  <ul class="vertical offset">

  <li><a href="#"><span>二级菜单1</span></a></li>

  <li><a href="#"><span>二级菜单2</span></a></li>

  <li><a href="#"><span>二级菜单3</span></a></li>

  <li class="item-has-children">

  <a href="#"><span>二级菜单4</span></a>

  <ul class="vertical offset">

  <li><a href="#"><span>三级菜单1</span></a></li>

  <li><a href="#"><span>三级菜单2</span></a></li>

  <li><a href="#"><span>三级菜单3</span></a></li>

  <li><a href="#"><span>三级菜单4</span></a></li>

  <li><a href="#"><span>三级菜单5</span></a></li>

  </ul>

  </li>

  <li><a href="#"><span>二级菜单5</span></a></li>

  </ul>

  </li>

  <li><a href="#"><span>一级菜单4</span></a></li>

  <li><a href="#"><span>一级菜单5</span></a></li>

  </ul>

  </div>

  七.下载

  点击这里 下载使用例子,和所有文件。