UNPKG

lu2

Version:

Simple and flexible UI component library based on native HTML and JavaScript

318 lines (275 loc) 9.4 kB
/** * @Drop.js * @author zhangxinxu * @version * Created: 15-06-30 */ (function (global, factory) { if (typeof define === 'function' && (define.amd || define.cmd)) { define(factory); } else { global.Drop = factory(); } }(this, function (require) { // require if (typeof require == 'function') { require('common/ui/Follow'); } else if (!$().follow) { if (window.console) { window.console.error('need Follow.js'); } return {}; } /* * 元素的下拉显示 */ /* * 支持jQuery API调用和模块化调用两种 * @example * $('trigger').drop(target, options); * or * new Drop(trigger, target, options); */ $.fn.drop = function(target, options) { return $(this).each(function() { var drop = $(this).data('drop'); if (!drop) { $(this).data('drop', new Drop($(this), target, options)); } }); }; /** * 实例方法 * @param {Object} trigger 触发元素,$()包装器元素类型 * @param {Object} target 显示的浮动定位元素,$()包装器元素类型 * @param {Object} options 可选参数 */ var Drop = function(trigger, target, options) { var defaults = { // 触发元素显示的事件, // 'null'直接显示;'hover'是hover方法;'click'是点击显示, // 新增'contextmenu'表示右键显示 eventType: 'null', // 实现点击或hover事件的委托实现 selector: '', offsets: { x: 0, y: 0 }, edgeAdjust: true, position: '7-5', onShow: $.noop, onHide: $.noop }; var params = $.extend({}, defaults, options || {}); var id = target.attr('id'); if (!id) { id = ('id_' + Math.random()).replace('0.', ''); target.attr('id', id); } if (params.selector == '') { trigger.attr({ 'data-target': id, 'aria-expanded': 'false' }); } // 元素暴露给实例 this.el = { trigger: trigger, target: target }; // 偏移 this.offsets = params.offsets; // 回调 this.callback = { show: params.onShow, hide: params.onHide }; // 位置 this.position = params.position; // 边缘调整 this.edgeAdjust = params.edgeAdjust; // 实例的显示状态 this.display = false; var drop = this; switch (params.eventType) { case 'null': { this.show(); break; } case 'hover': { // hover处理需要增加延时 var timerHover; // 同时,从trigger移动到target也需要延时,因为两者可能有间隙,不能单纯移出就隐藏 var timerHold; trigger.delegate(params.selector, 'mouseenter', function() { if (params.selector) { drop.el.trigger = $(this).attr({ 'data-target': id, 'aria-expanded': 'false' }); } // 显示的定时器 timerHover = setTimeout(function() { drop.show(); }, 150); // 去除隐藏的定时器 clearTimeout(timerHold); }); trigger.delegate(params.selector, 'mouseleave', function() { // 清除显示的定时器 clearTimeout(timerHover); // 隐藏的定时器 timerHold = setTimeout(function() { drop.hide(); }, 200); }); if (!target.data('dropHover')) { target.hover(function() { // 去除隐藏的定时器 clearTimeout(timerHold); }, function() { // 隐藏 timerHold = setTimeout(function() { drop.hide(); }, 100); }); target.data('dropHover', true); } // 键盘支持,原本使用focus事件,但并不利于键盘交互 trigger.delegate(params.selector, 'click', function(event) { // window.isKeyEvent表示是否键盘触发,来自Enhance.js if (window.isKeyEvent) { if (params.selector) { drop.el.trigger = $(this).attr({ 'data-target': id, 'aria-expanded': 'false' }); } // 点击即显示 if (drop.display == false) { drop.show(); } else { drop.hide(); } event.preventDefault(); } }); break; } case 'click': case 'contextmenu': { trigger.delegate(params.selector, params.eventType, function(event) { event.preventDefault(); // aria支持 if (params.selector) { drop.el.trigger = $(this).attr({ 'data-target': id, 'aria-expanded': 'false' }); } // 重复右键点击一直显示,非显隐切换 if (params.eventType == 'contextmenu') { drop.position = [event.pageX, event.pageY]; drop.show(); return; } // 点击即显示 if (drop.display == false) { drop.show(); } else { drop.hide(); } }); break; } } // 点击页面空白区域隐藏 $(document).click(function(event) { var clicked = event && event.target; if (!clicked || !drop || drop.display != true) return; var tri = drop.el.trigger.get(0); var tar = drop.el.target.get(0); if (tri && tar && clicked != tri && clicked != tar && tri.contains(clicked) == false && tar.contains(clicked) == false) { drop.hide(); } }); // 窗体尺寸改变生活的重定位 $(window).resize(function() { drop.follow(); }); return drop; }; /** * 下拉定位处理 * @return {Object} 返回当前实例对象 */ Drop.prototype.follow = function() { var target = this.el.target; var trigger = this.el.trigger; // 下拉必须是显示状态才执行定位处理 if (this.display == true && trigger.css('display') != 'none') { target.follow(trigger, { offsets: this.offsets, position: this.position, edgeAdjust: this.edgeAdjust }); } return this; }; /** * 下拉的显示处理 * @return {Object} 返回当前实例对象 */ Drop.prototype.show = function() { // target需要在页面中 var target = this.el.target; var trigger = this.el.trigger; // 如果target在内存中,append到页面上 if (target && $.contains(document.body, target.get(0)) == false) { $('body').append(target); } // 改变显示标志量 this.display = true; // 进行定位 target.css({ position: 'absolute', display: 'inline' }).addClass('ESC'); // aria trigger.attr({ 'aria-expanded': 'true' }); // 定位 this.follow(); // 显示回调处理 if ($.isFunction(this.callback.show)) { this.callback.show.call(this, trigger, target); } return this; }; /** * 下拉的隐藏处理 * @return {Object} 返回当前实例对象 */ Drop.prototype.hide = function() { var target = this.el.target; var trigger = this.el.trigger; // 隐藏下拉面板 target.hide().removeClass('ESC'); // aria trigger.attr({ 'aria-expanded': 'false' }); if (window.isKeyEvent) { trigger.focus(); } // 更改显示标志量 this.display = false; // 隐藏回调处理 if ($.isFunction(this.callback.hide)) { this.callback.hide.call(this, trigger, target); } return this; }; return Drop; }));