Thứ hai, 27/07/2020 | 00:00 GMT+7

Cách tạo phần tử kéo và thả với Vanilla JavaScript và HTML

Kéo và thả là một tương tác user phổ biến mà bạn có thể tìm thấy trong nhiều giao diện user đồ họa.

Có sẵn các thư viện JavaScript để thêm tính năng kéo và thả vào ứng dụng của bạn. Tuy nhiên, có thể có những tình huống mà thư viện không có sẵn hoặc giới thiệu chi phí hoặc phụ thuộc mà dự án của bạn không cần. Trong những tình huống này, kiến thức về các API có sẵn cho bạn trong các trình duyệt web hiện đại có thể đưa ra các giải pháp thay thế.

API Kéo và thả HTML dựa vào mô hình sự kiện của DOM để lấy thông tin về những gì đang được kéo hoặc thả và để cập nhật phần tử đó khi kéo hoặc thả. Với trình xử lý sự kiện JavaScript, bạn có thể biến bất kỳ phần tử nào thành một mục có thể kéo hoặc một mục có thể được thả vào.

Trong hướng dẫn này, ta sẽ xây dựng một ví dụ kéo và thả bằng cách sử dụng API Kéo và thả HTML với JavaScript vani để sử dụng các trình xử lý sự kiện.

Yêu cầu

Để hoàn thành hướng dẫn này, bạn cần :

  • Một trình duyệt web hiện đại hỗ trợ API Kéo và Thả (Chrome 4+, Firefox 3.5+, Safari 3.1+, Edge 18+).

Bước 1 - Tạo dự án và đánh dấu ban đầu

Dự án của ta sẽ bao gồm một containers với hai loại phần tử con:

  • Các phần tử con mà bạn có thể kéo
  • Các phần tử con có thể có các phần tử rơi vào chúng

Đầu tiên, mở cửa sổ terminal của bạn và tạo một folder dự án mới:

  • mkdir drag-and-drop-example

Tiếp theo, chuyển đến folder đó:

  • cd drag-and-drop-example

Sau đó, tạo index.html trong folder đó:

  • nano index.html

Tiếp theo, thêm mã soạn sẵn cho một trang web HTML:

index.html
<!DOCTYPE html> <html>   <head>     <title>My Drag-and-Drop Example</title>     <link rel="stylesheet" href="style.css" />   </head>   <body>   </body> </html> 

Và giữa các <body> thêm mục draggabledropzone (mục tiêu thả) của bạn:

index.html
<div class="example-parent">   <div class="example-origin">     <div       id="draggable-1"       class="example-draggable"     >       draggable     </div>   </div>    <div     class="example-dropzone"   >     dropzone   </div> </div> 

Lưu và đóng file . Sau đó, tạo style.css :

  • nano style.css

Tiếp theo, thêm kiểu cho các phần tử trong index.html của ta :

style.css
.example-parent {   border: 2px solid #DFA612;   color: black;   display: flex;   font-family: sans-serif;   font-weight: bold; }  .example-origin {   flex-basis: 100%;   flex-grow: 1;   padding: 10px; }  .example-draggable {   background-color: #4AAE9B;   font-weight: normal;   margin-bottom: 10px;   margin-top: 10px;   padding: 10px; }  .example-dropzone {   background-color: #6DB65B;   flex-basis: 100%;   flex-grow: 1;   padding: 10px; } 

Điều này sẽ thêm một số định dạng cho ứng dụng. Đến đây bạn có thể xem index.html trong trình duyệt và quan sát rằng điều này tạo ra một <div> draggable và một dropzone <div> .

Ảnh chụp màn hình của div có thể kéo và dropzone

Tiếp theo, ta sẽ làm cho <div> đầu tiên có thể kéo một cách rõ ràng bằng cách thêm thuộc tính draggable :

index.html
<div class="example-parent">   <div class="example-origin">     <div       id="draggable-1"       class="example-draggable"       draggable="true"     >       draggable     </div>   </div>    <div     class="example-dropzone"   >     dropzone   </div> </div> 

Lưu và đóng file .

Cuối cùng, xem lại index.html trong trình duyệt. Nếu ta click vào draggable <div> và kéo nó trên màn hình, có phải là một dấu hiệu cho thấy hình ảnh của nó di chuyển.

Giá trị mặc định cho thuộc tính draggableauto . Điều đó nghĩa là phần tử có thể kéo hay không sẽ được xác định bởi hành vi mặc định của trình duyệt của bạn. Thông thường, điều này nghĩa là các lựa chọn văn bản, hình ảnh và liên kết có thể kéo mà không chỉ định draggable="true" .

Đến đây bạn có một file HTML với phần tử có thể kéo. Ta sẽ chuyển sang thêm trình xử lý onevent .

Bước 2 - Xử lý sự kiện kéo và thả bằng JavaScript

Hiện tại, nếu ta thả chuột trong khi kéo phần tử có thể kéo thì không có gì xảy ra. Để kích hoạt tác vụ kéo hoặc thả trên các phần tử DOM, ta cần sử dụng API Kéo và Thả:

  • ondragstart : xử lý sự kiện này sẽ được gắn liền với ta draggable phần tử và hỏa hoạn khi một dragstart sự kiện xảy ra.
  • ondragover : Trình xử lý sự kiện này sẽ được gắn vào phần tử dropzone của ta và kích hoạt khi sự kiện dragover xảy ra.
  • ondrop : Trình xử lý sự kiện này cũng sẽ được gắn vào phần tử dropzone của ta và kích hoạt khi sự kiện drop xảy ra.

Lưu ý: Tổng cộng có tám trình xử lý sự kiện: ondrag , ondragend , ondragenter , ondragexit , ondragleave , ondragover , ondragstartondrop . Ví dụ của ta , ta sẽ không yêu cầu tất cả chúng.

Trước tiên, hãy tham chiếu file script.js mới trong index.html của ta :

index.html
<body>   ...   <script src="script.js"></script> </body> 

Tiếp theo, tạo một file script.js mới:

  • nano script.js

Đối tượng DataTransfer sẽ theo dõi các thông tin liên quan đến việc kéo hiện tại đang xảy ra. Để cập nhật phần tử của ta khi kéo và thả, ta cần truy cập trực tiếp vào đối tượng DataTransfer . Để làm điều này, ta có thể chọn thuộc tính dataTransfer từ DragEvent của phần tử DOM.

Lưu ý: Đối tượng DataTransfer về mặt kỹ thuật có thể theo dõi thông tin cho nhiều phần tử đang được kéo cùng một lúc. Đối với ví dụ của ta , ta sẽ tập trung vào việc kéo một phần tử.

Các dataTransfer đối tượng của setData phương pháp được dùng để cài đặt các thông tin trạng thái kéo cho phần tử hiện kéo của bạn. Nó có hai tham số:

  • một chuỗi khai báo định dạng của tham số thứ hai
  • dữ liệu thực tế đang được chuyển

Mục tiêu của ta là chuyển phần tử draggable mình sang phần tử mẹ mới. Ta cần có thể chọn phần tử draggable với một id duy nhất. Ta có thể đặt id của phần tử được kéo bằng phương thức setData để nó được dùng sau này.

Hãy truy cập lại file script.js của ta và tạo một hàm mới để sử dụng setData :

script.js
function onDragStart(event) {   event     .dataTransfer     .setData('text/plain', event.target.id); } 

Lưu ý: Internet Explorer 9 đến 11 được báo cáo có vấn đề với việc sử dụng 'text/plain' . Định dạng cần 'text' cho trình duyệt đó.

Để cập nhật kiểu CSS của mục được kéo, ta có thể truy cập lại kiểu của nó bằng sự kiện DOM và bằng cách đặt bất kỳ kiểu nào ta muốn cho currentTarget .

Hãy thêm vào chức năng của ta và thay đổi backgroundColor thành yellow :

script.js
function onDragStart(event) {   event     .dataTransfer     .setData('text/plain', event.target.id);    event     .currentTarget     .style     .backgroundColor = 'yellow'; } 

Lưu ý: Bất kỳ kiểu nào bạn thay đổi cần được cập nhật lại theo cách thủ công khi thả nếu bạn muốn kiểu chỉ kéo. Nếu bạn thay đổi bất kỳ thứ gì khi nó bắt đầu kéo, phần tử được kéo sẽ giữ nguyên kiểu dáng mới đó trừ khi bạn thay đổi lại.

Bây giờ, ta có hàm JavaScript của bạn khi bắt đầu kéo.

Ta có thể thêm ondragstart vào phần tử draggable trong index.html :

index.html
<div class="example-parent">   <div class="example-origin">     <div       id="draggable-1"       class="example-draggable"       draggable="true"       ondragstart="onDragStart(event);"     >       draggable     </div>   </div>    <div class="example-dropzone">     dropzone   </div> </div> 

Xem index.html trong trình duyệt của bạn. Nếu bạn cố gắng kéo mục của bạn ngay bây giờ, kiểu được khai báo trong hàm của ta sẽ được áp dụng:

Ảnh động gif mô tả một phần tử được kéo nhưng không bị rơi

Tuy nhiên, sẽ không có gì xảy ra khi bạn nhả nhấp chuột của bạn .

Trình xử lý sự kiện tiếp theo được kích hoạt trong chuỗi này là ondragover .

Hành vi thả mặc định cho các phần tử DOM nhất định như <div> s trong trình duyệt thường không chấp nhận thả. Hành vi này sẽ chặn hành vi mà ta đang cố gắng thực hiện. Để đảm bảo ta có được hành vi thả mong muốn, ta sẽ áp dụng preventDefault .

Hãy truy cập lại file script.js và tạo một hàm mới để sử dụng preventDefault . Thêm mã này vào cuối file :

script.js
function onDragOver(event) {   event.preventDefault(); } 

Bây giờ, ta có thể thêm ondragover vào phần tử dropzone trong index.html :

index.html
<div class="example-parent">   <div class="example-origin">     <div       id="draggable-1"       class="example-draggable"       draggable="true"       ondragstart="onDragStart(event);"     >       draggable     </div>   </div>    <div     class="example-dropzone"     ondragover="onDragOver(event);"   >     dropzone   </div> </div> 

Đến đây, ta vẫn chưa viết mã xử lý việc giảm thực tế. Trình xử lý sự kiện cuối cùng được kích hoạt trong chuỗi này là ondrop .

Hãy truy cập lại file script.js của ta và tạo một hàm mới.

Ta có thể tham khảo các dữ liệu ta đã lưu trước đó với dataTransfer đối tượng của setData phương pháp. Ta sẽ sử dụng phương thức getData của đối tượng dataTransfer . Dữ liệu ta đặt là id , vì vậy đó là những gì sẽ được trả lại cho ta :

script.js
function onDrop(event) {   const id = event     .dataTransfer     .getData('text'); } 

Chọn phần tử draggable của ta với id mà ta đã truy xuất:

script.js
function onDrop(event) {   // ...    const draggableElement = document.getElementById(id); } 

Chọn phần tử dropzone của ta :

script.js
function onDrop(event) {   // ...    const dropzone = event.target; } 

Nối phần tử draggable của ta vào dropzone :

script.js
function onDrop(event) {   // ...    dropzone.appendChild(draggableElement); } 

Đặt lại đối tượng dataTransfer của ta :

script.js
function onDrop(event) {   // ...    event     .dataTransfer     .clearData(); } 

Bây giờ, ta có thể thêm ondrop vào phần tử dropzone trong index.html :

index.html
<div class="example-parent">   <div class="example-origin">     <div       id="draggable-1"       class="example-draggable"       draggable="true"       ondragstart="onDragStart(event);"     >       draggable     </div>   </div>    <div     class="example-dropzone"     ondragover="onDragOver(event);"     ondrop="onDrop(event);"   >     dropzone   </div> </div> 

Sau khi hoàn tất, ta đã hoàn thành tính năng kéo và thả. Xem index.html trong trình duyệt của bạn và kéo phần tử draggable vào dropzone .

Ảnh động gif mô tả một phần tử bị kéo và thả vào mục tiêu thả

Ví dụ của ta xử lý tình huống của một mục có thể kéo và một mục tiêu thả duy nhất. Bạn có thể có nhiều mục có thể kéo, nhiều mục tiêu thả và tùy chỉnh nó với tất cả các trình xử lý sự kiện API Kéo và Thả khác.

Bước 3 - Xây dựng một ví dụ nâng cao với nhiều mục có thể kéo

Dưới đây là một ví dụ khác về cách bạn có thể sử dụng API này: danh sách việc cần làm với các nhiệm vụ có thể kéo mà bạn có thể di chuyển từ cột "To-do" sang cột "Done" .

Ảnh động gif mô tả nhiều việc cần làm đang được kéo và thả vào cột Xong

Để tạo danh sách việc cần làm của bạn , hãy thêm các phần tử có thể kéo khác với id duy nhất vào index.html :

index.html
<div class="example-parent">   <h1>To-do list</h1>   <div class="example-origin">     To-do     <div       id="draggable-1"       class="example-draggable"       draggable="true"       ondragstart="onDragStart(event);"     >       thing 1     </div>     <div       id="draggable-2"       class="example-draggable"       draggable="true"       ondragstart="onDragStart(event);"     >       thing 2     </div>     <div       id="draggable-3"       class="example-draggable"       draggable="true"       ondragstart="onDragStart(event);"     >       thing 3     </div>     <div       id="draggable-4"       class="example-draggable"       draggable="true"       ondragstart="onDragStart(event);"     >       thing 4     </div>   </div>    <div     class="example-dropzone"     ondragover="onDragOver(event);"     ondrop="onDrop(event);"   >     Done   </div> </div> 

Xem index.html trong trình duyệt của bạn và kéo các mục trong To-làm cột để cột Done. Bạn đã tạo một ứng dụng việc cần làm và thử nghiệm chức năng.

Kết luận

Trong bài viết này, bạn đã tạo một ứng dụng việc cần làm để khám phá chức năng kéo và thả có sẵn cho các trình duyệt web hiện đại.

API Kéo và Thả cung cấp nhiều tùy chọn để tùy chỉnh các hành động của bạn ngoài việc kéo và thả. Ví dụ: bạn có thể cập nhật kiểu CSS của các mục được kéo. Ngoài ra, thay vì di chuyển mục, bạn có thể chọn sao chép mục có thể kéo của bạn để nó được sao chép khi thả.

Lưu ý trong khi nhiều trình duyệt web hỗ trợ công nghệ này, bạn có thể không dựa vào nó nếu đối tượng của bạn bao gồm các thiết bị không hỗ trợ chức năng này .

Để tìm hiểu thêm về tất cả những gì bạn có thể thả với API Kéo và Thả, hãy xem tài liệu của MDN về nó.


Tags:

Các tin liên quan

Hiểu các chữ mẫu trong JavaScript
2020-06-30
Cách sử dụng .map () để lặp lại thông qua các mục mảng trong JavaScript
2020-05-19
Hiểu về cấu trúc hủy, tham số khôi phục và cú pháp trải rộng trong JavaScript
2020-05-12
Cách gỡ lỗi JavaScript với Google Chrome DevTools và Visual Studio Code
2020-05-08
Thanh tiến trình trang với các biến JavaScript và CSS
2020-04-16
Xem xét API JavaScript của trình quan sát thay đổi kích thước
2020-04-16
Xem xét API control panel JavaScript
2020-04-16
Xem xét Đề xuất Nhà điều hành Đường ống JavaScript
2020-04-16
Cách triển khai các phương thức mảng JavaScript từ Scratch
2020-04-09
Các đống nhị phân và hàng đợi ưu tiên qua JavaScript
2020-04-05