iT邦幫忙

2021 iThome 鐵人賽

DAY 10
0
Modern Web

30天30個前端任務系列 第 10

#10. Drag & Drop(原生JS版)

第十天的心得

本來想要趁這幾天多做一些Vue的改寫,跟原生JS版同步,但時間上蠻趕的,又遇上一些難題。因此這幾天先以原生JS版為主。可以預期到了第三十天鐵人賽結束,Vue版本應該沒辦法同步完成。但這個系列的文章會持續到Vue版本開發完才會結束。

#10. Drag & Drop

預期效果
從unsplash api取得隨機圖片,渲染到一個方塊中,然後再拖曳到另一個空白的方塊中來填滿。拼圖遊戲應該會用到類似的效果。

請大家先來看CodePen:
https://codepen.io/zyrxdkoz/pen/MWomYzG

實作邏輯

html部分

  <div class="empty">
  // 啟用draggable屬性,是true的話就可以拖曳圖片
    <div class="fill" draggable="true"></div>
  </div>
  <div class="empty"></div>
  <div class="empty"></div>
  <div class="empty"></div>
  <div class="empty"></div>

css部分


.empty {
  height: 150px;
  width: 150px;
  margin: 10px;
  border: solid 3px black;
  background: white;
}

.fill {
  // 使用unsplash api
  background-image: url('https://source.unsplash.com/random/150x150');
  background-size: cover;
  height: 145px;
  width: 145px;
  cursor: pointer;
}

.hold {
  border: solid 5px #ccc;
}

.hovered {
  background-color: #333;
  border-color: white;
  border-style: dashed;
}

@media (max-width: 800px) {
  body {
    flex-direction: column;
  }
}

javascript部分

const fill = document.querySelector('.fill')
const empties = document.querySelectorAll('.empty')

// 在有fill選擇器的div放上監聽器
// ''當中的名稱都是DOM API預設好的行為,行為發生後就啟動相關連的函式
fill.addEventListener('dragstart', dragStart)
fill.addEventListener('dragend', dragEnd)

// 迭代陣列中每個屬性的值
for(const empty of empties) {
    empty.addEventListener('dragover', dragOver)
    empty.addEventListener('dragenter', dragEnter)
    empty.addEventListener('dragleave', dragLeave)
    empty.addEventListener('drop', dragDrop)
}

function dragStart() {
    // 當div被拖曳的時候,加上hold屬性(會出現灰白邊框)
    this.className += ' hold' 
    // 同時也要將div改成白色,但為了避免與hold發生同步衝突,因此使用非同步語法setTimeout來加上invisible選擇器。
    setTimeout(() => this.className = 'invisible', 0)
}

function dragEnd() {
    // 停止拖曳行為後,加回fill選擇器
    this.className = 'fill'
}

function dragOver(e) {
    // 停止瀏覽器預設行為:拒絕透過拖曳來執行submit
    e.preventDefault()
}

function dragEnter(e) {
    // 停止瀏覽器預設行為:拒絕透過拖曳來執行submit
    e.preventDefault()
    // 當拖曳圖片滑過任一個<div>時,加上hovered選擇器
    this.className += ' hovered'
}

function dragLeave() {
// 當拖曳圖片滑過並離開任一個<div>時,將該<div>的class指定為empty。
    this.className = 'empty'
}

function dragDrop() {
    // 清空hovered選擇器
    this.className = 'empty'
    // 拖曳到<div>後放掉,即是dragDrop行為,
    // 此時在<div>當中加入child dom,也就是div.full
    this.append(fill)
}

參考資料:
HTML Drag and Drop API


上一篇
#9. Netflix Sidebar(原生JS版)
下一篇
#11. Color theme switcher + Clock(原生JS版)
系列文
30天30個前端任務19

尚未有邦友留言

立即登入留言