iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0

在實現拖放功能時,我考慮了兩種主要方法:一是使用原生的 HTML5 拖放 API,另一是利用 touchstart 觸碰事件。綜合考慮後,我選擇了使用觸碰事件,主要因為 HTML5 的拖放 API 直到近年才獲得較為廣泛的支援。

drag and drop 範例

但我這裡仍想對補充一下 拖放 API 的寫法。

主要功能

  1. 從 "拖動區域" 拖動項目。
  2. 將項目拖到 "放置區域"。
  3. 被拖放的項目會出現在 "放置區域" 的列表中,並從 "拖動區域" 的列表中消失。

方法:

  • dragStart(event, item):這個方法在拖動開始時被觸發。它設置 draggedItem 並初始化拖動數據。
  • drop(event):這個方法在項目被放置時被觸發。它將拖放的項目添加到 droppedItems 陣列中,並從 items 陣列中移除該項目。

這個程式碼示例提供了一個基本但完整的拖放互動的模型,包括從一個列表拖動項目並將其放置到另一個列表中。

範例連結

遊戲裡的 touchstart, touchend 實作

與拖放 API 的差異是我將 touchstart 跟 touchend 事件綁在同一個元素上。然後用 touchmove 的事件來抓取移動位置是否是在放置的範圍裡,或說是來決定放置位置。

拖曳開始

const handleClueCardTouch = (cardIndex, ev) => {

    //為防止 iOS safari 觸發重新整理頁面
    ev.preventDefault();

    //當開始拖曳就把一開始教學動畫取消
    isShowTip.value = false;

    //抓取最上層的作答卡片並初始化卡片跟手指的位置
    currentClueCardEl.value = clueCardEl.value[cardIndex];
    document.body.append(currentClueCardEl.value);
    setCurrentClueCardMove(ev.touches[0].pageX, ev.touches[0].pageY - currentClueCardEl.value.offsetHeight / 2);
    
    //開始跟著手指移動
    document.addEventListener('touchmove', handleClueCardMove);
};

拖曳進行中

const handleClueCardMove = (ev) => {
    ev.preventDefault();

    //純錯的更新移動位置 
    if (isMobile()) {
        setCurrentClueCardMove(ev.touches ? ev.touches[0]?.pageX : ev.pageX, (ev.touches ? ev.touches[0]?.pageY : ev.pageY) - currentClueCardEl.value.offsetHeight / 2);
    } else {
        setCurrentClueCardMove(ev.pageX, ev.pageY - currentClueCardEl.value.offsetHeight / 2);
    }

    //另外拆出判斷作答位置的邏輯
    handleAnswerProcess();
};

放掉拖曳


const handleClueCardTouchOff = async (cardIndex, ev) => {
    ev.preventDefault();
    let isCurrentAnswerCorrect = false;

    if (isShowHint.value) {
        // 邏輯 略 如果有在作答區域內就進一步判斷卡片放置作答位置 
    } else {
        // 如果作答卡片不在作答位置,就將卡片放回原位
        setCurrentClueCardMove(0, 0);
        clueCardContainerEl.value.append(currentClueCardEl.value);
    }
    
    // 無論如何收合拉伸的時間軸
    handleTimelineContainerExtend(false);
    
    // 移除監聽事件
    document.removeEventListener('touchmove', handleClueCardMove);
};

[補充] 觸碰事件 VS 拖曳事件

touchstart

  1. 觸碰事件:touchstart 是一個觸碰事件,主要用於觸碰螢幕設備,如智慧型手機和平板電腦。
  2. 多點觸控:它支持多點觸控,我們可以通過事件對象來獲取多個觸碰點的資訊。
  3. 通用性:touchstart 可用於任何類型的元素和交互,不僅僅是拖放。
  4. 手動實現拖放:如果使用 touchstart 來實現拖放,需要手動處理所有相關的邏輯,包括元素的移動、放置等。
  5. 跨平台:主要用於移動設備,但也可以在一些桌面瀏覽器中使用(如果它們支持觸碰事件)。

dragstart

  1. 拖放事件:dragstart 是一個拖放事件,主要用於實現拖放交互。
  2. 單點互動:僅支持單點互動,即使用滑鼠或單點觸碰。
  3. 專用於拖放:這個事件是專為拖放交互而設計的,並且與一系列其他拖放事件(如 dragend、dragover、drop 等)一起使用。
  4. 內建邏輯:瀏覽器提供了一些內建的拖放邏輯,如顯示拖動圖標、處理放置目標等。
  5. 跨平台:主要用於桌面瀏覽器,但也可以在支持拖放事件的移動瀏覽器中使用。

小結

  • 使用 touchstart 可能會更靈活,但需要我們手動實現更多的邏輯。
  • 使用 dragstart 可以讓我們更容易地實現拖放交互,但它可能不適用於所有類型的設備和交互。

[補充] 滑鼠事件 VS 觸碰事件

滑鼠事件

  1. click:當用戶按下滑鼠按鈕時觸發一次。通常用於簡單的互動,如按鈕點擊,但不適用於拖放操作。
  2. mousedown:當用戶按下滑鼠按鈕時觸發。這通常是啟動拖放操作的起點。
  3. mousemove:當用戶移動滑鼠時觸發。在拖放操作中,這用於更新被拖動元素的位置。

觸碰事件

  1. touchstart:當使用者觸碰螢幕時觸發。這相當於滑鼠的 mousedown 事件,通常用作拖放操作的起點。
  2. touchmove:當使用者移動觸碰點時觸發。這相當於 mousemove,用於更新被拖動元素的位置。
  3. touchend:當用戶停止觸碰時觸發。這相當於 mouseup,標誌著拖放操作的結束。

注意事項

  1. 移動設備和桌面的差異:移動設備主要使用觸碰事件,而桌面則使用滑鼠事件。因此,為了使拖放功能在所有設備上都能正常工作,就可能需要同時處理這兩種類型的事件。
  2. 事件順序:了解事件的觸發順序也很重要。例如,mousedown 或 touchstart 通常會在 click 之前觸發。
  3. 防止默認行為:在某些情況下,我們需要使用 event.preventDefault() 來防止瀏覽器的默認行為。這尤其在處理觸碰事件時很常見。
  4. 多點觸控:觸碰事件允許多點觸控,這意味著我們可以同時追踪多個觸碰點,但就必須處理更複雜的觸碰邏輯,需要在定義需求時更加地仔細。

上一篇
功能製作 遊戲說明與燈箱
下一篇
功能製作 (drag and drop mobile 下)
系列文
打造紐時風格的時間線小遊戲30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言