成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

關于前端里的拖拖拽拽,了解一下?

開發 前端
最近在開發一款低代碼平臺,所以借此機會分享一下關于“拖拽”這一交互的基礎知識和實踐經驗,希望可以給有需要的同學提供一點參考。

最近在項目中使用了 react-dnd[1],一個基于 HTML5 的拖拽庫,“拖拽能力”豐富了前端的交互方式,基于拖拽能力,會擴展各種各樣的拖拽反饋效果,因此有必要學習了解,最好的學習方式就是實操!

拖拽交互常見于各種前端編輯器里,而“編輯器”是一個集成前端技術能力的綜合性工程,其中就會涉及到各種形式的拖拽交互,因為“拖拽”是提升用戶體驗的重要交互方式,所以需要對拖拽的交互效果做各種定制化,作為開發者理應熟練掌握“拖拽”的使用!

最近在開發一款低代碼平臺,所以借此機會分享一下關于“拖拽”這一交互的基礎知識和實踐經驗,希望可以給有需要的同學提供一點參考。

一、HTML5 中的拖放

拖(Drag)和放(Drop)是 HTML5 標準的組成部分,了解掌握之后,舉一反三,有助于提升我們在拖拽場景下技術方案的設計能力。

1.1 draggable 屬性

現代瀏覽器中,不難發現,圖片標簽()是可以被長按拖拽,但如果需要自定義的 DOM 節點可以被拖拽需要配置以告訴瀏覽器提供對元素(Element / Tag)支持拖拽的能力。

而元素是否允許被拖放且可響應 API 操作依賴于 draggable[2] 全局標簽屬性

draggable 是一個布爾值類型的標簽屬性:

  • true:元素可被拖拽
  • false:元素不可拖拽

當元素設置了 draggable 屬性,此時長按就可以自由拖拽了:

1.2 Darg & Drop 事件

HTML 的 drag & drop 使用了“DOM Event”和從“Mouse Event”繼承而來的“drag event” 。

一個典型的拖拽操作: 用戶選中一個可拖拽的(draggable)元素,并將其拖拽(鼠標按住不放)至一個可放置的(droppable)元素上,然后松開鼠標。

在拖動元素期間,一些與拖放相關的事件會被觸發,像 drag 和 dragover 類型的事件會被頻繁觸發。

除了定義拖拽事件類型,每個事件類型還賦予了對應的事件處理器

各個事件的時機可以用下面這個圖簡單表示:

??注意: dragOver 事件的默認行為是:“Reset the current drag operation to "none"”。也就是說,如果不阻止放置元素的 dragOver 事件,則放置元素不會響應“拖動元素”的“放置行為”

// 讓綁定該事件的元素支持放置
function handleDragOver(e) {
// 阻止默認的重置行為
// 即可成為拖拽元素的放置區
e.preventDefault();
}


從設計事件標準來看,如果我們需要自行實現拖拽的效果,就需要從這關鍵的幾個事件去思考設計。

1.3 DataTransfer

在上述的事件類型中,不難發現,放置元素和拖動元素分別綁定了自己的事件,可如何將拖拽元素和放置元素建立聯系以及傳遞數據?

這就涉及到 DataTransfer 對象:

DataTransfer 對象用于保存拖動并放下(drag and drop)過程中的數據。它可以保存一項或多項數據,這些數據項可以是一種或者多種數據類型。—— DataTransfer - MDN[3]

DataTransfer 對象在不同瀏覽器上因為標準可能不一樣使得 API 有差異,但有幾個“標準(常用)”屬性和方法需要熟悉

在 Chrome 瀏覽器上的 DataTransfer 實例如下:

(1) 屬性

(2) 方法

在簡單的拖拽場景中,其實可以類比 window.localStorage 對象的 setItem() 和 getItem() 方法來理解記憶.

但 getData() 在測試中發現只能在 ondrop 事件中獲取到值:

1.4 一個案例掌握拖放 API

拖動元素 放置區域

<div>
<div class="drag" draggable="true" id="dragger" ondragstart="handleDragStart(event)">拖動元素</div>
<div class="drop" ondrop="handleDrop(event)" ondragover="allowDrop(event)">放置區域</div>
</div>
<script>
function handleDragStart(e) {
e.dataTransfer.setData('DRAG_NODE_ID', e.target.id)
}
function handleDragOver(e) {
e.preventDefault();
}
function handleDrop(e) {
e.preventDefault();
var data = e.dataTransfer.getData('DRAG_NODE_ID');
e.target.appendChild(document.getElementById(data));
}
</script>


演示案例: https://codepen.io/DYBOY/pen/eYeyvWm

效果:

演示

拖拽演示效果

1.6 兼容性

是 HTML5 標準提出的能力,因此各大瀏覽器廠商對于標準的支持有差異,其兼容性參考如下:

相較于傳統的通過鼠標事件:mousedown、mousemove、mouseup 組合實現的拖拽要簡單很多,少了放入目標邊界的判斷,也少了對位置的實時獲取操作。

另外目前的 API 不算多,例如我們想要定制化拖拽的圖片大小、鼠標樣式等,目前暫時沒發現比較方便的解決方式,但是從另一個角度來說,讓我們對于拖拽能力的設計和標準有了一個更深切的認識,對于設計實現拖拽交互有了一個“理論”基礎!

二、手搓一個

有了上面的基礎知識,那么實現一個列表拖拽排序并不是什么難事。

2.1 設計實現

結合上述的 Drag & Drop 的事件類型,那么拖拽排序主要是針對“拖動對象”之間相互作用關系的邏輯梳理,此處我們暫且區分為:

  • 源對象: 拖拽列表中被拖動的單個列表項
  • 目標對象: 拖拽列表中和“源對象”產生“相互作用”的列表項

整體的交互事件的設計思路如下:

(1) ondragstart

此時開始拖拽“源對象”的時機,在此事件回調函數中改變“源對象”的樣式,設置拖拽的一些傳遞參數等初始值。

// 源對象開始拖拽
const handleDragStart = (e: React.DragEvent<HTMLDivElement>) => {
e.dataTransfer.effectAllowed = "move";
setDragId(e.currentTarget.dataset.index); //dataset 獲取拖拽項的 id
};


(2) ondragover

正與拖拽中的“源對象”產生相互影響的目標對象,此時“源對象”處于“目標對象”的正上方,目標對象 100ms/次的頻率調用“目標對象”的 ondragover 中聲明的回調事件。

此時,我們會計算改變“源對象”和“目標對象”的位置。

// 源對象在目標對象上方時
const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault(); // 允許放置,阻止默認事件
const dropId = e.currentTarget.dataset.index;
move(dragId, dropId); // 改變原列表數據
};


(3) ondrag

該事件作用于“源對象”,此時正處于拖拽過程中,此時可以改變源對象的 opacity、display(none)、visiblity 樣式屬性,如果在 dragstart 事件改變,則會導致拖拽拷貝對象丟失。

// 源對象被拖拽過程中
const handleDrag = (e: React.DragEvent<HTMLDivElement>) => {
e.currentTarget.style.opacity = "0";
};


(4) ondragend

在松手完成“源對象”的放置時,主動調用綁定在“源對象”身上的事件,此時恢復更改的樣式。

// 源對象被放置完成時
const handleDragEnd = (e: React.DragEvent<HTMLDivElement>) => {
e.currentTarget.style.opacity = "1";
};


2.2 實現效果

2.3 加點動畫

上面的實現中效果還算可以,但是少了拖拽項的切換過程動畫,直接在 dragover 事件中通過 move(dragId, dropId) 方法直接修改了原列表數據的排序,導致切換突變。

借助 animation 新增 CSS 幀動畫:

@keyframes dropUp {
100% {
transform: translateY(5px);
}
}
@keyframes dropDown {
100% {
transform: translateY(-5px);
}
}

.drop-up{
animation: dropUp 0.3s ease-in-out forwards;
}
.drop-down{
animation: dropDown 0.3s ease-in-out forwards;
}


同樣的在 dragOver 事件中處理,新增邏輯代碼:

// 源對象在目標對象上方時
const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
...
// 設置動畫
const dropId = e.currentTarget.dataset.index;
const dragIndex = findIndex(listData, (i) => i.id === dragId);
const dropIndex = findIndex(listData, (i) => i.id === dropId);
// 通過增加對應的 CSS class,實現視覺上的動畫過渡
e.currentTarget.classList.remove("drop-up", "drop-down");
if (dragIndex < dropIndex) {
e.currentTarget.classList.add("drop-down");
} else if (dragIndex > dropIndex) {
e.currentTarget.classList.add("drop-up");
}
...
};


增加了動畫的效果:

增加了動畫的效果

看起來似乎好一點了,當然大家可以去擴充動畫的效果,亦或者借助三方動畫庫。

三、已有拖拽庫

目前主流的拖拽庫有:

  • react-dnd: https://github.com/react-dnd/react-dnd/
  • react-beautiful-dnd: https://github.com/atlassian/react-beautiful-dnd/
  • sortablejs: https://sortablejs.github.io/Sortable/
  • react-sortable-hoc: https://github.com/clauderic/react-sortable-hoc/

關于幾者的差異,可以參閱:《關于react中使用拖拽插件的評測[4]》

四、總結

由于低代碼平臺其實會有豐富的拖拽場景,從可擴展和兼容性上考慮,最終選擇了 react-dnd 作為基礎拖拽庫,當然,在復雜的拖拽場景下,是需要自行擴展該拖拽庫,上手難度相對會高一點,不過有了這些“拖拽知識”作為前置基礎,那么擴展功能也就不是什么難事了。

參考資料

[1]react-dnd - Github: https://react-dnd.github.io/react-dnd/about

[2]draggable - MDN: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/draggable

[3]DataTransfer - MDN: https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer

[4]關于react中使用拖拽插件的評測: https://juejin.cn/post/6956112150989373448

責任編輯:姜華 來源: DYBOY
相關推薦

2020-02-10 14:26:10

GitHub代碼倉庫

2020-12-10 08:44:35

WebSocket輪詢Comet

2022-03-24 13:36:18

Java悲觀鎖樂觀鎖

2020-03-01 17:53:38

Excel大數據微軟

2019-02-20 14:16:43

2018-06-05 17:40:36

人工智能語音識別

2024-04-11 12:19:01

Rust數據類型

2018-04-25 06:46:52

2023-03-02 08:00:55

包管理工具pnpm 包

2019-03-11 14:33:21

Redis內存模型數據庫

2022-03-07 06:34:22

CQRS數據庫數據模型

2018-07-17 14:42:50

2023-11-18 09:09:08

GNUBSD協議

2024-02-28 18:22:13

AI處理器

2021-07-06 14:56:20

深度學習編程人工智能

2021-05-12 10:59:39

Kubernetes容器集群

2018-03-21 09:08:06

超融合架構本質

2022-03-10 07:39:33

.NET部署模式

2023-04-27 13:32:16

AutoGPTAPI智能

2011-03-25 10:39:06

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲成人精品 | 青青草社区 | 久久伊人精品 | 国产一区二区视频在线观看 | 一区二区三区久久久 | 国产日韩一区二区 | 国产电影一区二区 | 91电影在线 | 欧美日韩国产一区二区三区 | 亚洲色图综合 | 我想看国产一级毛片 | 亚洲一区在线免费观看 | 久久久91精品国产一区二区三区 | 成人精品视频99在线观看免费 | 美女黄网 | 久久久91| 亚洲视频一区二区三区 | 亚洲国产伊人 | 国产小u女发育末成年 | 国产91综合 | 操久久| 欧美福利 | 国产精品黄色 | 国产亚洲精品精品国产亚洲综合 | 欧美毛片免费观看 | 人人澡人人爱 | 伦理二区 | 亚洲精品一二区 | 午夜电影网 | 日韩精品在线网站 | 久久精品欧美一区二区三区麻豆 | 欧美精品a∨在线观看不卡 欧美日韩中文字幕在线播放 | 欧美一级欧美一级在线播放 | 精品国产乱码久久久久久蜜退臀 | 在线观看中文字幕 | 美女露尿口视频 | 欧美国产精品一区二区三区 | 国产一区二区三区在线视频 | www中文字幕 | 国产9999精品 | 欧美日韩一区二区三区四区五区 |