博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于jQuery的下拉菜单插件,诸位上眼!!!
阅读量:6272 次
发布时间:2019-06-22

本文共 14037 字,大约阅读时间需要 46 分钟。

前言


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

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

应用背景


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

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

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

③ 按钮类应用

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

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

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

集中展示


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

View Code
1  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   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
        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 };

           

           

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

           

           

          你可能感兴趣的文章
          dojo.mixin(混合进)、dojo.extend、dojo.declare
          查看>>
          虚拟机克隆之后无法正确获取静态ip
          查看>>
          Java 连接Kafka报错java.nio.channels.ClosedChannelExcep
          查看>>
          字符设备驱动程序——poll机制介绍
          查看>>
          Markdown使用
          查看>>
          iOS - cocoapods/pod
          查看>>
          Apache+Tomcat(windows环境下)整合
          查看>>
          Java程序员应该收藏的书籍
          查看>>
          小菜学设计模式——策略模式
          查看>>
          Python 数据类型
          查看>>
          iOS--环信集成并修改头像和昵称(需要自己的服务器)
          查看>>
          PHP版微信权限验证配置,音频文件下载,FFmpeg转码,上传OSS和删除转存服务器本地文件...
          查看>>
          教程前言 - 回归宣言
          查看>>
          PHP 7.1是否支持操作符重载?
          查看>>
          Vue.js 中v-for和v-if一起使用,来判断select中的option为选中项
          查看>>
          jquery特效网站
          查看>>
          Java中AES加密解密以及签名校验
          查看>>
          定义内部类 继承 AsyncTask 来实现异步网络请求
          查看>>
          VC中怎么读取.txt文件
          查看>>
          七天学会ASP.NET MVC (四)——用户授权认证问题
          查看>>