UNPKG

lu2

Version:

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

390 lines (354 loc) 13.3 kB
/** * @Follow.js * @author zhangxinxu * @version * @Created: 15-06-25 * @edited: 17-06-19 */ (function (global, factory) { if (typeof define === 'function' && (define.amd || define.cmd)) { define(factory); } else { global.Follow = factory(); } }(this, function (require) { if (typeof require == 'function') { require('common/ui/Enhance'); } /** * 绝对定位元素的定位效果 * 针对所有浏览器 * 自动含边界判断 * 可用在DropDown, Tips等组件上 * 支持链式调用和模块化调用 * @example * $().follow(trigger, options); * new Follow(trigger, target, options); * 文档见:http://www.zhangxinxu.com/wordpress/?p=1328 position()方法 **/ $.fn.follow = function(trigger, options) { var defaults = { offsets: { x: 0, y: 0 }, // trigger-target position: '4-1', // 边缘位置自动调整 edgeAdjust: true }; var params = $.extend({}, defaults, options || {}); return $(this).each(function() { var target = $(this); if (trigger.length == 0) { return; } var pos, triL, triT, tarL, tarT; var triH = 0; var triW = 0; var tarH = target.data('height'); var tarW = target.data('width'); //缓存目标对象高度,宽度,提高鼠标跟随时显示性能,元素隐藏时缓存清除 if (!tarH) { tarH = target.outerHeight(); } if (!tarW) { tarW = target.outerWidth(); } var st = $(window).scrollTop(); var sl = $(window).scrollLeft(); var offX = parseInt(params.offsets.x, 10) || 0; var offY = parseInt(params.offsets.y, 10) || 0; var winWidth = $(window).width(); var winHeight = $(window).height(); var position = params.position; if (typeof position != 'string' && position.length == 2) { var left = position[0] + offX; var top = position[1] + offY; if (params.edgeAdjust == true) { if (left + tarW > winWidth + sl - 5) { left = winWidth + sl - 5 - tarW; } if (top + tarH > winHeight + st - 5) { top = winHeight + st - 5 - tarH; } } //浮动框显示 target.css({ position: 'absolute', left: left, top: top }).attr('data-align', '3-1'); // z-index自动最高 if (target.zIndex) { target.zIndex(); } return; } pos = trigger.offset(); triH = trigger.outerHeight(); triW = trigger.outerWidth(); triL = pos.left; triT = pos.top; // 合法的位置关系数据 var arrLegalPos = ['4-1', '1-4', '5-7', '2-3', '2-1', '6-8', '3-4', '4-3', '8-6', '1-2', '7-5', '3-2']; // 设定的对齐关系 var align = params.position; // 是否对齐匹配的标志量 var alignMatch = false; // 确定定位的方向 var strDirect; // 遍历,以确定设定的对齐是否有匹配 $.each(arrLegalPos, function(i, n) { if (n === align) { alignMatch = true; return false; } }); // 如果没有匹配的对齐方式,使用默认的对齐方式 if (!alignMatch) { align = defaults.position; } // 确定定位方位,是上下左右的哪个 var funDirect = function(a) { var dir = 'bottom'; //确定方向 switch (a) { case '1-4': case '5-7': case '2-3': { dir = 'top'; break; } case '2-1': case '6-8': case '3-4': { dir = 'right'; break; } case '1-2': case '8-6': case '4-3': { dir = 'left'; break; } case '4-1': case '7-5': case '3-2': { dir = 'bottom'; break; } } return dir; }; // 居中判断 var funCenterJudge = function(a) { if (a === '5-7' || a === '6-8' || a === '8-6' || a === '7-5') { return true; } return false; }; // 是否超出边界的判断 var funJudge = function(dir) { var totalHeight = 0; var totalWidth = 0; // 4个方位分别判断 if (dir === 'right') { totalWidth = triL + triW + tarW + offX; if (totalWidth > $(window).width()) { return false; } } else if (dir === 'bottom') { totalHeight = triT + triH + tarH + offY; if (totalHeight > st + $(window).height()) { return false; } } else if (dir === 'top') { totalHeight = tarH + offY; if (totalHeight > triT - st) { return false; } } else if (dir === 'left') { totalWidth = tarW + offX; if (totalWidth > triL) { return false; } } return true; }; //此时的方向 strDirect = funDirect(align); //边缘过界判断 if (params.edgeAdjust) { //根据位置是否溢出显示界面重新判定定位 if (funJudge(strDirect)) { //该方向不溢出 (function() { if (funCenterJudge(align)) { return; } var obj = { top: { right: '2-3', left: '1-4' }, right: { top: '2-1', bottom: '3-4' }, bottom: { right: '3-2', left: '4-1' }, left: { top: '1-2', bottom: '4-3' } }; var o = obj[strDirect]; var name; if (o) { for (name in o) { if (!funJudge(name)) { align = o[name]; } } } })(); } else { //该方向溢出 (function() { if (funCenterJudge(align)) { var center = { '5-7': '7-5', '7-5': '5-7', '6-8': '8-6', '8-6': '6-8' }; align = center[align]; } else { var obj = { top: { left: '3-2', right: '4-1' }, right: { bottom: '1-2', top: '4-3' }, bottom: { left: '2-3', right: '1-4' }, left: { bottom: '2-1', top: '3-4' } }; var o = obj[strDirect]; var arr = []; for (var name in o) { arr.push(name); } if (funJudge(arr[0]) || !funJudge(arr[1])) { align = o[arr[0]]; } else { align = o[arr[1]]; } } })(); } } // 是否变换了方向 var strNewDirect = funDirect(align); var strFirst = align.split('-')[0]; //确定left, top值 switch (strNewDirect) { case 'top': { tarT = triT - tarH; if (strFirst == '1') { tarL = triL; } else if (strFirst === '5') { tarL = triL - (tarW - triW) / 2; } else { tarL = triL - (tarW - triW); } break; } case 'right': { tarL = triL + triW ; if (strFirst == '2') { tarT = triT; } else if (strFirst === '6') { tarT = triT - (tarH - triH) / 2; } else { tarT = triT - (tarH - triH); } break; } case 'bottom': { tarT = triT + triH; if (strFirst == '4') { tarL = triL; } else if (strFirst === '7') { tarL = triL - (tarW - triW) / 2; } else { tarL = triL - (tarW - triW); } break; } case 'left': { tarL = triL - tarW; if (strFirst == '1') { tarT = triT; } else if (strFirst === '8') { tarT = triT - (tarH - triH) / 2; } else { tarT = triT - (tarH - triH); } break; } } if (params.edgeAdjust && funCenterJudge(align)) { // 是居中定位 // 变更的不是方向,而是offset大小 // 偏移处理 if (align == '7-5' || align == '5-7') { // 左右是否超出 if (tarL - sl < 0.5 * winWidth) { // 左半边,判断左边缘 if (tarL - sl < 0) { tarL = sl; } } else if (tarL - sl + tarW > winWidth) { tarL = winWidth + sl - tarW; } // 下面两个else if 判断上下是否超出 } else if (tarT - st < 0.5 * winHeight) { // 左半边,判断左边缘 if (tarT - st < 0) { tarT = st; } } else if (tarT - st + tarH > winHeight) { tarT = winHeight + st - tarH; } } if (strNewDirect == 'top' || strNewDirect == 'left') { tarL = tarL - offX; tarT = tarT - offY; } else { tarL = tarL + offX; tarT = tarT + offY; } //浮动框显示 target.css({ position: 'absolute', left: Math.round(tarL), top: Math.round(tarT) }).attr('data-align', align); // z-index自动最高 if (target.zIndex) { target.zIndex(); } }); }; var Follow = function(trigger, target, options) { target.follow(trigger, options); }; // Follow.prototype.hide = function() { // target.remove(); // }; return Follow; }));