背景
平平無奇的一天,博主正在敲著自己的專案,這時候被領導告知要我寫一個工程自動化工具,接到需求的時候我的大腦便開始瘋狂轉圈(因為我需要前后端都做,相對來說思考的東西要多一點),后來在思考資料設計,介面資料處理的一些細節之后,終于是有條不紊的進行了,But ,一個Vue的拖拽排序功能如何實作卻讓我犯了難,在痛苦的學習中我終于明白了這個東西是怎么玩的 記錄的同時進行分享,希望能幫助到有同樣需求的碼農們(狗頭)
文章目錄
- 背景
- 第一步是MDN拖拽方法總結,若無興趣可以略過,
- 一、官方關于拖拽方法和屬性有哪些?
- 1.可拖拽屬性 draggable
- 2.開始拖拽操作 dragstart
- 3.拖拽資料 dataTransfer
- 4.設定拖拽反饋影像 setDragImage
- 5.拖拽效果 effectAllowed
- 6.指定放置目標 dragover
- 7.放置反饋 -moz-drag-over CSS
- 8.執行放置 drop
- 8.完成拖拽 dragend
- 二、開始實作
- 1.在總結完拖拽方法之后,拖拽-開始-進入-結束應當是正常流程
- 2.漸入佳境
- 3.打完收工
- 總結
- 明天,又是充滿希望的一天!
第一步是MDN拖拽方法總結,若無興趣可以略過,
本著做什么功能都盡量不匯入包的思維,
我放棄了使用vue的插件(需要匯入的包太大,冗余代碼太多)
轉而選擇使用H5原生來實作這個功能
一、官方關于拖拽方法和屬性有哪些?
首先讓我們看一下MDN上對拖拽的方法的一些總結,
1.可拖拽屬性 draggable
在 HTML 中,除了影像、鏈接和選擇的文本默認的可拖拽行為之外,其他元素在默認情況下是不可拖拽的,要使其他的 HTML 元素可拖拽,
必須做三件事:
1.將想要拖拽的元素的 draggable 屬性設定成 draggable="true"
2.為 dragstart () 事件添加一個監聽程式
3.在上一步定義的監聽程式中 設定拖拽資料
<p draggable="true"
ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')">
這個文本 <strong>可以</strong> 被拖拽.
</p>
2.開始拖拽操作 dragstart
當用戶開始拖拽時,會觸發 dragstart (), 事件
在這個例子中, dragstart (),事件監聽程式被添加到可拖拽元素本身;然而,你可以監聽一個 祖先元素,因為就像大多數其他事件一樣,拖拽事件會冒泡,
在 dragstart (),事件中,你可以指定拖拽資料、反饋影像和拖拽效果,所有這些都將在下面描述,不過,我們只需要設定拖拽資料,因為在大多數情況下默認的影像和拖拽效果都是適用的,
<p draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')">
這個文本 <strong>可以</strong> 被拖拽.
</p>
3.拖拽資料 dataTransfer
所有 拖拽事件 都有一個名為 dataTransfer 的屬性,它持有拖拽資料(dataTransfer 是一個 DataTransfer 物件),
這個屬性有兩個引數,簡而言之,第一個引數是你允許拖拽的型別,第二個是放置到指定鏈接的資料
event.dataTransfer.setData("text/plain", "可拖拽的文本");
- 你還可以提供多種型別的資料,代碼如下:
const dt = event.dataTransfer;
dt.setData("application/x.bookmark", bookmarkString);
dt.setData("text/uri-list", "http://www.abc.org");
dt.setData("text/plain", "http://www.abc.org");
- 如果你用相同格式重復添加,新資料會替換舊資料,你可以清除它們,代碼如下:
event.dataTransfer.clearData("text/uri-list");
4.設定拖拽反饋影像 setDragImage
當拖拽發生時,會生成拖拽目標的一個半透明影像(觸發"{event("dragstart")}" 事件的元素),并在拖拽程序中跟蹤滑鼠指標,這個影像是自動創建的,所以你不需要自己創建它,但是,你可以使用 setDragImage() 方法來自定義拖拽反饋影像,
event.dataTransfer.setDragImage(image, xOffset, yOffset);
-
這三個引數都是必要的,第一個是影像的參考,這個參考通常是一個
<img>元素
但也可以是<canvas>或任何其他元素,生成的反饋影像就是該影像在螢屏上的樣子,
以影像原始的大小繪制,
setDragImage()方法的第二、三個引數是影像位置相對于滑鼠指標位置的偏移量,
也可以使用不在檔案中的影像和畫布,這種技術在使用canvas元素繪制自定義的拖拽反饋影像時非常有用,如下面的例子:function dragWithCustomImage(event) { var canvas = document.createElementNS("http://www.w3.org/1999/xhtml","canvas"); canvas.width = canvas.height = 50; var ctx = canvas.getContext("2d"); ctx.lineWidth = 4; ctx.moveTo(0, 0); ctx.lineTo(50, 50); ctx.moveTo(0, 50); ctx.lineTo(50, 0); ctx.stroke(); var dt = event.dataTransfer; dt.setData('text/plain', 拖拽的資料'); dt.setDragImage(canvas, 25, 25); }在這個例子中,我們做了一個是畫布的拖拽影像,當畫布寬 50 像素,高 50 像素時,我們使用一半的偏移量(25 和 25),這樣滑鼠指標即為影像中心,
5.拖拽效果 effectAllowed
拖拽程序中可能會執行一些操作, copy 操作用來指示被拖拽的資料將從當前位置復制到放置位置, move 操作指示被拖拽的資料會被移動,link 操作表示在源和放置位置之間將會創建某種形式的關系或連接,
可以在 dragstart () 事件監聽程式中設定 effectAllowed 屬性以指定允許拖拽源頭執行三種操作中的哪幾種,
event.dataTransfer.effectAllowed = "copy";
以上代碼示例為只允許復制,你可以用不用的方式來實作你的需求:
1. none:不允許操作
2. copy:只復制
3. move:只移動
4. link:只鏈接
5. copyMove:復制或移動
6. copyLink:復制或鏈接
7. linkMove:鏈接或移動
8. all:復制,移動或鏈接
6.指定放置目標 dragover
dragenter () 或 dragover () 事件的監聽程式用于表示有效的放置目標,也就是被拖拽專案可能放置的地方,網頁或應用程式的大多數區域都不是放置資料的有效位置,因此,這些事件的默認處理是不允許放置,
如果你想要允許放置,你必須取消 dragenter 和 dragover事件來阻止默認的處理,你可以在屬性定義的事件監聽程式回傳 false,或者呼叫事件的 preventDefault() 方法來實作這一點,在一個獨立腳本中的定義的函式里,可能后者更可行,
<div ondragover="return false">
<div ondragover="event.preventDefault()">
7.放置反饋 -moz-drag-over CSS
有幾種方法可以向用戶表明哪個位置允許放置,滑鼠指標將根據 dropEffect 屬性的值做必要的更新,滑鼠指標具體的外觀取決于用戶平臺,典型的如加號圖示會出現在 ‘copy’ 中,而不允許放置時,會出現禁止放置的圖示,在許多情況下,滑鼠指標反饋就足夠了,
但是,你還可以根據需要更新用戶界面,如添加一個插入標記或使用高亮顯示,對于簡單的高亮顯示,你可以在放置目標上使用 -moz-drag-over CSS 偽類,
.droparea:-moz-drag-over {
border: 1px solid black;
}
注意:要使這個偽類生效,必須要在 dragenter 事件添加preventDefault()方法
8.執行放置 drop
當用戶放開滑鼠,拖放操作就會結束,
如果在有效的放置目標元素(即取消了 dragenter () 或 dragover () 的元素)上放開滑鼠,放置會成功實作,drop () 事件在目標元素上被觸發,否則拖拽會被取消,
不會觸發 drop () 事件,
在所有拖拽操作相關的事件中,事件的 domxref("DragEvent.dataTransfer","dataTransfer") 屬性會一直保存著拖拽資料,可使用 getData() 方法來取回資料,
function onDrop(event) {
const data = event.dataTransfer.getData("text/plain");
event.target.textContent = data;
event.preventDefault();
}
8.完成拖拽 dragend
一旦拖拽完成,dragend () 事件會在拖拽源頭(即觸發 dragstart () 的元素)上發生,無論拖拽是成功還是被取消,這個事件都會被觸發,然而,你可以使用 dropEffect 屬性來決定執行什么放置操作,
如果在dragend () 事件中,dropEffect 屬性值為 none,則拖拽會被取消,否則,這個屬性會規定需要執行什么操作,源頭元素可使用這個資訊以在拖拽操作完成后從原來的位置移除被拖拽的專案,mozUserCancelled () 屬性會在用戶取消拖拽(按下 Esc 鍵)時設定為 true,在拖拽因為其他原因如無效放置目標等被取消時,或拖拽成功時,則設定為 false,
放置可發生在同一視窗或另一個應用程式中,兩種情況都會觸發 dragend () 事件,事件的 screenX 和 screenY 屬性會被設定為放置發生時滑鼠在螢屏上的坐標,
event("dragend") 事件結束后,整個拖放操作就完成了,
二、開始實作
1.在總結完拖拽方法之后,拖拽-開始-進入-結束應當是正常流程
任何一個單獨的事件都不可能完成我的業務需求,但是組合就可以,于是我用了以下事件
dragstart通過傳給函式的index來知曉拖動的是哪個元素dragenter通過index來知曉最后進入的是哪個元素dragend元素放置時立馬執行對應邏輯,將拖動元素的資料和最后放置元素的資料進行交換dragover通過禁用父級的默認屬性,來取消掉子元素的拖動禁止按鈕
于是我添加了如下代碼(示例):
<view
@dragstart="dragstart(index)"
@dragenter.prevent="dragenter($event, index)"
@dragend="dragend($event, index)"
>
拖拽測驗代碼
</view>
對應函式為:
dragstart(index) {
console.log(index)
this.startIndex = index;//存盤開始拖動時候的下標,可以知道從哪個地方開始拖動的
},
dragenter(e, index) {
console.log(e,index)
this.endIndex = index;//存盤結束拖動時候的下標,可以知道最后進入的是哪個元素
},
dragend(e, index) {
console.log(e,index)
let { startIndex, endIndex } = this; //有開始和結束直接把對應資料交換值就可以了
},
值得注意的地方是,如果用第三方變數交換資料的時候,建議使用深拷貝給資料源進行復制,
而Vue2.0的陣列和物件的雙向系結一直是硬傷,
切記賦值的時候要用this.$set('必定有的資料','哪個屬性','賦值資料源')
2.漸入佳境
值得欣慰的是現在簡易版的基礎拖動排序已經基本完成了,但這個時候出現一個問題:
在進行拖拽的時候,一直有一個禁用的圖示顯示,我意識到肯定是哪個地方做得不對了,經過多處查詢檔案,發現了出現這個的原因:
原來在拖拽的元素上,其父級必須要禁用默認阻止其放置的屬性才會不出現這個禁止圖示,
于是對代碼進行修改,最后的代碼如下所示:
<view @dragover.prevent="allowDrop($event)">
<view
@dragstart="dragstart(index)"
@dragenter.prevent="dragenter($event, index)"
@dragend="dragend($event, index)"
>
拖拽測驗代碼
</view>
</view>
dragstart(index) {
console.log(index)
this.startIndex = index;//存盤開始拖動時候的下標,可以知道從哪個地方開始拖動的
},
dragenter(e, index) {
console.log(e,index)
this.endIndex = index;//存盤結束拖動時候的下標,可以知道最后進入的是哪個元素
},
dragend(e, index) {
console.log(e,index)
let { startIndex, endIndex } = this; //有開始和結束直接把對應資料交換值就可以了
},
allowDrop(e){
e.preventDefault() //禁用父級元素默認阻止放置的屬性,使元素可進行放置(不出現禁用圖示)
},
3.打完收工
由于每人的業務需求不一樣,具體的邏輯要自己寫,成品實體如下圖:

由于錄制軟體原因,拖動程序的影片被默認壓縮了,顯得影片不夠流暢,這個沒有辦法,因為是白嫖的
總結
好記性不如爛筆頭
隨時隨地給自己對專案的狀態進行實時的記錄,想來以后回憶起來也是極美的
明天,又是充滿希望的一天!
最后放上一張鎮樓圖

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/286186.html
標籤:AI
上一篇:計算機網路(1)
