美文网首页
Bootstrap插件解析2 下拉菜单

Bootstrap插件解析2 下拉菜单

作者: 波拉拉 | 来源:发表于2020-03-12 16:50 被阅读0次

https://www.php.cn/js-tutorial-411656.html

1 整体结构

(function ($) {
    'use strict';
    //构造函数
    var Dropdown=function () {};
    //静态变量
    Dropdown.VERSION = '3.3.7';
    // 工具函数
    function getParent(){}
    function clearMenus(){}
    // 原型方法
    Dropdown.prototype.toggle = function (e) {};
    Dropdown.prototype.keydown = function (e) {};
    // Plugin插件入口
    function Plugin(option) {}
    var old = $.fn.dropdown;
    $.fn.dropdown             = Plugin;//暴露插件
    $.fn.dropdown.Constructor = Dropdown;//指向原构造函数
    $.fn.dropdown.noConflict = function () {};//防冲突处理
    // data-api实现插件
    $(document) .on('click.bs.dropdown.data-api', clearMenus)
})(jQuery);

2 插件入口

  function Plugin(option) {
    return this.each(function () {
      var $this = $(this);
      var data  = $this.data('bs.dropdown');//提取实例化的对象
      //如果没有就new一个。保存在"data-bs.dropdown"
      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)));
      //如果选项是字符串,就执行原型上的方法
      if (typeof option == 'string') data[option].call($this)
    })
  }

  var old = $.fn.dropdown;

  $.fn.dropdown             = Plugin;//暴露插件接口
  $.fn.dropdown.Constructor = Dropdown;//静态变量指向原构造函数


  //防冲突处理

  $.fn.dropdown.noConflict = function () {
    $.fn.dropdown = old;
    return this
  };

3 data-api实现+构造函数+静态变量

  • data-api实现插件功能
  $(document)
    //  先关闭所有的下拉菜单
    .on('click.bs.dropdown.data-api', clearMenus)
    //  如果有form 就阻止冒泡
    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
    //  给按钮点击绑定原型上的切换事件
    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
    // 给按钮按下绑定原型上的keydown事件
    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
    //  给dropdown-menu按下绑定原型上的keydown事件
    .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
  • 构造函数+静态变量
 var backdrop = '.dropdown-backdrop';//苹果移动设备上使用
  var toggle   = '[data-toggle="dropdown"]';//切换按钮
  var Dropdown = function (element) {
    $(element).on('click.bs.dropdown', this.toggle);//实例化时,也会绑定函数
  };

  Dropdown.VERSION = '3.3.7';

4 工具函数

  //获取下拉菜单的父元素容器
  function getParent($this) {
    var selector = $this.attr('data-target');

    if (!selector) {
      selector = $this.attr('href');
      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, ''); // strip for ie7
    }

    var $parent = selector && $(selector);

    return $parent && $parent.length ? $parent : $this.parent()
  }
  //关闭所有下拉菜单
  function clearMenus(e) {
    if (e && e.which === 3) return;//鼠标右键不反应
    $(backdrop).remove();
    $(toggle).each(function () {//遍历所有切换按钮
      var $this         = $(this);
      var $parent       = getParent($this);//获取父元素
      var relatedTarget = { relatedTarget: this };

      if (!$parent.hasClass('open')) return;//没有open,直接返回
        // 点击的是input、textarea就返回
      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return;
      // 触发hide事件
      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget));
      //取消默认行为返回
      if (e.isDefaultPrevented()) return;
      $this.attr('aria-expanded', 'false');
      //父元素添加open,触发hidden事件
      $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
    })
  }

5 原型方法

  • toggle切换
Dropdown.prototype.toggle = function (e) {
    var $this = $(this);
    //如果禁用就不处理
    if ($this.is('.disabled, :disabled')) return;

    var $parent  = getParent($this);//找到父元素
    var isActive = $parent.hasClass('open');//显示与否的标识

    clearMenus();//先把所有的下拉菜单关闭

    //如果是移动设备,开启backdrop因为手机不支持点击事件委托
    if (!isActive) {
      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
        $(document.createElement('div'))
          .addClass('dropdown-backdrop')
          .insertAfter($(this))
          .on('click', clearMenus)
      }

      var relatedTarget = { relatedTarget: this };
      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget));

      if (e.isDefaultPrevented()) return;

      $this
        .trigger('focus')
        .attr('aria-expanded', 'true');

      $parent
        .toggleClass('open')//添加open类名
        .trigger($.Event('shown.bs.dropdown', relatedTarget));//触发shown事件
    }

    return false
  };
Dropdown.prototype.keydown = function (e) {
    //不是这些键上下箭头,esc,空格或者input+textarea不处理
    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return;

    var $this = $(this);

    e.preventDefault();//取消默认
    e.stopPropagation();//不冒泡

    if ($this.is('.disabled, :disabled')) return;//不处理

    var $parent  = getParent($this);//获取父元素
    var isActive = $parent.hasClass('open');//标识

    if (!isActive && e.which != 27 || isActive && e.which == 27) {
      if (e.which == 27) $parent.find(toggle).trigger('focus')
      return $this.trigger('click')
    }

    var desc = ' li:not(.disabled):visible a'
    var $items = $parent.find('.dropdown-menu' + desc)

    if (!$items.length) return

    var index = $items.index(e.target)

    if (e.which == 38 && index > 0)                 index--         // up
    if (e.which == 40 && index < $items.length - 1) index++         // down
    if (!~index)                                    index = 0

    $items.eq(index).trigger('focus')
  }

相关文章

网友评论

      本文标题:Bootstrap插件解析2 下拉菜单

      本文链接:https://www.haomeiwen.com/subject/teahjhtx.html