原生JavaScript编写的查看大图组件

23 March 2016

JavaScript 组件 兼容

最近接手了一个商城项目,所以自己写了一个商品详情页面浏览商品大图的组件。虽然可能背负上重复造轮子的骂名。但我还是觉得有必要写的。 这起码也是自己的一个实践过程。兼容方面考虑到兼容IE8+,所以很多的代码都是在做兼容。

知识点

1.css设置兼容

ie8是不支持style来设置属性的。但ie8支持存在runtimeStyle属性对象。

    /**
    * 设置元素样式属性
    * @param {Object} element 元素
    * @param {Object} props   属性对象
    */
    function setCss(element , props){
      if( element.style ){
        for (var prop in  props ) {
          element.style[prop] = props[prop];
        };
      }else if(element.runtimeStyle){//ie8
        for (var prop in  props ) {
          element.runtimeStyle[prop] = props[prop];
        };
      }
    };

2.事件监听

事件监听ie8也是与正常的添加事件监听不同,所以需要使用attachEvent来处理事件监听。

    /**
     * 事件监听
     * @param {Object} element 元素
     * @param {Object} type    类型
     * @param {Object} fn      回调函数
     */
    function addEvent(element , type , fn){
      if( element.addEventListener ){//w3c
        element.addEventListener(type , fn);
      }else if( element.attachEvent ){//ie8
        element.attachEvent('on'+type , fn);
      }else{//其他
        element['on'+type] = fn;
      }
    };

3.获取元素相对于页面的左边距和上边距的距离

因为无法立即获得这个距离,所以只能通过遍历元素到body之间所有的元素的上边距或左边距进行选取最大值。 才可以获取得到最后元素距离页面左边距和上边距的距离。

    //获取距离距离top和left的距离
    function getOffset(element){
      var top = 0 , left = 0;
      if ( element ) {
        while ( element != body && element != document ){
          top = Math.max(+element.offsetTop , top);
          left = Math.max(+element.offsetLeft , left);
          element = element.parentNode;
        }
      }
      return {left:left , top:top};
    };

4.滚动距离

获取滚动条滚动的距离,这里主要的也是兼容问题。

IE Firefox Opera 标准模式下使用 document.documentElement.scrollLeft;

获取页面的水平滚动条位置,而混杂模式下则是使用 document.body.scrollLeft。

Chrome Safari 在两种文档模式下均使用 document.body.scrollLeft 获取页面的水平滚动条位置。

In IE 6 standards compatibility mode (where document.compatMode == “CSS1Compat”), use document.body.parentNode.scrollLeft and document.body.parentNode.scrollTop to get the scroll values of the html element.

    //获取屏幕滚动距离
    function getScrollXY(){
      return {
        x : window.scrollX  ||window.scrollLeft ||
            document.documentElement.scrollLeft || document.body.scrollLeft,
        y : window.scrollY || window.scrollTop|| 
            document.documentElement.scrollTop || document.body.scrollTop
      }
    };

全部源码

var B = (function(){
    var body = document.getElementsByTagName('body')[0];
    //对象
    function Blow(obj){
        this.blowbox = obj.blowbox;
        this.cursor = obj.cursor;
        this.blowmax = obj.blowmax;
        this.maxbox = obj.maxbox;
        this.blowsmall = obj.blowsmall;
        this.max = obj.max;
        this.pst = {};
    };
    //初始化
    Blow.prototype.init = function(){
        var blowmax = this.blowmax ,
            blowbox = this.blowbox,
            cursor = this.cursor,
            max = this.max , 
            blowsmall = this.blowsmall,
            maxbox = this.maxbox,
            pst = this.pst;
        
        setCss(blowmax , {width : max*2+'px' , height:max*2+'px'});
        addEvent(blowbox , 'mousemove' , function(e){
            setCss(maxbox , {display: 'block'});
            pst = getPosition(e,max , blowbox);
            setCss(cursor , {top : pst.top+'px' , left:pst.left+'px'});
            showMax(pst , blowmax);
        }); 
        addEvent(blowbox, 'mouseout' , function(e){
            setCss(maxbox , {display: 'none'});
        });
        
    };
    /**
     * 事件监听
     * @param {Object} element 元素
     * @param {Object} type    类型
     * @param {Object} fn      回调函数
     */
    function addEvent(element , type , fn){
        if( element.addEventListener ){
            element.addEventListener(type , fn);
        }else if( element.attachEvent ){
            element.attachEvent('on'+type , fn);
        }else{
            element['on'+type] = fn;
        }
    };
    /**
     * 设置元素样式属性
     * @param {Object} element 元素
     * @param {Object} props   属性对象
     */
    function setCss(element , props){
        if( element.style ){
            for (var prop in  props ) {
                element.style[prop] = props[prop];
            };
        }else if(element.runtimeStyle){
            for (var prop in  props ) {
                element.runtimeStyle[prop] = props[prop];
            };
        }
    };
    //获取位置
    function getPosition(e , max , blowbox){
        var offset = getOffset(blowbox) , 
            xy = getScrollXY();
        var x = +(e.clientX-offset.left+xy.x) , 
            y = +(e.clientY-offset.top+xy.y);
        var left = x-max*0.25 > 0 ? x-max*0.25 : 0 , 
            top = y-max*0.25 > 0 ? y-max*0.25 : 0;
            
        left = left > max*0.5 ? max*0.5 : left ;
        top = top > max*0.5 ? max*0.5 : top ;
        
        return {left:left ,top:top};
    };
    //展示大图
    function showMax(pst , blowmax){
        var x = pst.left*2 , y = pst.top*2;
        if ( blowmax.style ){
            blowmax.style.marginLeft = -x +'px';
            blowmax.style.marginTop = -y+'px';
        }else if( blowmax.runtimeStyle ){
            blowmax.runtimeStyle.marginLeft = -x +'px';
            blowmax.runtimeStyle.marginTop = -y+'px';
        }
    };
    //获取距离距离top和left的距离
    function getOffset(element){
        var top = 0 , left = 0;
        if ( element ) {
            while ( element != body && element != document ){
                top = +element.offsetTop > top ? +element.offsetTop : top;
                left = +element.offsetLeft > left ? +element.offsetLeft : left;
                element = element.parentNode;
            }
        }
        return {left:left , top:top};
    };
    //获取屏幕滚动距离
    function getScrollXY(){
        return {
            x : window.scrollX || window.scrollLeft || document.documentElement.scrollLeft || document.body.scrollLeft,
            y : window.scrollY || window.scrollTop|| document.documentElement.scrollTop || document.body.scrollTop
        }
    };
    return {
        run : function(obj){
            return new Blow(obj).init();
        }
    }
})();

调用方式

//index.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>查看大图</title>
        <link rel="stylesheet" type="text/css" href="blow.css"/>
    </head>
    <body>
        <div class="blow-box">
            <div class="blow-small-box">
                <div class="blow-content-box" id="j_blow_box">
                    <div class="blow-img-box">
                        <img class="blow-small-img" id="j_blow_small" src="images/small.jpg"/>
                    </div>
                    <span class="blow-img-cursor" id="j_blow_cursor"></span>
                </div>
                <div class="blow-small-bar">
                    <ul class="blow-small-list">
                        <li class="blow-small-list-i"><img src="images/small.jpg"/></li>
                        <li class="blow-small-list-i"><img src="images/small.jpg"/></li>
                        <li class="blow-small-list-i"><img src="images/small.jpg"/></li>
                        <li class="blow-small-list-i"><img src="images/small.jpg"/></li>
                    </ul>
                </div>
            </div>
            <div class="blow-max-box" id="j_blow_max_box">
                <img src="images/max.jpg" id="j_blow_max"/>
            </div>
        </div>
    </body>
    <script src="blow.js"></script>
    <script>
        //手势
    var cursor = document.getElementById('j_blow_cursor'),
        //小图
        blowsmall = document.getElementById('j_blow_small'),
        //大图
        blowmax = document.getElementById('j_blow_max'),
        //大图box
        maxbox = document.getElementById('j_blow_max_box'),
        //小图box
        blowbox = document.getElementById('j_blow_box');
    
    //运行
    ;B.run({
        blowbox :blowbox,
        cursor : cursor,
        blowmax : blowmax,
        maxbox : maxbox,
        blowsmall : blowsmall,
        max : 464//大图大小
    })
    </script>
</html>

css代码如下:

.blow-box{
    width: 574px;
    height: 464px;
    position: relative;
    margin-left: 100px;
    margin-top: 400px;
}
.blow-small-box{
    width: 100%;
    height: 100%;
}
.blow-max-box{
    position: absolute;
    z-index: 99;
    right: -464px;
    top: 0;
    width: 464px;
    height: 464px;
    overflow: hidden;
}
.blow-content-box{
    width: 464px;
    height: 464px;
    float: left;
}
.blow-small-bar{
    width: 110px;
    height: 464px;
    overflow: hidden;
}
.blow-small-list{
    width: 82px;
    height: 464px;
    margin: 0;
    padding: 0;
}
.blow-small-list .blow-small-list-i{
    width: 78px;
    height: 78px;
    margin: 14px;
    border: 2px solid #47baac;
    list-style: none;
    overflow: hidden;
    cursor: pointer;
}
.blow-small-list .blow-small-list-i img{
    width: 78px;
    height: 78px;
}
.blow-content-box{
    width: 464px;
    height: 464px;
    overflow: hidden;
    position: relative;
}
.blow-img-box , .blow-small-img{
    width: 464px;
    height: 464px;
}
.blow-img-cursor{
    position: absolute;
    display: none;
    z-index: 2;
    top: 0;
    left: 0;
    width: 232px;
    height: 232px;
    cursor: move;
    background: url(images/blow.png) repeat transparent;
}
.blow-content-box:hover .blow-img-cursor{
    display: block;
}

案例

案例演示