ITPub博客

首页 > IT职业 > IT生活 > 基于jQuery的下拉菜单插件,诸位上眼!!!

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

IT生活 作者:socall 时间:2021-09-09 09:47:21 0 删除 编辑

前言


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

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

应用背景


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

图片描述

图片描述

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

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

③ 按钮类应用

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

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

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

集中展示


图片描述

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

View Code

 1 html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2  3  4      5     14     15     16     69 70 71 72 73 
74 点击按钮出现下拉菜单75 
76 
77 
78  79 80 81 
82 
83   
84 鼠标滑动85 
86 87 88 

 

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 = $('
  • ');        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 = $('
      ')            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 = $('
        ');    $('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 html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  2   3   4       5      86      87      88     159 160 161 162 点击按钮出现下拉菜单163 
        164 
        165 
        166 167 滑动按钮出现下拉菜单168 
        169 
        170 
        171 172 点击文本出现下拉菜单173 
        174 
        175 
        176 177 <!--178     给用户发短信179     180         
      • 短信选中用户
      • 181         
      • 短信全部用户
      • 182         
      • 短信未发送用户
      • 183     184 
      • -->185 186 187 188 189 /// 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 = '' + toggleText + '';224     } else {225         toggleEl = '';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 = $('
          ');238     container.append(item_container);239     for (var i in drop_items) {240         var item = drop_items[i];241         var tmp = $('
        • ');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 };

           

           

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

           

           

        • 来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/3536/viewspace-2812378/ ,如需转载,请注明出处,否则将追究法律责任。

          上一篇: Scroller的应用
          请登录后发表评论 登录
          全部评论

          注册时间:2019-08-30

          最新文章