照片墙效果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
    * {margin: 0; padding: 0;}

    #ul1 { 360px; position: relative; margin: 10px auto; }
    #ul1 li{ 100px; height: 100px; float: left; list-style: none; margin: 10px; z-index: 1;}
    #ul1 .active{ border: 1px dashed red; }
    </style>
    <script type="text/javascript">
        window.onload=function(){
            var oUl=document.getElementById('ul1');
            var aLi=oUl.getElementsByTagName('li');
            var aPos=[];  //事先定义一个数组用来把li的位置存起来
            var iMinZindex=2;  //为了解决层级关系
            var i=0;
            //布局转换
            for(i=0; i<aLi.length; i++){
                aPos[i]={
                    left: aLi[i].offsetLeft,
                    top: aLi[i].offsetTop
                };  //以josn的方式存储每个li位置的坐标
            }

            for(i=0; i<aLi.length; i++){
                aLi[i].style.left=aPos[i].left+'px';
                aLi[i].style.top=aPos[i].top+'px';

                aLi[i].style.position='absolute';
                aLi[i].style.margin=0;

                aLi[i].index=i;  //设置每个li的index索引值
            }  //设置每个li的位置, 不能放在同一个循环里面

            //拖拽
            for(i=0; i<aLi.length; i++){
                setDrag(aLi[i]);
            }

            function setDrag(obj){

                obj.onmousedown=function(ev){
                    var oEvent=ev||event;

                    obj.style.zIndex=iMinZindex++;

                    var disX=oEvent.clientX-obj.offsetLeft;
                    var disY=oEvent.clientY-obj.offsetTop;

                    document.onmousemove=function(ev){
                        var oEvent=ev||event;

                        obj.style.left=oEvent.clientX-disX+'px';
                        obj.style.top=oEvent.clientY-disY+'px';

                        /*for(i=0; i<aLi.length; i++){
                            aLi[i].className=''; //先清空class
                            if(obj==aLi[i]) continue;  //跳过本身循环 因为和本身检测肯定是碰上的

                            if(cdTest(obj, aLi[i])){
                                aLi[i].className='active';
                            }
                        }*/
                        for(i=0; i<aLi.length; i++){
                            aLi[i].className='';
                        }
                        var oNer=findNearest(obj);

                        if(oNer){
                            oNer.className='active';
                        }
                    };

                    document.onmouseup=function(){
                        document.onmousemove=null;
                        document.onmouseup=null;

                        var oNer=findNearest(obj); //找到碰上的,并且找到最近的

                        if(oNer){ //碰到的时候
                            oNer.className='';  //让碰见的物体的样式为空
                            oNer.style.zIndex=iMinZindex++; //为了移动的时候在最上面移动
                            obj.style.zIndex=iMinZindex++;  //为了移动的时候在最上面移动

                            startMove(oNer, aPos[obj.index]); //被碰到的物体移动到拖拽的这个物体的位置上

                            startMove(obj, aPos[oNer.index]); //拖拽的物体移动到被碰到的物体oNer的物体上

                            var tmp=0; //交换index值
                            tmp=obj.index;
                            obj.index=oNer.index;
                            oNer.index=tmp;
                        }else{  //没有碰到的时候
                            startMove(obj, aPos[obj.index]  /*{left: aPos[obj.index].left, top: aPos[obj.index].top}*/);
                            //没有碰撞时恢复到原来的位置。利用apos数组事先存好的位置
                            //aPos 本身就是一个json可以直接用
                        }
                    };

                    clearInterval(obj.timer); //鼠标按下时把原来的定时器先清除掉
                    return false;  
                };
            };

            //碰撞检测
            function cdTest(obj1, obj2){   //九宫格原理
                var l1=obj1.offsetLeft;  //obj1的左边线
                var r1=obj1.offsetLeft+obj1.offsetWidth;  //obj1的右边线
                var t1=obj1.offsetTop;   //上边线
                var b1=obj1.offsetTop+obj1.offsetHeight; //下边线

                var l2=obj2.offsetLeft;  //obj1的左边线
                var r2=obj2.offsetLeft+obj1.offsetWidth;  //obj1的右边线
                var t2=obj2.offsetTop;   //上边线
                var b2=obj2.offsetTop+obj1.offsetHeight; //下边线

                if(r1<l2 || l1>r2 || b1<t2 || t1>b2){  //四种上下左右碰不到的情况
                    return false;
                }else{
                    return true;
                }
            }

            //找到碰上的,并且找到最近的
            function findNearest(obj){
                var iMin=9999999; //预先定义一个最大值 然后比较比这个小就赋值给他 求最小值
                var iMinIndex=-1;

                for(i=0; i<aLi.length; i++){
                    if(obj==aLi[i]) continue;  //如果是本身就跳出当次循环

                    if(cdTest(obj, aLi[i])){  //检测碰上的时候找最近的
                        var dis=getDis(obj, aLi[i]);  //求出距离

                        if(iMin>dis){  //把最小的赋值给iMin
                            iMin=dis;
                            iMinIndex=i; //并且记住位置
                        }
                    }    
                }

                if(iMinIndex==-1){  //如何没有改变iMinIndex的值说明没有碰撞任何物体
                    return null;  //返回空
                }else{
                    return aLi[iMinIndex];  //返回最近的那个值
                }
            }

            //计算两点间的距离利用勾股定理
            function getDis(obj1, obj2){
                var a=obj1.offsetLeft-obj2.offsetLeft;  //两个物体的左右距离
                var b=obj1.offsetTop-obj2.offsetTop; //两个物体的上下距离

                return Math.sqrt(a*a + b*b);
            }
        };
        //运动框架
        function getStyle(obj,attr){
            if(obj.currentStyle){
                return obj.currentStyle[attr];
            } else{
                return getComputedStyle(obj,false)[attr];
            }
        };
        function startMove(obj,json,fn){
            clearInterval(obj.timer);
            obj.timer = setInterval(function(){
                var bStop=true; //这一次运动就结束了,所有值都到达了。
                for(var attr in json){

                    //1.取当前的值
                    var iCur=0;
                    if(attr == 'opacity'){
                        iCur=parseInt(parseFloat(getStyle(obj,attr))*100);
                    } else{
                        iCur=parseInt(getStyle(obj,attr));
                    }

                    //2.算速度
                    var iSpeed=(json[attr]-iCur)/8;
                    iSpeed=iSpeed>0?Math.ceil(iSpeed):Math.floor(iSpeed);

                    //3.检测停止
                    if(iCur!=json[attr]){
                        bStop=false;
                    }

                    if(attr=='opacity'){
                        obj.style.filter='alpha(opacity:'+(iCur+iSpeed)+')';
                        obj.style.opacity=(iCur+iSpeed)/100;
                    } else{
                        obj.style[attr]=iCur+iSpeed+'px';
                    }
                }

                if(bStop){
                    clearInterval(obj.timer);
                    if(fn){
                        fn();
                    }
                }
            },30)
        }
        //运动框架结束
    </script>
</head>
<body>
    <ul id="ul1">
        <li><img src="images/image01.jpg" width="100" /></li>
        <li><img src="images/image02.jpg" width="100" /></li>
        <li><img src="images/image03.jpg" width="100" /></li>
        <li><img src="images/image04.jpg" width="100" /></li>
        <li><img src="images/image05.jpg" width="100" /></li>
        <li><img src="images/image01.jpg" width="100" /></li>
        <li><img src="images/image02.jpg" width="100" /></li>
        <li><img src="images/image03.jpg" width="100" /></li>
        <li><img src="images/image04.jpg" width="100" /></li>
        <li><img src="images/image05.jpg" width="100" /></li>
        <div style="clear: both;"></div>
    </ul>
</body>
</html>

原文地址:https://www.cnblogs.com/qibingshen/p/5410812.html