使用拖曳效果,進化寶可夢吧!
最近時不時的就可以看到 Pokemon GO 的廣告在電視、網路媒體上出現,這波行銷宣傳打的可真兇哪!
回想起小時候那個寶可夢還叫做神奇寶貝的年代(遠目...),為了每週六晚上的寶可夢卡通,客廳必定會上演的遙控器搶奪戰;不然就是在學校上課偷打寶可夢 Game Boy 的美好歲月,那些都是我一去不復返的童年時光啊~(喂喂喂,扯遠了!)
前言
咳咳,回歸正題,為了紀念一下那逝去的美好,於是就用寶可夢最迷人的特點「進化」為題,寫了一個互動操作效果,用滑鼠拖動進化石到伊布身上來進化牠(如圖)
這種可以用拖曳的方式來移動進化石的操作,叫做「拖曳效果」。而以下就簡單的介紹「拖曳效果」是怎麼做出來的吧!
也可以點此「進化吧,寶可夢!」自己操作看看唷
好啦,我知道要進化太陽精靈和月精靈不是用進化石,但這不是重點請忽略它╮(′~‵〞)╭
Ps:除了拖曳外,其他大部分的效果都是偽元素的應用,想更了解偽元素可以點此全都是假的,一起來認識偽元素!
基本認識
在以前的時候,據說要製作出這種拖曳效果是非常不容易的事,得要有一大堆的語法配合才能實現這種效果。但在現在最新的 HTML5 中,已經有直接的 Drag 與 Drop 機制,讓我們得以用更簡潔的方式來實現出拖曳的效果,真的是瞬間便利了不少啊!
在 HTML5 中提供了多種可用來觸發拖曳的監聽事件,這些事件所監聽的對象大致上可分為 Drag Source 和 Drop Target 兩種。
- Drag Source: 指的是「拖曳對象」,意即被點擊要拖曳的物件
- Drop Target: 指的是「放置目標」,意即拖曳的物件被放置的區域
Drag Source 和 Drop Target 兩種監聽對象的事件有不少,以下列舉這次範例使用到的幾個,也是比較常運用的幾個監聽事件:
有關「拖曳對象」的監聽事件
- dragstart :當滑鼠按住拖曳對象不放,且拖曳時的瞬間觸發
- drag:在拖動拖曳對象的這段期間持續觸發
有關「放置目標」的監聽事件
- dragenter:當拖曳對象首次進入放置目標的範圍時觸發
- dragover :當拖曳對象位在放置目標的範圍內時,會持續觸發
- drop :當拖曳對象在放置目標的範圍內被釋放時觸發(也就是放開滑鼠的時候)
好了,關於 Drag 與 Drop 機制的基礎認識就先到這邊,接下來,我們就一步一步地來說明該怎麼運用 Drag 與 Drop 囉!
拖曳對象的設置
一般來說,除了 <a>
和 <img>
這兩個元素之外,其他的 HTML 的元素都是預設為不可被拖曳的。但在 HTML5 中只要添加上 draggable="true"
這個屬性之後,它就可以「被拖曳」囉。
因此製作拖曳效果的第一個步驟,便是先對要被拖曳的元素, 加上 draggable="true"
這個屬性,如下:
<div id="element" draggable="true">拖曳對象</div>
<div id="container">放置目標</div>
好了,現在 element 這個元素已經被設定為「可拖曳」的狀態了,那麼接下來的第二個步驟,便是要運用 JavaScript 對 element 這個元素設置監聽事件,如此一來,當 user 在使用滑鼠拖曳時,才能觸發相應的拖曳效果。
對要被拖曳的元素 element 設置 dragstart
這個監聽事件:
let el = document.querySelector('#element');
el.addEventListener('dragstart', dragStart);
當拖曳對象剛被拖動時,觸發把「拖曳對象」的內容放進「放置目標」內:
function dragStart(e) {
e.dataTransfer.setData('text/plain', e.target.id)
};
OK ,有關於「拖曳對象」的設定先到這邊,接下來要進行的是「放置目標」部分的設置。
放置目標的設置
在正常的狀況下,元素是不能被放置拖曳物的,因此我們得要用 JavaScript 針對要放置拖曳物的元素進行一些設定,好讓這個元素變成可以放置拖曳物的「容器」。
對要放置元素的 container 容器,設置 dragenter
、 dragover
和 drop
三個監聽事件:
let container = document.querySelector('#container');
container.addEventListener('drop', dropped);
container.addEventListener('dragenter', cancelDefault);
container.addEventListener('dragover', cancelDefault);
當拖曳對象被滑鼠拖到放置目標上釋放時,就把 id 從資料中取出來,然後利用 id 把 DOM 抓過來:
function dropped(e) {
cancelDefault(e)
let id = e.dataTransfer.getData('text/plain');
e.target.appendChild(document.querySelector(`#${id}`));
};
元素預設行為是不能被放置拖曳物的,因此在拖曳對象出現在放置目標上時,取消預設行為,讓放置目標可以被放置:
function cancelDefault(e) {
e.preventDefault();
e.stopPropagation();
return false
};
設定多個容器:
在放置目標的「容器」可以設置很多個,我們甚至可以改用 class 選擇器來做 JavaScript 的設定:
<div class="container"></div>
<div class="container"></div>
<div class="container"></div>
let container = document.querySelectorAll('.container');
// 用 forEach 來做多個 class 的監聽事件綁定
container.forEach(container => {
container.addEventListener('drop', dropped);
container.addEventListener('dragenter', cancelDefault);
container.addEventListener('dragover', cancelDefault);
})
另外一提的是,同一個選擇器是無法設置多個「拖曳物件」的喔,這點要特別要注意!
只要運用上面的語法,再加上一點 CSS 的設定後,就可以做出如下圖的效果囉!
觀看完整程式碼可點擊此處!
補充語法
在上面範例中有運用到了一些不是很常見的語法,所以在這邊做一個小統整,不過因為這每一個項目都可以再寫一篇文章了,所以這邊只做個簡單介紹,想知道更詳盡的內容的話可以自行 Google 一下囉。
- dataTransfer.setData
用來設置當拖曳對象放到放置目標時,所能取得的資料類型。 - target
用來找到觸發事件的 DOM 元素。 - appendChild
將一個 DOM 元素添加到指定的父元素內 ( 如果該父元素內已經有子元素,那麼添加的元素會排在所有子元素的最後面 )。 - preventDefault
阻止元素觸發預設的行為 ( 例如點擊 a 元素時會觸發開啟鏈結網址的行為 ) 。 - stopPropagation
阻止當前事件繼續進行捕捉 ( capturing ) 及冒泡 ( bubbling ) 階段的傳遞。
小結
一開始接觸 Drag 與 Drop 機制的時候可能會覺得有點小複雜,但是如果能弄清楚他的各種監聽事件與原理,其實這個效果要實作出來並不算太難。那麼,以上就是有關拖曳效果的簡單介紹囉!