照片墙-拖拽交换

效果图

在这里插入图片描述
在这里插入图片描述

html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        ul {
            width: 480px;
            height: 640px;
            margin: 10px auto;
            background: yellow;
            padding: 10px;
            position: relative;
            list-style: none;
        }

        ul li {
            width: 150px;
            height: 150px;
            margin: 5px;
            float: left;
            background: lightgreen;
            cursor: move;
            /*position: relative;*/
            /*相对父级;通过getComputedStyle获取的是相对于自身的位置的left和top;*/
        }

        ul li img {
            width: 100%;
            height: 100%;
            user-select: none;
            pointer-events: none;
        }
    </style>
</head>

<body>
    <ul>
    <li><img src="../day02/images/images/23.jpg"></li>
    <li><img src="../day02/images/images/22.jpg"></li>
    <li><img src="../day02/images/images/21.jpg"></li>
    <li><img src="../day02/images/images/20.jpg"></li>
    <li><img src="../day02/images/images/19.jpg"></li>
    <li><img src="../day02/images/images/18.jpg"></li>
    <li><img src="../day02/images/images/17.jpg"></li>
    <li><img src="../day02/images/images/16.jpg"></li>
    <li><img src="../day02/images/images/15.jpg"></li>
    <li><img src="../day02/images/images/14.jpg"></li>
    <li><img src="../day02/images/images/13.jpg"></li>
    <li><img src="../day02/images/images/12.jpg"></li>
    </ul>
    <script src="event.js"></script>
    <script>
        let oLis = document.getElementsByTagName("li");
        // 循环每一个li;让其有拖拽效果;
        // 通过倒序,先给最后一张加position,那么前面几张位置是不受影响的;
        // offsetLeft : 获取是当前盒子的外边框到父级参照物的内边框的距离,包含margin值;这样会导致设置的left值偏大
        for (let i = oLis.length - 1; i >= 0; i--) {
            oLis[i].style.left = oLis[i].offsetLeft - 5 + "px";
            oLis[i].style.top = oLis[i].offsetTop - 5 + "px";
            oLis[i].style.position = "absolute"; //
            // 第一个迅速脱离文档流;第二个元素会跑到第一个位置上;
            new Drag(oLis[i]).on("selfdown", changeIndex).on("selfmove", isHit).on("selfup", changePosi);
        }
        let zIndex = 0;
        // 增加拖拽元素的索引;
        function changeIndex() {
            // 保证当前拖拽的元素z-index永远是最大的;
            this.ele.style.zIndex = ++zIndex;
        }
        // 碰撞检测
        function isHit() {
            // this--> Drag的实例;上的ele属性就是被拖拽的元素;
            let curLi = this.ele;
            this.hit = [];
            for (let i = 0; i < oLis.length; i++) {
                if (curLi === oLis[i]) continue; // 和自己没必要进行检测;
                if (curLi.offsetLeft + curLi.offsetWidth < oLis[i].offsetLeft || curLi.offsetTop + curLi.offsetHeight <
                    oLis[i].offsetTop || curLi.offsetTop > oLis[i].offsetTop + oLis[i].offsetHeight || curLi
                    .offsetLeft > oLis[i].offsetLeft + oLis[i].offsetWidth) {
                    // 只要满足其中一个条件,那么说明这个拖拽的盒子和li没有重合的部分;没有碰撞;
                    // 说明没碰到
                    oLis[i].style.background = "";
                } else {
                    oLis[i].style.background = "pink";
                    this.hit.push(oLis[i]); // 把有交集的元素放入hit这个数组中;
                }
            }
        }

        function changePosi() {
            //this
            let ary = this.hit;
            let curLi = this.ele;
            if (ary) {
                for (let i = 0; i < ary.length; i++) {
                    let cur = ary[i];
                    // 计算出左上角点之间的距离的平方;
                    cur.distance = Math.pow(cur.offsetLeft - curLi.offsetLeft, 2) + Math.pow(cur.offsetTop - curLi
                        .offsetTop, 2);
                    cur.style.background = "";
                }
            };
            // 对数组的distance进行排序;找出最小值;
            ary.sort(function (a, b) {
                return a.distance - b.distance;
            })
            // 实现位置的交换
            if (ary[0]) {
                this.ele.style.left = ary[0].style.left;
                this.ele.style.top = ary[0].style.top;
                ary[0].style.left = this.l + "px";
                ary[0].style.top = this.t + "px";
            } else {
                // 如果没有任何碰撞的元素,直接设置原有的样式;
                this.ele.style.left = this.l + "px";
                this.ele.style.top = this.t + "px";
            }
            this.hit = []; // 清空hit;
        }
    </script>
</body>

</html>

event.js

function EventFire() {}
EventFire.prototype.on=function (type,fn) {
    // 把方法订阅到这个EventFire这个类的实例上;
    if(!this[type]){
        // 第一次执行,给obj新增键值对,并且属性值是[];
        this[type]=[];
    }
    let ary = this[type];
    //遍历ary中的数组成员,判断是否绑定过;
    for(let i=0;i<ary.length;i++){
        if(ary[i]===fn){
            return;
        }
    }
    ary.push(fn);
    // 为了实现链式调用on订阅的方法;
    return this;
}
EventFire.prototype.emit=function (type) {
    let a = this[type];
    if(a){//如果是undefined,不进循环
        for(let i=0;i<a.length;i++){
            if(typeof a[i]==="function"){
                a[i].call(this);
            }
        }
    }
}
EventFire.prototype.off=function (type,fn) {
    let ary = this[type];
    for(let i=0;i<ary.length;i++){
        if(fn===ary[i]){
            //ary.splice(i,1);数组塌陷;
            ary[i]=null;
            return;
        }
    }
}
function Drag(ele) {
    // this-->实例;Drag的一个实例
    // 把元素放在Drag的实例上;
    this.ele = ele;
    this.ele.onmousedown=this.down.bind(this);
}
// 原型继承
Drag.prototype=new EventFire();
Drag.prototype.down=function (e) {
    // console.log(this);// this--> Drag的实例
    this.x=e.clientX;
    this.y=e.clientY;
    this.l = parseFloat(getComputedStyle(this.ele).left);
    this.t = parseFloat(getComputedStyle(this.ele).top);
    document.onmousemove=this.move.bind(this);
    document.onmouseup = this.up.bind(this);
    this.emit("selfdown");
}
Drag.prototype.move=function (e) {
    let changeX = e.clientX-this.x+this.l;
    let changeY = e.clientY-this.y+this.t;
    this.ele.style.left = changeX+"px";
    this.ele.style.top= changeY+"px";
    this.emit("selfmove")
}
Drag.prototype.up = function () {
    document.onmousemove=null;
    document.onmouseup =null;
    this.emit("selfup");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章