實作效果圖

GitHub 和 Gitee 個人主頁中可以對自己的專案進行拖拽排序,于是我就想自己實作一個,本隨筆只是記錄一下大概的實作思路,如果感興趣的小伙伴可以通過代碼和本隨筆的說明去理解實作程序,??我的 Gitee 和 GitHub 地址,
在線瀏覽地址:11.拖拽排序,里面還有更多的例子,
思路構思
要實作元素拖拽可替換位置,就必須要鎖定每一個元素的具體位置,且要直到兩個元素的 transform: translate(),從代碼上看,這是一個二維陣列,從界面上看,就是一個網格布局,06#Web 實戰:實作可滑動的標簽頁是通過一維陣列實作的,
元素的布局不可能通過display: grid來進行,得用transform: translate(),實作元素得平移,且需要使用絕對和相對定位,
靜態界面代碼
這里給出初始的靜態界面代碼,draggable 表示開啟這個元素的可拖拽功能:
<div >
<div >
<div draggable="true">Item 0</div>
</div>
<div >
<div draggable="true">Item 1</div>
</div>
<div >
<div draggable="true">Item 2</div>
</div>
<div >
<div draggable="true">Item 3</div>
</div>
</div>
老樣子,我喜歡把不必要的代碼給省略掉,如果樣式不全,去我的倉庫復制:
.drop-box {
transition: all 0.5s ease-in-out;
box-sizing: border-box;
/* 在這里設定 drop-box 的高寬 */
width: 420px;
height: 300px;
/* 在這里設定 drop-box 的高寬 */
border-radius: 10px;
border: 1px solid #cccccc;
position: relative;
}
.drag-item {
transition: all 0.5s ease-in-out;
box-sizing: border-box;
border-radius: 10px;
border: 1px solid #cccccc;
width: 200px;
height: 50%;
position: absolute;
top: 0;
left: 0;
}
.drag-item > div.ontology {
width: 100%;
height: 100%;
}
構建二維陣列
拖拽每一個元素不代表真實地改變了 DOM 所在的位置,給這些元素設定監聽器,并獲取 index,拖拽之后都不會影響它的索引值,
上面給的 HTML 結構,在界面上生成之后,從 1 ~ 4 這樣的序列是不會改變的,即便是我們修改了它的 translate(平移元素)之后,也不會影響它原本在 DOM 樹上的順序,
為了方便在代碼中修改元素的transform: translate(),我們需要在頁面載入時就虛擬化這些元素到二維陣列中,元素虛擬化進二維陣列的目的是讓編程更加易于使用,
let virtualGridElem = [];
function initVirtualGrid(elem, init) {
let elemIndex = 0;
for (let rowIndex = 0; rowIndex < init.rowNum; rowIndex++) {
virtualGridElem[rowIndex] = [];
for (let colIndex = 0; colIndex < init.colNum; colIndex++) {
$(elem[elemIndex]).attr("data-row-index", rowIndex);
$(elem[elemIndex]).attr("data-col-index", colIndex);
$(elem[elemIndex]).css({ width: init.width, height: init.height, transform: gridVals[rowIndex][colIndex] });
initEvents(elem[elemIndex], elemIndex, rowIndex, colIndex);
virtualGridElem[rowIndex][colIndex] = elem[elemIndex++];
}
}
}
在虛擬化之前,需要獲得這個界面中的網格資訊,即網格有多少行,每一行有多少列,
let gridVals = [];
function initGridVals(elNum, colNum, rowMaxWidth, colMaxWidth) {
let rowNum = Math.ceil(elNum / colNum);
let widthPerRow = rowMaxWidth / colNum;
let heightPerCol = colMaxWidth / rowNum;
let translateX = 0;
for (let rowIndex = 0; rowIndex < rowNum; rowIndex++) {
let translateY = 0;
gridVals[rowIndex] = [];
for (let colIndex = 0; colIndex < colNum; colIndex++) {
gridVals[rowIndex][colIndex] = `translate(${translateY}px, ${translateX}px)`;
translateY += widthPerRow;
}
translateX += heightPerCol;
}
return {
width: widthPerRow,
height: heightPerCol,
rowNum: rowNum,
colNum: colNum
};
}
到目前為止,得到了兩個重要的二維陣列:virtualGridElem 和 gridVals,virtualGridElem 不會被改變,一直保持原有的位置,與實際的可拖拽元素的 DOM 樹保持一致,gridVals 會與 virtualGridElem 發生出入,會根據操作而修改,
let dragItem = $(".drop-box").children(".drag-item");
initVirtualGrid(dragItem, initGridVals($(dragItem).length, 2, 420, 300));
拖拽排序功能
拖拽在 HTML5 就已經存在,drop、dragover、dragstart、dragend 都是實作本案例中最重要的幾個監聽事件,其中 drop 表示可拖拽元素到目標元素之后的元素,即 item1 拖拽到 item2 之后,獲取 item2 的元素,
function initEvents(elem, index, rowIndex, colIndex) {
// drop 是獲取拖拽目標元素
$(elem).on("drop", e => {
e.preventDefault();
$(virtualGridElem[rowIndex][colIndex]).css({ transform: gridVals[currRowIndex][currColIndex] });
$(virtualGridElem[currRowIndex][currColIndex]).css({ transform: gridVals[rowIndex][colIndex] });
// let tempTargetGridVals = gridVals[currRowIndex][currColIndex];
// gridVals[currRowIndex][currColIndex] = gridVals[rowIndex][colIndex];
// gridVals[rowIndex][colIndex] = tempTargetGridVals;
[gridVals[currRowIndex][currColIndex], gridVals[rowIndex][colIndex]] = [gridVals[rowIndex][colIndex], gridVals[currRowIndex][currColIndex]];
});
// 必須寫這一段代碼,否則 drop 監聽器不生效
$(elem).on("dragover", e => {
e.preventDefault();
});
// drag 相關的監聽是對拖拽元素目標有效的
let ontology = $(elem).children(".ontology");
$(ontology).on("dragstart", e => {
currRowIndex = rowIndex;
currColIndex = colIndex;
$(elem).css({ opacity: "0.5" });
});
$(ontology).on("dragend", e => {
$(elem).css({ opacity: "1" });
});
}
代碼最多的是 drop 事件,在開始拖拽時,也就是獲取拖拽的元素資訊,在這里我們要把這個拖拽的元素透明度調低一點,表示被拖拽中的元素,之后,記錄改拖拽元素的二維索引值,rowIndex、colIndex,記錄為 currXxxIndex,
在拖拽完成之后,就要觸發 drop 事件,drop 事件中,對 gridVals 進行值的交替,ES6 中解構賦值不需要中間變數臨時存盤,就可以實作值交換:
let x = 1, y = 2;
[x, y] = [y, x]
替換之后,x = 2,y = 1,
結束語
具體實作程序請去看我倉庫中的代碼?? Gitee 和 GitHub 地址,喜歡的話,請點個贊??再走哦!后續帶來更多的 Web 實踐,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/538568.html
標籤:JavaScript
上一篇:本地JS檔案批量壓縮
下一篇:Angular樣式隔離(style isolation)及選擇器(:host, :host-context, ::ng-deep)的使用
