/*!
* fLayer.js v1.0.1
* (c) 2016 Talent
* Date: 2016-12-26
* Support Broswer: IE9+ Firefox12+ Chrome4+ safair4+ Opera11.5+
*/
/**
* 参数解释:
* w:默认为当前的window 如果是框架内的请传入框架内的window
* doc:默认是当前的文档对象 如果需要改变请显示的传入
* zIndex:遮罩层的堆叠顺序,默认999
* backgroundColor:遮罩层的背景色,默认rgba(51, 51, 51, 0.44)
* copyBoolean:是否对元素深拷贝,默认为true 在无需使用元素定位高亮显示,这样一个遮罩的时候无需传入
* heightLightColor:在需要元素高亮的时候,传入以作为元素高亮的背景色 默认为#fff
* aimEle:需要遮罩的元素,默认是doc下的body
* allowScroll:是否允许滚动 默认为false
* showTop:在allowScroll为false时候有意义 表示需要定位的元素在视口中的距离顶部的高度,若直接就在视口中那么不起效果,若元素距离视口的最大距离小于该距离则也不起效果,此时元素将会在距离顶部为0px的地方进行展示
* showLeft:在allowScroll为false时候有意义 表示需要定位的元素在视口中的距离左边的高度,若直接就在视口中那么不起效果,若元素距离视口的最大距离小于该距离则也不起效果,此时元素将会在距离左边为0px的地方进行展示
*/
/**
* 返回值解析:
* dom:遮罩层元素
* remove:删除遮罩层的方法 无参
* lightEle:添加定位元素的方法
有参:selector 选择器
该方法不会判断是否之前已经生成了该元素的遮罩定位元素,会反复生成,但是由于定位一致,所以并不会有什么特殊的效果
该方法的返回值为一个对象:
{copyCon,copyEle,copyMark}
copyCon:包含拷贝元素的容器 copyEle:拷贝元素 copyMark:遮罩在拷贝元素上的遮罩层元素
关系:copyCon包含copyEle,copyMark
copyMark与copyEle平级
*/
/**
* 使用方法:
* 1.引入fLayer.js
* 2.var fLayer = fLayer(option);//此时才生成遮罩层
* 3.fLayer.lightEle(selector);//这时才会对元素进行定位复制并高亮显示
*/
/**
* 未测试过的场景:
* 1.iframe内
* 2.单个元素内部的遮罩 aimEle不是body的情况(此场景在V1.0.0中不支持,V1.0.0只支持body的遮罩)
* 3 doc不属于w的情况
* 4.有左右滚动的时候,不管是body允许滚动还是不允许滚动都未测试
*/
/**
* fLayer v1.0.1
* 修复问题:当元素处于视口的下方的时候,禁止滚动状态无法去定位被高亮元素 现在已经修复
* 发现的新问题:1.当元素只要有1px存在于当前视口中,都会判断其在视口中,不会进行重新定位,导致出现遮罩元素被遮住的现象
* 2.当被拷贝的元素有继承样式的时候,拷贝的元素并不会继承原本的样式。
* 例如被拷贝的元素继承了父元素的字体大小 16px 但在拷贝元素里面字体大小为默认值
*/
function fLayer(option) {
var w = (option.w == undefined ? window : w); //防止iframe,w即是需要document所在的浏览器对象实例
//var $ele = option.ele; //the element which need be show in mark layer
var doc = (option.doc == undefined ? w.document : option.doc); //the document which need
var zIndex = (option.zIndex == undefined ? 999 : option.zIndex);
var backgroundColor = (option.backgroundColor == undefined ? 'rgba(51, 51, 51, 0.44)' : option.backgroundColor);
var copyBoolean = (option.copyBoolean == undefined ? true : option.copyBoolean);
var heightLightColor = (option.heightLightColor == undefined ? '#fff' : option.heightLightColor);
var allowScroll = (option.allowScroll == undefined ? false : option.allowScroll);
var showTop = (option.showTop == undefined ? 10 : option.showTop);
var showLeft = (option.showLeft == undefined ? 10 : option.showLeft);
//获得窗口的大小 直接获取浏览器的视口大小
var _height = w.innerHeight;
var _width = w.innerWidth;
var _body = (option.aimEle == undefined ? doc.querySelector('body') : option.aimEle);
var _div = doc.createElement('div');
var _divStyle = _div.style;
var _cssText = 'width:' + _width + 'px;' + 'height:' + _height + 'px;z-index:' + zIndex +
';position:fixed;top:0px;left:0px;background: ' + backgroundColor + ';';
_divStyle.cssText = _cssText;
_body.appendChild(_div); //会返回添加的div
if (allowScroll == false) {
// _body.style.setProperty('overflow', 'hidden');
// _body.style.setProperty('overflow-x', 'hidden');
// _body.style.setProperty('overflow-y', 'hidden');
}
//获取元素对应于body的位置
var recursion = function (ele, offsetTop, offsetLeft) {
if (offsetTop == undefined) {
offsetTop = 0;
offsetLeft = 0;
}
offsetTop += ele.offsetTop;
offsetLeft += ele.offsetLeft;
if (ele.offsetParent != null) {
return recursion(ele.offsetParent, offsetTop, offsetLeft);
} else {
return {
top: offsetTop,
left: offsetLeft
};
}
};
//目前为止只支持一个ele在mark层上的展现,创建拷贝div
function createCopyCon(selector) {
var _ele = doc.querySelector(selector);
//获取元素的高度以及宽度(包括边框)
var _eleHight = _ele.offsetHeight;
var _eleWidth = _ele.offsetWidth;
//拷贝副本,为了防止ie中事件的拷贝,所以用一个div将其包裹起来
//同时用一个小型遮罩层将其包裹防止事件的点击以及触发,并给出背景色高亮色,默认为#fff
var _copyEle = _ele.cloneNode(copyBoolean); //默认深拷贝(ie中会拷贝事件)
_copyEle.style.setProperty('background-color', heightLightColor);
_copyEle.style.setProperty('margin', '0px', 'important'); //防止拷贝元素有margin 直接不允许有margin
var _copyCon = doc.createElement('div');
var _copyConMark = doc.createElement('div');
_copyCon.style.cssText = 'width:' + _eleWidth + 'px;height:' + _eleHight + 'px;position:absolute;';
_copyConMark.style.cssText = 'width:' + _eleWidth + 'px;height:' + _eleHight +
'px;position:absolute;top:0px;left:0px;'; //z-index:' + (zIndex + 1);
_copyCon.appendChild(_copyConMark);
_copyCon.appendChild(_copyEle);
return {
'copyCon': _copyCon,
'copyEle': _copyEle,
'copyMark': _copyConMark
};
// _div.appendChild(copyCon);
};
//计算高度,进行定位用的
function posEle(selector, copyCon) {
var _ele = doc.querySelector(selector);
var position = _ele.getBoundingClientRect(); //IE9+ 获取元素在视口的位置
//无需去判断位置,因为他定位的就是被拷贝元素自己所在的位置(相对于浏览器的) 无需考虑视口内,视口上,还是视口外
copyCon.style.setProperty('top', position.top + 'px');
copyCon.style.setProperty('left', position.left + 'px');
copyCon.style.setProperty('visibility', 'visible');
}
//当不允许滚动的时候直接去定位元素展示在视口里面 要去判断元素在哪:在视口里面,在视口上面,以及在视口下面
function oncePositon(selector, copyCon) {
var _ele = doc.querySelector(selector);
var position = _ele.getBoundingClientRect();
//判断被拷贝的元素在哪里
var where = eleIswhere(_ele);
switch (where) {
case 0:
_body.scrollTop = _body.scrollTop - (position.top > 0 ? position.top : -position.top);
_body.scrollLeft = _body.scrollLeft - (position.left > 0 ? position.left : -position.left);
if ((_body.scrollTop - showTop) > 0) {
_body.scrollTop = _body.scrollTop - showTop;
}
if ((_body.scrollLeft - showLeft) > 0) {
_body.scrollTop = _body.scrollLeft - showLeft;
}
oncePositon(selector, copyCon);
break;
case 1:
//视口内
copyCon.style.setProperty('top', position.top + 'px');
copyCon.style.setProperty('left', position.left + 'px');
copyCon.style.setProperty('visibility', 'visible');
break;
case 2:
var dis = position.top > position.bottom ? position.top : position.bottom;
_body.scrollTop = _body.scrollTop + dis - showTop;
oncePositon(selector, copyCon);
break;
}
// if (position.left > 0 && position.top > 0) {
// copyCon.style.setProperty('top', position.top + 'px');
// copyCon.style.setProperty('left', position.left + 'px');
// copyCon.style.setProperty('visibility', 'visible');
// } else {
// //到那个位置去 scrollTop scrollTop
// _body.scrollTop = _body.scrollTop - (position.top > 0 ? position.top : -position.top);
// _body.scrollLeft = _body.scrollLeft - (position.left > 0 ? position.left : -position.left);
// if ((_body.scrollTop - showTop) > 0) {
// _body.scrollTop = _body.scrollTop - showTop;
// }
// if ((_body.scrollLeft - showLeft) > 0) {
// _body.scrollTop = _body.scrollLeft - showLeft;
// }
// oncePositon(selector, copyCon);
// }
}
function eleIswhere(_ele) {
//元素相对于body的位置 如果小于scrollTop表示在视口上 如果大于scrollTop小于scrollTop+视口大小表示在视口内,如果大于crollTop+视口大小表示在视口下
var posBody = posFather(_ele);
if (posBody.top <= _body.scrollTop) {
return 0;
} else if (_body.scrollTop < posBody.top && posBody.top < (_body.scrollTop + w.innerHeight)) {
return 1;
} else {
return 2;
}
}
function posFather(_ele, top, left) {
if (top == undefined) {
top = 0;
left = 0;
}
if (_ele.offsetParent != null) {
top += _ele.offsetTop;
left += _ele.offsetLeft;
return posFather(_ele.offsetParent, top, left);
} else {
return {
top: top,
left: left
};
}
}
//当窗口变化的时候进行遮罩层高度的重新计算事件 必须要有
w.onresize = function () {
var _height = w.innerHeight;
var _width = w.innerWidth;
_divStyle.setProperty('height', _height + 'px', '');
_divStyle.setProperty('width', _width + 'px', '');
//TODO
}
//高亮元素并进行页面展示
var lightEle = function (selector) {
var resizeFun = '';
var copyObject = createCopyCon(selector);
var copyCon = copyObject.copyCon;
_div.appendChild(copyCon);
if (allowScroll == false) {
oncePositon(selector, copyCon);
resizeFun = oncePositon;
} else {
posEle(selector, copyCon);
resizeFun = posEle;
//鼠标的滚动事件
w.addEventListener('scroll', function () {
posEle(selector, copyCon);
});
}
//窗口大小的改变
w.addEventListener('resize', function () {
resizeFun(selector, copyCon);
});
//返回一个对象,包括里面的拷贝元素(copyEle),拷贝所在的容器(copyCon),以及拷贝元素上的遮罩层(copyMark)
return copyObject;
};
return {
'dom': _div, //遮罩层
'remove': function () {
_body.removeChild(_div); //removeChild只能移除直接属于自己的子元素,子元素内部的子元素无法进行移除
},
'lightEle': lightEle
};
}