JavaScript >> Javascript 文檔 >  >> JavaScript

在 Vanilla JavaScript 中拖放

簡介

選擇一個項目或文本塊並移動它的行為(拖動 ),然後放置它(dropping ) 在另一個位置被描述為 拖放功能 .

大多數瀏覽器默認選擇可拖動的文本、圖片和鏈接。例如,如果您在任何網站上拖動圖像或基於圖像的標識,“ghost image " 將出現(這不適用於 SVG,因為它們不是圖像)。

注意: 要使其他類型的內容可拖動,您需要使用 HTML5 拖放 (DnD) API外部 JavaScript 庫 .

廣受歡迎的看板 Trello 利用拖放功能使卡片從一個列表移動到另一個列表更容易!在本指南中,我們將構建一些非常相似的東西。

使用 HTML5 拖放 API+

為了在傳統 HTML4 中實現拖放功能,開發人員不得不利用困難的 JavaScript 編程或其他 JavaScript 框架,如 jQuery 等,但 HTML 5 引入了拖放 (DnD) API,為瀏覽器提供原生 DnD 支持,使其成為更容易編碼!

我們幾乎可以使用 API 使我們網站上的任何元素都可拖動。使用鼠標,用戶可以選擇可拖動的項目,將它們拖動到 droppable 元素,然後通過釋放鼠標按鈕放下它們。這同時利用了 DOM 事件範式和拖放事件。

注意: 在拖動操作期間會觸發幾種事件類型,以及某些事件,例如 dragdragover 事件,可能會觸發多次。

拖放事件

在拖放過程的各個階段都會觸發許多事件:

  • 拖動開始: 當用戶開始拖動項目時,會發生此事件。
  • dragenter: 拖動時鼠標第一次移到目標元素上時,觸發該事件。
  • 拖拉機: 當發生拖動時,當鼠標拖動到元素上時會觸發此事件。在偵聽器期間發生的過程通常與 dragenter 事件相同。
  • 拖拽: 當鼠標在拖動過程中離開元素時,觸發該事件。
  • 拖動: 當拖動項目時鼠標移動時,會觸發此事件。
  • 放下: 拖拽操作完成後,drop 在發生放置的元素上觸發事件。偵聽器將負責獲取拖動的數據並將其放置在放置位置。
  • 拖累: 當用戶在拖動項目時釋放鼠標按鈕時,會發生此事件。

開始使用

讓我們構建一個 Trello 板的簡單副本!結果將類似於以下內容:

創建項目和初始標記

讓我們在 HTML 中創建基本結構 - container 有幾個 column 充當任務列表的元素。比如說,第一個列表,對應於“所有任務” 列,最初包含所有任務,我們可以將其拖放到其他列:

<div class="container">
    <div class="column">
        <h1>All Tasks</h1>
        <div class="item">Wash Clothes</div>
        <div class="item">Meeting at 9AM</div>
        <div class="item">Fix workshop</div>
        <div class="item">Visit the zoo</div>
    </div>
    <div class="column">
        <h1>In progress</h1>
    </div>
    <div class="column">
        <h1>Paused</h1>
    </div>
    <div class="column">
        <h1>Under Review</h1>
    </div>
    <div class="column">
        <h1>Completed</h1>
    </div>
</div>

讓我們為 container 添加一些基本樣式 , column s 和 item s:

.container{
    font-family: "Trebuchet MS", sans-serif;
    display: flex;
    gap: 30px;
}
.column{
    flex-basis: 20%;
    background: #ddd;
    min-height: 90vh;
    padding: 20px;
    border-radius: 10px;
}
.column h1{
    text-align: center;
    font-size: 22px;
}
.item{
    background: #fff;
    margin: 20px;
    padding: 20px;
    border-radius: 3px;
    cursor: pointer;
}
.invisible{
    display: none;
}

頁面應該是這樣的:

使對象可拖動

不過,這些對像還不能拖動。他們就在那裡!為了使對象可拖動 - 我們設置它的 draggable true 的屬性 .您網站上的任何內容,包括照片、文件、鏈接和文件,都可以拖動!

讓我們設置 draggable="true" 在我們的 item 元素:

<div class="column">
    <h1>All Tasks</h1>
    <div class="item" draggable="true">Wash Clothes</div>
    <div class="item" draggable="true">Meeting at 9AM</div>
    <div class="item" draggable="true">Fix workshop</div>
    <div class="item" draggable="true">Visit the zoo</div>
</div>

現在元素是可拖動的,它們可以發出拖動事件!讓我們設置事件偵聽器來接收這些事件,並對事件做出反應。

使用 JavaScript 處理拖放事件

讓我們收集要在其上實現拖放的所有項目和列。我們可以使用 document.querySelectorAll() 輕鬆收集它們 DOM 選擇器!這將產生一個 NodeList 數組,我們可以循環處理每個單獨的項目/列:

const items = document.querySelectorAll('.item')
const columns = document.querySelectorAll('.column')

當然 - 如果您沒有要使用的項目列表,您可以單獨選擇它們!

讓我們遍曆元素,並為每個元素添加一個事件偵聽器。我們將為 dragstart 添加一個事件監聽器 和 dragend 事件,以及它們觸發時要運行的函數:

items.forEach(item => {
    item.addEventListener('dragstart', dragStart)
    item.addEventListener('dragend', dragEnd)
});

dragStart() 將在每個 'dragstart' 上運行 事件和 dragEnd() 將在每個 'dragend' 上運行 事件。

注意: 當用戶拖放特定項目時,這些函數可用於添加樣式以獲得更好的視覺交互性,例如您正在移動的卡片的流暢動畫。

讓我們通過記錄消息來測試功能:

function dragStart() {
    console.log('drag started');
}
function dragEnd() {
    console.log('drag ended');
}

偉大的!當一個元素被拖動時 - 事件正在觸發。現在,讓我們將類名應用到卡片上,而不是僅僅記錄消息。讓我們首先讓移動的卡片不可見,使其從原始列表中消失。我們將為拖動的元素設置樣式並為其添加邏輯以使其稍後出現在新列表中。

沒有必要讓元素消失;您還可以通過調整不透明度來使其淡化,以說明它正在從一個位置拖到另一個位置。盡情發揮創意吧!

讓我們修改 dragStart() 功能:

function dragStart() {
    console.log('drag started');
    setTimeout(() => this.className = 'invisible', 0)
}

現在 - 我們不只是與卡片互動。我們還希望與每個進行交互 接受新卡並從舊列中刪除卡。為此,我們希望在列上的事件觸發時運行方法,就像項目一樣!

讓我們循環並添加事件監聽器到 columns

columns.forEach(column => {
    column.addEventListener('dragover', dragOver);
    column.addEventListener('dragenter', dragEnter);
    column.addEventListener('dragleave', dragLeave);
    column.addEventListener('drop', dragDrop);
});

免費電子書:Git Essentials

查看我們的 Git 學習實踐指南,其中包含最佳實踐、行業認可的標準以及隨附的備忘單。停止谷歌搜索 Git 命令並真正學習 它!

讓我們測試一下事件監聽器:

function dragOver() {
    console.log('drag over');
}
function dragEnter() {
    console.log('drag entered');
}
function dragLeave() {
    console.log('drag left');
}
function dragDrop() {
    console.log('drag dropped');
}

當您在瀏覽器中查看此內容時,當您拖動項目時,它們應該會消失,並且當您“跨入”該項目的新列時應該會彈出控制台日誌:

注意: 如果你仔細檢查控制台區域,你會發現 dragDrop() 方法沒有記錄消息。為了使這項工作,您必須禁用 dragOver() 中的默認行為 方法。

function dragOver(e) {
  e.preventDefault()
  console.log('drag over');
}

當您放下項目時,您會注意到現在記錄了“拖放”。

這些都是我們需要的活動!現在,我們只想實現刪除項目的邏輯,當它們被刪除時將它們添加到新列等。由於我們將在某個時間點拖動一個項目,讓我們為其創建一個全局變量。由於我們通常會更改引用,因此它將是 let ,而不是 const .

當拖動開始時 - 我們將設置 this dragItem 的元素 ,將其添加到我們要刪除的列中,並將其設置為 null

let dragItem = null;

function dragStart() {
    console.log('drag started');
    dragItem = this;
    setTimeout(() => this.className = 'invisible', 0)
}

function dragEnd() {
    console.log('drag ended');
  	this.className = 'item'
  	dragItem = null;
}

function dragDrop() {
    console.log('drag dropped');
    this.append(dragItem);
}

注意: 每個發出事件的元素都可以通過 this 訪問 關鍵字,在觸發事件時調用的方法中。

就是這樣 - 我們現在可以將卡片從一列拖放到另一列:

我們不需要使用所有可用的事件來完成這項工作 - 它們已添加並可用於進一步風格化流程。

需要注意的一點是 - 我們按順序將元素添加到 end 每列,總是,因為我們不跟踪它們的相對位置,只是調用 append() 在需要的時候。這很容易通過 Sortable 解決 圖書館!

使用 SortableJS 實現拖放

Sortable 是一個輕量級且簡單的 JavaScript 模塊,它使用原生 HTML5 拖放 API 對對象列表進行排序,就像我們擁有的一樣!它兼容所有當代瀏覽器和触控設備。

中的元素進行排序非常有用 一個列表,並允許您在列中的不同位置拖放元素,而不僅僅是在列之間。這將是我們應用程序的一個很好的補充!

事實上 - 使用 Sortable,我們可以通過一個 group 來完全自動化整個過程 列,每個列可以共享項目。

Sortable 可以通過 CDN 導入:

<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js" integrity="sha512-zYXldzJsDrNKV+odAwFYiDXV2Cy37cwizT+NkuiPGsa9X1dOz04eHvUWVuxaJ299GvcJT31ug2zO4itXBjFx4w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

或者通過 NPM 安裝:

$ npm install sortablejs --save

使用 Sortable 就像實例化一個 Sortable 一樣簡單 對象,在給定的 HTML 元素上:

const column = document.querySelector('.column');

new Sortable(column, {
    animation: 150,
    ghostClass: 'blue-background-class'
});

您可以設置相當多的屬性來自定義流程——我們已經使用了其中的兩個。 animation 是動畫時間,以毫秒錶示,而 ghostClass 可用於風格化拖動元素的“幽靈”外觀!這使得拖動元素的體驗更好。

讓我們回到我們的 Trello 示例,並將 Sortable 應用於任務!它要求我們使用 list-group-item 類而不是 item

<div class="container">
    <div class="column">
        <h1>All Tasks</h1>
        <div class="list-group-item" draggable="true">Wash Clothes</div>
        <div class="list-group-item" draggable="true">Take a stroll outside</div>
        <div class="list-group-item" draggable="true">Design Thumbnail</div>
        <div class="list-group-item" draggable="true">Attend Meeting</div>
        <div class="list-group-item" draggable="true">Fix workshop</div>
        <div class="list-group-item" draggable="true">Visit the zoo</div>
    </div>
    <div class="column">
        <h1>In progress</h1>
    </div>
    <div class="column">
        <h1>Paused</h1>
    </div>
    <div class="column">
        <h1>Under Review</h1>
    </div>
    <div class="column">
        <h1>Completed</h1>
    </div>
</div>

讓我們應用與之前相同的樣式:

.container {
    font-family: "Trebuchet MS", sans-serif;
    display: flex;
    gap: 30px;
}
.column {
    flex-basis: 20%;
    background: #ddd;
    min-height: 90vh;
    padding: 5px;
    border-radius: 10px;
}
.column h1 {
    text-align: center;
    font-size: 22px;
}
.list-group-item {
    background: #fff;
    margin: 20px;
    padding: 20px;
    border-radius: 5px;
    cursor: pointer;
}

現在,讓我們實例化一個 Sortable 對於頁面上的每一列,設置它們的 group"shared" 所以卡片可以在列之間共享:

const columns = document.querySelectorAll(".column");

columns.forEach((column) => {
    new Sortable(column, {
        group: "shared",
        animation: 150,
        ghostClass: "blue-background-class"
    });
});

而已! Sortable 負責其餘的工作:

結論

在本文中,我們了解瞭如何在 HTML5 中拖放元素以及如何使用 JavaScript 可排序庫。


Tutorial JavaScript 教程
  1. 使用 jQuery 在文本框中按回車鍵

  2. 如何在 React JS 中創建管理面板 - 第 1 部分

  3. tsParticles 1.41.0 發布

  4. 在 Windows 10 上的本地 Kubernetes 集群上運行 React 應用程序

  5. Node fs 模塊

  6. 使用 AWS JS 開發工具包清空和刪除多個 S3 存儲桶

  7. 使用 JavaScript 創建 ODM

  1. 你能在一個月內學會 React JS 嗎?

  2. 打印網頁時刪除頁面標題和日期(使用 CSS?)

  3. 將(n)個鍵從對像數組中分離到一個帶有鍵名的數組中

  4. 如何從 Javascript 調用原生 Iphone/Android 函數?

  5. 將 Passport.js 集成到 Node、Express 和 Vue

  6. 成為問題解決者挑戰!

  7. 我剛剛用 React、JSON 和 MaterializeCSS 創建了一個 Google 地球遊戲

  1. 使用 HTML、CSS、JavaScript 創建投資組合網站

  2. 在 JavaScript 中計算最大文件大小限制

  3. 2013 年 25 大 jQuery Mobile 插件

  4. 如何輕鬆讓 PWA 兼容離線展示