现在的位置: 首页 > 综合 > 正文

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

2012年06月10日 ⁄ 综合 ⁄ 共 7539字 ⁄ 字号 评论关闭

前言


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

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

应用背景


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

① 鼠标点击某个文本框时出现下拉菜单

② 常用的操作鼠标划上出现下拉菜单

③ 按钮类应用

我们会用到这种功能往往原因是因为地方小了,按钮多了,这往往说明产品设计一般出问题了。。。 但是,我辈屁民豪不关注产品(没资格插手),所以需要完成以上功能;

其实总的来说,这些功能还是非常实用的。

于是,为了应对以上场景,我工作中先是做了一个,然后又遇到了,然后又遇到了,所以最后就写了这么一个东西。

集中展示


几个功能放到一起了,前端代码如下:

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);
}

 

难点&后续


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

① 菜单展开后如何关闭

② 多级菜单如何处理

不完善的级联效果

③ 事件如何回调

最后做出了这个比较简陋的东东。。。。

但是做完后也发现了一些问题:

① 像这种菜单在最左最下出现时没有解决;

② 然后菜单项过多时候也没有出现像select的滚动条;

③ 由于个人水平,整个代码的质量亦有问题;

④ 开始也考虑了异步数据加载的问题,但是着实有点难便放弃了,功能代码有一点,有兴趣的同学可以看看:

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

抱歉!评论已关闭.