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

来源:互联网 发布:js实现视频播放 编辑:程序博客网 时间:2024/05/21 11:25

前言


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

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

应用背景


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

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

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

③ 按钮类应用

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

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

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

集中展示


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

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

 

 

所以先贴出来和各位看看,后续小生再行优化,希望能把这个功能做好!

 

 

原创粉丝点击