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
};
- keydown
keyCode速查表
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')
}
网友评论