fLayer遮罩层组件 V1.0.1

如下是fLayerV1.0.1的代码,随意使用以及修改,若有什么需求或者建议请评论或私信

/*!
 * 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
    };
}

猜你喜欢

转载自blog.csdn.net/javawebty/article/details/53897423