您的位置:首页 > Web前端 > JQuery

基于jQuery的下拉菜单插件

2013-03-29 23:47 525 查看

基于jQuery的下拉菜单插件,诸位上眼!!!

前言

很久没有写博客了,话说真的工作后才发现很多需要学的,有很多不足。

加之最近工作没有什么沉淀,现在团队又面临解散,反正闲着也是闲着,就自己写了个插件,反正水平就这样,当时自我总结吧!

应用背景

在我们工作中,经常会遇到这种需求:

View Code
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <html xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4     <title></title>
5     <style type="text/css">
6 body{ font: 12px/1.231 tahoma,arial,宋体; }
7 .drop_list_items , .drop_list_items ul { display: none; position:absolute; background-color: #FFFFFF; border: 1px solid #D2D2D2; padding: 2px; margin: 0; }
8 .drop_list_items li { margin: 0; padding: 4px; list-style: none; cursor: pointer; }
9 .drop_list_items li:hover { background-color: #3399FF; }
10 .drop_list_items li.parent_drop_list { padding: 4px; list-style: none; }
11 .drop_list_items li.cur_active { background-color: #3399FF; }
12 .z800 { z-index: 800; }
13     </style>
14     <script type="text/javascript" src="http://www.cnblogs.com/jquery-1.7.1.min.js"></script>
15     <script src="DropList.js" type="text/javascript"></script>
16     <script type="text/javascript">
17
18         //方案一
19         $(document).ready(function () {
20             new DropList({
21                 id: 'click_btn_drop',
22                 dropItems: [
23                                 ['短信选定用户', 'select'],
24                                 ['短信全部用户', 'all'],
25                                 ['短信未发送用户用户', 'all_else']
26                             ],
27                 func: function (e, scope, listEl) {
28                     var el = $(this);
29                     alert(el.html());
30                     scope.closeList();
31                     var s = '';
32                 }
33             });
34
35             new DropList({
36                 id: 'div1',
37                 open: '1',
38                 close: '1',
39                 dropItems: [
40                     ['昵称'],
41                     ['姓名'],
42                     ['性别'],
43                     ['联系方式']
44                 ],
45                 func: function (e, scope, listEl, toggleEl) {
46                     var el = $(this);
47                     scope.closeList();
48                     toggleEl.val(el.html());
49                 }
50             });
51
52             new DropList({
53                 id: 'click_text_drop',
54                 dropItems: [
55                     ['昵称'],
56                     ['姓名'],
57                     ['性别'],
58                     ['联系方式']
59                 ],
60                 func: function (e, scope, listEl, toggleEl) {
61                     var el = $(this);
62                     scope.closeList();
63                     toggleEl.val(el.html());
64                 }
65             });
66
67         });
68     </script>
69 </head>
70 <body>
71
72
73 <div id="click_btn_drop"  style=" width:140px;" >
74 点击按钮出现下拉菜单
75 </div>
76 <br />
77 <br />
78
79
80 <input id="click_text_drop"  type="text" />
81 <br />
82 <br />
83   <div id="div1"  style=" width:140px;" >
84 鼠标滑动
85 </div>
86
87 </body>
88 </html>


js代码:

View Code
var DropList = function (opts) {
if (!opts.id) {
alert('请指定触发展开事件的元素id');
return false;
}
//触发展开元素id
this.toggleId = opts.id;
this.toggleEl = opts.id ? $('#' + opts.id) : $('body');
this.key = opts.id ? opts.id + '_list' : new Date().getTime();
this.open = opts.open || 'click'; //展开菜单方式 mousein
this.close = opts.close || 'click'; //关闭菜单方式 mouseleave

//this.initShow = false; //判断是否初始化出现菜单绑定事件

/*下拉菜单数据,可能出现多级菜单数据格式:
[['v', 'k', []], ['v', {}, []],
['v', 'k', [['v', 'k', []], ['v', 'k', []]]
]
*/
this.dropItems = opts.dropItems || null;
this.loadData = opts.loadData; //用于异步加载下拉菜单数据//具有层级关系
this.listEl = null;
this.func = opts.func || null; //点击时的事件处理
//同步方式加载
if (this.dropItems) {
this.initDropItems();
this.eventBind();
} else {

}
};

DropList.prototype.closeList = {};

DropList.prototype.dropItemLoad = function (data, el) {
for (var i in data) {
var item = data[i];
var tmp = $('<li></li>');
el.append(tmp); //标签已装载
if (item[0]) {
tmp.html(item[0]);
}
if (item[1] || typeof item[1] == 'number') {
if (typeof item[1] == 'string' || typeof item[1] == 'number') {
tmp.attr('id', item[1]);
} else {
for (_k in item[1]) {
tmp.attr(_k, item[1][_k]);
}
}
}
if (item[2] && item[2]['length']) {//此处需要递归
var child = $('<ul ></ul>')
tmp.append(child);
tmp.addClass('parent_drop_list');
this.dropItemLoad(item[2], child);
}
}
};

//['v', 'k', []]
DropList.prototype.initDropItems = function () {
var scope = this;
var dropItems = scope.dropItems;
var listEl = $('<ul class="drop_list_items" id="' + scope.key + '"></ul>');
$('body').append(listEl);
scope.dropItemLoad(dropItems, listEl);
scope.listEl = listEl;
};

DropList.prototype.closeList = function () {
var listEl = this.listEl;
listEl.find('li').removeClass('cur_active');
listEl.find('ul').hide();
listEl.hide();
};

DropList.prototype.eventBind = function () {
var scope = this;
var listEl = scope.listEl;
var toggleEl = scope.toggleEl;
var open = scope.open;
var close = scope.close;
var func = scope.func;

var obj_len = function (o) {
var len = 0;
for (var k in o) {
len++;
}
return len;
};

var func_cls = function () {
if (close == 'click') {
$(document).click(function (e) {
var el = $(e.target);
var is_el = false;
//判断父元素是否为
while (el.attr('id') != scope.key) {
if (el.is("ul") || el.is('li')) {
is_el = true;
el = el.parent();
} else {
break;
}
}
if (el.attr('id') == scope.toggleId) {
is_el = true;
}
if (!is_el) {
scope.closeList();
if (scope.closeList[scope.toggleId])
delete scope.closeList[scope.toggleId];
if (obj_len(scope.closeList) == 0)
$(document).unbind('click');
var s = '';
}
});
} else {
listEl.mouseleave(function (e) {
scope.closeList();
if (scope.closeList[scope.toggleId])
delete scope.closeList[scope.toggleId];
listEl.unbind('mouseleave');
});
}
};

//确认弹出层位置
var func_init_pos = function (el) {
var offset = el.offset();
var h = el.height();
var p_top = el.css('padding-top');
var p_bottom = el.css('padding-bottom');
listEl.css('min-width', (parseInt(el.css('width')) + parseInt(el.css('padding-left')) + parseInt(el.css('padding-right')) - 6) + 'px')
listEl.css('left', parseInt(offset.left) + 'px');
listEl.css('top', (parseInt(offset.top) + parseInt(h) + parseInt(p_top) + parseInt(p_bottom)) + 'px');
};

if (open == 'click') {
toggleEl.unbind('click').click(function (e) {
var el = $(this);
var drop_list_items = $('.drop_list_items');
func_init_pos(el);
drop_list_items.removeClass('z800');
listEl.addClass('z800');
listEl.show();
func_cls();
scope.closeList[scope.toggleId] = 1;
//e.stopPropagation(); //阻止冒泡
});
} else {
toggleEl.unbind('mouseenter').mouseenter(function (e) {
var el = $(this);
var drop_list_items = $('.drop_list_items');
func_init_pos(el);
drop_list_items.removeClass('z800');
listEl.addClass('z800');
listEl.show();
func_cls();
//e.stopPropagation(); //阻止冒泡
});
}

listEl.delegate('li', 'mouseenter', function (e) {
var el = $(this);
listEl.find('li').removeClass('cur_active');
listEl.find('ul').hide();
el.addClass('cur_active');
el.children().show();

el = el.parent();
while (el.attr('id') != scope.key) {
if (el.is("li")) {
el.addClass('cur_active');
}
if (el.is('ul')) {
el.show();
}
el = el.parent();
}
e.stopPropagation();
});

if (func && typeof func == 'function') {
listEl.delegate('li', 'click', function (e) {
func.call(this, e, scope, listEl, toggleEl);
e.stopPropagation();
});
}
};

function initNewDrop(opts) {
new DropList(opts);
}


难点&后续

做的过程中还是遇到了几个问题的,比如:

① 菜单展开后如何关闭

② 多级菜单如何处理

不完善的级联效果View Code
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <html xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4     <title></title>
5     <style type="text/css">
6         *
7         {
8           margin:0;
9         }
10         body
11         {
12             font: 12px/1.231 tahoma,arial,宋体;
13         }
14         div
15         {
16           width:160px;
17           margin:5px;
18         }
19
20         .drop_btn ul
21         {
22             position:absolute;
23             background-color: #FFFFFF;
24             border: 1px solid #D2D2D2;
25             padding: 2px;
26             line-height: 18px;
27             display: none;
28             top: 25px;
29             z-index: 500;
30
31         }
32
33         .drop_btn li
34         {
35             list-style: none;
36         }
37         .drop_btn_toggle
38         {
39             background: url("http://shz.qq.com/statics/images/button.png") repeat-x scroll 0 0 #E5E5E5;
40             border: 1px solid #999999;
41             box-shadow: 0 1px 0 #E5E5E5;
42             border-radius: 3px;
43             cursor: pointer;
44             height: 28px;
45             line-height: 28px;
46             *height: 18px;
47             *line-height: 18px;
48             padding: 3px 6px;
49             vertical-align: middle;
50             zoom:1;
51         }
52         .drop_btn_open .drop_btn_toggle
53         {
54             background: url("http://shz.qq.com/statics/images/button_selected.png") repeat-x scroll 0 0 #B4B4B4;
55             border-color: #CCCCCC #B1B1B1 #AFAFAF #BEBEBE;
56             color: #515151;
57         }
58         .drop_btn_toggle .icon
59         {
60             border-left: 4px dashed transparent;
61             border-right: 4px dashed transparent;
62             border-top: 4px solid;
63             display: inline-block;
64             width: 0;
65             height: 0;
66             margin: 11px 0 0 4px;
67             *margin: 6px 0 0 4px;
68             overflow: hidden;
69             vertical-align: top;
70         }
71
72         div.drop_btn_open ul
73         {
74             display: block;
75         }
76         .drop_btn li
77         {
78             padding: 2px;
79             cursor: pointer;
80         }
81         .drop_btn li:hover
82         {
83             background-color: #3399FF;
84         }
85     </style>
86     <script type="text/javascript" src="http://www.cnblogs.com/jquery-1.7.1.min.js"></script>
87     <script src="DropList.js" type="text/javascript"></script>
88     <script type="text/javascript">
89
90         //方案一
91         $(document).ready(function () {
92             var click = new DropList({
93                 id: 'click_btn_drop',
94                 toggleText: '给用户发送短信',
95                 openType: 'move',
96                 drop_items: [
97                     { id: 'select', text: '短信选定用户' },
98                     { id: 'all', text: '短信全部用户' },
99                     { id: 'all_else', text: '短信未发送用户用户' }
100                 ],
101                 func: function (e, container) {
102                     var el = $(this);
103                     alert(el.html())
104                     var s = '';
105                 }
106             });
107
108             var move = new DropList({
109                 id: 'move_btn_drop',
110                 toggleText: '给用户发送短信',
111
112                 loadData: function (callBack) {
113                     var scope = this;
114                     $.get('Handler.ashx', function (data) {
115                         if (data && typeof data == 'string') {
116                             data = eval('(' + data + ')');
117                         }
118                         data = data.data;
119                         var param = [];
120                         param.push({ text: '报名人数:' + data.reg_num });
121                         var type = data.notice;
122                         if (type == 0) {
123                             msg = '不发送短信';
124                         } else if (type == 1) {
125                             msg = '自动短信';
126                         } else if (type == 3) {
127                             msg = '手动短信';
128                         }
129                         param.push({ text: '短信类型:' + msg });
130                         param.push({ text: '<a href="#">自动短信条数:' + data.sms_auto_count + '</a>'});
131                         param.push({ text: '<a href="http://www.baidu.com/" target="_blank">手动短信条数:' + data.sms_manual_count });
132
133                         scope.drop_items = param;
134                         callBack();
135
136                         var s = '';
137
138                     });
139                 }
140             });
141
142             var text = new DropList({
143                 id: 'click_text_drop',
144                 toggleType: 'text',
145                 drop_items: [
146                     { text: '昵称' },
147                     { text: '姓名' },
148                     { text: '性别' },
149                     { text: '联系方式' }
150                 ],
151                 func: function (e, container, toggleEl) {
152                     var el = $(this);
153                     toggleEl.val(el.html());
154                 }
155             });
156
157         });
158     </script>
159 </head>
160 <body>
161
162 点击按钮出现下拉菜单
163 <div id="click_btn_drop" class="drop_btn"></div>
164 <br />
165 <br />
166
167 滑动按钮出现下拉菜单
168 <div id="move_btn_drop" class="drop_btn"></div>
169 <br />
170 <br />
171
172 点击文本出现下拉菜单
173 <div id="click_text_drop" class="drop_btn"></div>
174 <br />
175 <br />
176
177 <!--<div class="drop_btn">
178     <a class="drop_btn_toggle"><span>给用户发短信<i class="icon"></i></span></a>
179     <ul class="drop_items">
180         <li>短信选中用户</li>
181         <li>短信全部用户</li>
182         <li>短信未发送用户</li>
183     </ul>
184 </div>-->
185
186 </body>
187 </html>
188
189 /// <reference path="http://www.cnblogs.com/jquery-1.7.1.min.js" />
190
191
192 var DropList = function (opts) {
193     this.id = opts.id || '';
194     //组件容器
195     this.container = $('#' + this.id);
196     //确定点击/滑动元素为按钮或者文本框(button/text)
197     this.toggleType = opts.toggleType || 'button';
198     this.toggleText = opts.toggleText || '请点击我';
199     //展开方式(点击/滑动)
200     this.openType = opts.openType || 'click';
201     this.drop_items = opts.drop_items || [];
202     this.loadData = opts.loadData;
203     this.func = opts.func;
204
205     if (this.drop_items && this.drop_items[0]) {
206         this.init();
207         this.eventBind();
208     } else {
209         if (this.loadData && typeof this.loadData == 'function') {
210             this.asyncLoad();
211         }
212     }
213 };
214
215 DropList.prototype.initBtn = function () {
216     var scope = this;
217     var container = scope.container;
218     var openType = scope.openType;
219     var toggleType = scope.toggleType;
220     var toggleText = scope.toggleText;
221     var toggleEl = '';
222     if (toggleType == 'button') {
223         toggleEl = '<a class="drop_btn_toggle"><span>' + toggleText + '<i class="icon"></i></span></a>';
224     } else {
225         toggleEl = '<input class="drop_text_toggle" type="text" />';
226     }
227     //获得点击元素用以添加事件
228     scope.toggleEl = $(toggleEl);
229     container.append(scope.toggleEl);
230 };
231
232 DropList.prototype.initDropItems = function () {
233     var scope = this;
234     var container = scope.container;
235     //组装下拉元素
236     var drop_items = scope.drop_items;
237     var item_container = $('<ul class="drop_items"></ul>');
238     container.append(item_container);
239     for (var i in drop_items) {
240         var item = drop_items[i];
241         var tmp = $('<li></li>');
242         if (item.id) {
243             tmp.attr('id', item.id);
244         }
245         if (item.text) {
246             tmp.html(item.text);
247         }
248         item_container.append(tmp);
249     }
250     //活动下拉菜单
251     scope.item_container = item_container;
252 };
253 DropList.prototype.init = function () {
254     //组装触发元素
255     var scope = this;
256     scope.initBtn();
257     scope.initDropItems();
258 };
259
260 DropList.prototype.eventBind = function () {
261     var scope = this;
262     var container = scope.container; //父容器
263     var toggleType = scope.toggleType; //触发方式
264     var toggleEl = scope.toggleEl; //点击元素
265     var item_container = scope.item_container; //下拉菜单
266     var openType = scope.openType;
267     var func = scope.func;
268
269     if (openType == 'click') {
270         toggleEl.click(function (e) {
271             container.addClass('drop_btn_open');
272
273             var el = $(this);
274             var offset = el.offset();
275             var s = el.height();
276             s = el.css('height');
277             var p_top = el.css('padding-top');
278             var p_bottom = el.css('padding-bottom');
279             item_container.css('min-width', el.css('width'))
280             item_container.css('left', parseInt(offset.left) + 'px');
281             item_container.css('top', (parseInt(offset.top) + parseInt(s) + parseInt(p_top) + parseInt(p_bottom)) + 'px');
282
283
284             //菜单出现后便阻止冒泡
285             e.stopPropagation();
286             $(document).unbind('click').click(function (ee) {
287                 if (container.hasClass('drop_btn_open')) {
288                     $('.drop_btn').removeClass('drop_btn_open');
289                 }
290                 $(document).unbind('click');
291             });
292         });
293     } else {
294         toggleEl.mousemove(function () {
295             container.addClass('drop_btn_open');
296
297             var el = $(this);
298             var offset = el.offset();
299             var s = el.height();
300             s = el.css('height');
301             var p_top = el.css('padding-top');
302             var p_bottom = el.css('padding-bottom');
303             item_container.css('min-width', el.css('width'))
304             item_container.css('left', parseInt(offset.left) + 'px');
305             item_container.css('top', (parseInt(offset.top) + parseInt(s) + parseInt(p_top) + parseInt(p_bottom)) + 'px');
306
307             $(document).unbind('click').click(function (ee) {
308                 if (container.hasClass('drop_btn_open')) {
309                     $('.drop_btn').removeClass('drop_btn_open');
310                 }
311                 $(document).unbind('click');
312             });
313         });
314     }
315
316     //    $("table").delegate("td", "hover", function () {
317     //        $(this).toggleClass("hover");
318     //    });
319     //处理选项处理事件
320     if (func && typeof func == 'function') {
321         item_container.delegate('li', 'click', function (e) {
322             func.call(this, e, container, toggleEl);
323         });
324     }
325 };
326
327 DropList.prototype.asyncLoad = function () {
328     var scope = this;
329     scope.initBtn();
330     scope.asyncBtnEventBind();
331
332     //    scope.initDropItems();
333 };
334
335 DropList.prototype.asyncBtnEventBind = function () {
336     var scope = this;
337     var container = scope.container; //父容器
338     var toggleType = scope.toggleType; //触发方式
339     var toggleEl = scope.toggleEl; //点击元素
340     var loadData = scope.loadData;
341     var openType = scope.openType;
342
343     //处理点击事件
344     if (openType == 'click') {
345         toggleEl.click(function (e) {
346             container.addClass('drop_btn_open');
347
348             var el = $(this);
349
350
351             //若是没有下拉菜单便添加数据
352             if (!scope.item_container) {
353                 //加载异步数据
354                 if (loadData && typeof loadData == 'function') {
355                     loadData.call(scope, function () {
356                         scope.initDropItems();
357                         scope.asyncDropEventBind(el);
358                     });
359                 }
360             }
361
362             //菜单出现后便阻止冒泡
363             e.stopPropagation();
364             $(document).unbind('click').click(function (ee) {
365                 if (container.hasClass('drop_btn_open')) {
366                     $('.drop_btn').removeClass('drop_btn_open');
367                 }
368                 $(document).unbind('click');
369             });
370         });
371     } else {
372         toggleEl.mousemove(function () {
373             if (container.hasClass('drop_btn_open')) {
374                 $('.drop_btn').removeClass('drop_btn_open');
375             }
376             $(document).unbind('click');
377         });
378     }
379 };
380
381 DropList.prototype.asyncDropEventBind = function (el) {
382     var scope = this;
383     var item_container = scope.item_container; //下拉菜单
384
385     var offset = el.offset();
386     var s = el.height();
387     s = el.css('height');
388     var p_top = el.css('padding-top');
389     var p_bottom = el.css('padding-bottom');
390     item_container.css('min-width', el.css('width'))
391     item_container.css('left', parseInt(offset.left) + 'px');
392     item_container.css('top', (parseInt(offset.top) + parseInt(s) + parseInt(p_top) + parseInt(p_bottom)) + 'px');
393
394     var func = scope.func;
395
396     //    $("table").delegate("td", "hover", function () {
397     //        $(this).toggleClass("hover");
398     //    });
399     //处理选项处理事件
400     if (func && typeof func == 'function') {
401         item_container.delegate('li', 'click', function (e) {
402             func.call(this, e, container, toggleEl);
403         });
404     }
405 };


所以先贴出来和各位看看,后续小生再行优化,希望能把这个功能做好!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: