效果圖
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");
}