原生js實(shí)現(xiàn)九宮格拖拽換位
使用原生JS寫(xiě)出一個(gè)九宮格,實(shí)現(xiàn)九個(gè)格子何以拖拽換位的效果,供大家參考,具體內(nèi)容如下
效果演示

具體思路分析和代碼:
圖解1:

代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!--
思路梳理:
1,樣式設(shè)置:在樣式里最好使用定位來(lái)布局,不然以后拖拽代碼會(huì)麻煩點(diǎn)兒。
(這里沒(méi)有設(shè)置父容器的具體位置,如果設(shè)置了父容器的具體位置,則在移動(dòng)
時(shí)top和left的值需要根據(jù)情況計(jì)算位置)
2,父容器盒子里的內(nèi)容最好使用js代碼來(lái)生成,方便使用和添加樣式
2-1:(循環(huán)生成子元素)
我們子元素使用的定位布局,不難發(fā)現(xiàn):每行的top值一樣,每列的left值一樣,因此循環(huán)生
成子元素我們可以使用3*3的循環(huán)嵌套來(lái)寫(xiě),這樣就可以講每行的樣式設(shè)置了。
2-2:(給循環(huán)生成的標(biāo)簽添加隨機(jī)顏色和文字)
隨機(jī)顏色我是用的時(shí)rgb()來(lái)實(shí)現(xiàn)的,文字可以使用ASCII碼來(lái)生成,也可以使用字符串拼接
來(lái)生成,我這里使用ASCII碼生成。
PS:這樣我們的基本樣式就設(shè)置完畢了,接下來(lái)就是設(shè)置拖拽的事件
3,給每一個(gè)元素添加事件,這里我們需要三個(gè)事件: onmousedown - onmousemove - onmouseup
3-1:(首先是按下事件 onmousedown)
當(dāng)我們?cè)趯?duì)應(yīng)子元素按下時(shí),我們要獲取鼠標(biāo)到按下目標(biāo)邊框線(xiàn)內(nèi)的距離,并且克隆這個(gè)元素,
將這個(gè)元素扔到父容器里面充當(dāng)占位,(這里注意,克隆的這個(gè)節(jié)點(diǎn)在HTML結(jié)構(gòu)里是放到最后
的,如果不處理后面會(huì)出BUG?。。。?。
3-2:(然后處理移動(dòng)事件 onmousemove)
在按下子元素塊兒并且移動(dòng)時(shí),我們要給目標(biāo)設(shè)置他的top和left值,來(lái)實(shí)現(xiàn)跟隨移動(dòng),所以
我們需要獲取鼠標(biāo)到可視窗口的距離,目標(biāo)的top和left值 = 鼠標(biāo)到可視窗口的距離 - 鼠標(biāo)
到目標(biāo)邊緣的距離(這里無(wú)邊框,如果有需要額外減去邊框?qū)挾龋?
PS:
這里存在一個(gè)BUG?。。?!在拖拽時(shí),存在一個(gè)默認(rèn)事件--選中文字,當(dāng)你松開(kāi)之后,目
標(biāo)還會(huì)跟著走,就算你關(guān)閉了onmousemove這個(gè)事件。所以這里需要阻止一下默認(rèn)事件。
3-3:(最后處理抬起事件 onmouseup)這里也是最重要的一步?。。。?
核心思想:
當(dāng)鼠標(biāo)抬起時(shí),我們要計(jì)算當(dāng)前移動(dòng)目標(biāo)的中心點(diǎn)和每一個(gè)子元素中心點(diǎn)的距離,
哪一個(gè)離得最近,和哪個(gè)交換位置(注意,這里存在一個(gè)BUG,這里的BUG就是
3-1 里提到的BUG,需要提前處理)。
具體過(guò)程:
3-3-1:
首先我們要進(jìn)行循環(huán),計(jì)算拖拽目標(biāo)的中心點(diǎn)與每一個(gè)子元素的中心點(diǎn)的距離,具體
參照 圖解1 。 (拖拽目標(biāo)距離可視窗口的左邊距 - 子元素距離可視窗口的左邊
距)平方 + (拖拽目標(biāo)距離可視窗口的上邊距 - 子元素距離可視窗口的上邊距)
平方。最后在開(kāi)方,得到中心點(diǎn)的距離(注意3-1的BUG要處理掉,把,要把移動(dòng)的
標(biāo)簽放到結(jié)構(gòu)的最后,然后循環(huán)的時(shí)候?qū)⑺懦?,不然每次距離最近的都是它本身)。
3-3-2:
我們循環(huán)會(huì)得到我們想要的每一個(gè)距離,然后將這些距離放到一個(gè)數(shù)組里,并且再定
義一個(gè)數(shù)組備份一下,方便對(duì)照具體是哪個(gè)標(biāo)簽。
將其中一個(gè)數(shù)組進(jìn)行排序,然后再備份數(shù)組中查一下最小的值在備份數(shù)組中的索引下
標(biāo),這個(gè)索引下標(biāo)也就是對(duì)應(yīng)的子元素了。
3-3-3:
然后將距離最近的子元素的 left和top值給 目標(biāo)元素
然后將克隆的標(biāo)簽的 left和top值給 距離最近的子元素
最后在將克隆的標(biāo)簽移除掉
這里還是會(huì)有一個(gè)BUG?。?!如果不在標(biāo)簽上按 直接抬起鼠標(biāo)的話(huà),會(huì)報(bào)錯(cuò),這是因
為直接執(zhí)行了onmouseup事件,所以需要移除掉onmouseup事件
-->
<style>
*{margin: 0;padding: 0;}
.father{position: relative;}
.father div{position: absolute;width: 100px;height: 100px;border-radius: 10px;text-align: center;line-height: 100px;font-size: 30px;cursor: pointer;}
</style>
</head>
<body>
<div class="father"></div>
<script>
// 3*3 循環(huán)生成子元素div,并給他們?cè)O(shè)置定位值
// 設(shè)定固定的margin值
var mT = 15;
var mL = 15;
var asc = 65;//ASCII碼值
var oFather = document.querySelector('.father');
for(var i = 0; i < 3; i++){
for(var j = 0; j < 3; j++){
var oDiv = document.createElement('div');//創(chuàng)建子元素
oFather.appendChild(oDiv);
oDiv.style.left = j * (oDiv.offsetWidth + mL) +'px';
oDiv.style.top = i * (oDiv.offsetHeight + mT) +'px';
// 隨機(jī)顏色設(shè)置
oDiv.style.background = 'rgb('+parseInt(Math.random()*256) + "," +parseInt(Math.random()*256) + ","+parseInt(Math.random()*256)+')';
// 加上字母
oDiv.innerText = String.fromCharCode(asc++);
}
}
// 為了方便理解,將事件寫(xiě)到了外面,這里可以生成標(biāo)簽循環(huán)內(nèi)部
/* var oItem = document.querySelectorAll('.father>div');
這種方式獲取的是靜態(tài)集合,只會(huì)獲取到初次頁(yè)面加載的內(nèi)容,用這種辦法獲取子元素會(huì)出BUG */
var oItem = oFather.children;
for(var k = 0 ;k<oItem.length; k++){
oItem[k].onmousedown = function(e){
var evt = e || event;
// 獲取鼠標(biāo)到目標(biāo)邊框內(nèi)的距離
var x = e.offsetX;
var y = e.offsetY;
var tagNode = this;
// 克隆目標(biāo)標(biāo)簽
var cloneNode = tagNode.cloneNode();
cloneNode.style.border = '1px dashed #fff';
oFather.appendChild(cloneNode);
tagNode.style.zIndex = 1;
// 在思路里提到過(guò),這里存在一個(gè)BUG需要將克隆的和被拖拽換位置
oFather.replaceChild(cloneNode, tagNode);
oFather.appendChild(tagNode);
document.onmousemove = function(e){
var evt = e || event ;
var l = evt.clientX - x;
var t = evt.clientY - y;
tagNode.style.left = l + 'px';
tagNode.style.top = t + 'px';
// 阻止默認(rèn)事件,防止bug
return false;
}
document.onmouseup = function(){
// 抬起鼠標(biāo)后,要判斷離那個(gè)最近,然后交換
var oldArr = [];
var newArr = [];
for(var l = 0; l<oItem.length - 1;l++){
var disX = tagNode.offsetLeft - oItem[l].offsetLeft;
var disY = tagNode.offsetTop - oItem[l].offsetTop;
// 勾股定理
var dis = Math.sqrt( Math.pow(disX,2) + Math.pow(disY,2) );
oldArr.push(dis);
newArr.push(dis);
}
// 將oldArr從小到大排序
oldArr.sort(function(a,b){return a-b});
var minIndex = newArr.indexOf(oldArr[0]);
console.log('oldArr' , oldArr, 'newArr' ,newArr);
// 將距離最近的元素的定位給移動(dòng)的目標(biāo)
tagNode.style.top = oItem[minIndex].style.top;
tagNode.style.left = oItem[minIndex].style.left;
// 把克隆的定位給距離最近的
oItem[minIndex].style.top = cloneNode.style.top;
oItem[minIndex].style.left = cloneNode.style.left;
//把克隆節(jié)點(diǎn)移除
oFather.removeChild(cloneNode);
document.onmousemove = null;
document.onmouseup = null;
}
return false;
}
}
</script>
</body>
</html>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- JQuery Dialog(JS 模態(tài)窗口,可拖拽的DIV)
- Sortable.js拖拽排序使用方法解析
- js實(shí)現(xiàn)拖拽效果
- javascript實(shí)現(xiàn)移動(dòng)端上的觸屏拖拽功能
- 使用js實(shí)現(xiàn)的簡(jiǎn)單拖拽效果
- JS實(shí)現(xiàn)的文件拖拽上傳功能示例
- JS實(shí)現(xiàn)漂亮的窗口拖拽效果(可改變大小、最大化、最小化、關(guān)閉)
- 使用javaScript實(shí)現(xiàn)鼠標(biāo)拖拽事件
- JavaScript實(shí)現(xiàn)圖片的放大縮小及拖拽功能示例
- JavaScript實(shí)現(xiàn)九宮格拖拽效果
相關(guān)文章
JS基于面向?qū)ο髮?shí)現(xiàn)的多個(gè)倒計(jì)時(shí)器功能示例
這篇文章主要介紹了JS基于面向?qū)ο髮?shí)現(xiàn)的多個(gè)倒計(jì)時(shí)器功能,結(jié)合實(shí)例形式分析了javascript面向?qū)ο蠹皶r(shí)間操作相關(guān)技巧,需要的朋友可以參考下2017-02-02
你必須知道的Javascript知識(shí)點(diǎn)之"this指針"的應(yīng)用
本篇文章小編為大家介紹,你必須知道的Javascript知識(shí)點(diǎn)之"this指針"的應(yīng)用。需要的朋友參考下2013-04-04
JavaScript的模塊化:封裝(閉包),繼承(原型) 介紹
在復(fù)雜的邏輯下, JavaScript 需要被模塊化,模塊需要封裝起來(lái),只留下供外界調(diào)用的接口。閉包是 JavaScript 中實(shí)現(xiàn)模塊封裝的關(guān)鍵,也是很多初學(xué)者難以理解的要點(diǎn)2013-07-07
javascript數(shù)組遍歷的方法實(shí)例分析
這篇文章主要介紹了javascript數(shù)組遍歷的方法,結(jié)合實(shí)例形式分析了javascript數(shù)組遍歷及相關(guān)的some、every、filter、map等方法的使用技巧,需要的朋友可以參考下2016-09-09
微信小程序商城項(xiàng)目之購(gòu)物數(shù)量加減(3)
這篇文章主要為大家詳細(xì)介紹了微信小程序商城購(gòu)物數(shù)量加減功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
uniapp小程序開(kāi)發(fā)組件封裝之自定義輪播圖效果
這篇文章主要介紹了uniapp小程序開(kāi)發(fā)組件封裝之自定義輪播圖,本文主要展示小程序端封裝輪播圖組件,使用的是uniapp進(jìn)行的開(kāi)發(fā),主要使用的是uniapp官網(wǎng)提供的swiper組件,需要的朋友可以參考下2023-02-02
如何去除js中的json存在的轉(zhuǎn)義字符\問(wèn)題
這篇文章主要介紹了如何去除js中的json存在的轉(zhuǎn)義字符\問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
微信小程序?qū)崿F(xiàn)購(gòu)物車(chē)選擇規(guī)格顏色效果
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)購(gòu)物車(chē)選擇規(guī)格顏色選中效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01

