原生實現html5的拖拽功能 drag and drop

題目

頁面內有一個正方形元素 A 以及一個待放置區域 B,實現對其拖拽和放下到 B 區域內,並且改變 B 區域背景顏色 (不可用 html5 原生事件)。

這也是一道騰訊面試題,要求遠程編程。

思路

  • 用鼠標的mousedown事件來模擬dragstart

  • 用持續的mousedown事件來模擬drag過程,用event的座標來改變相關element的座標

  • 經試驗,H5原生是以被拖拽元素在容器元素中的面積達到一半時可以觸發drop(待確認),簡易版的就不算面積了,以鼠標進入容器中爲準,用mouseup事件作爲觸發條件模擬drop

代碼

html部分

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>demo</title>
  <link rel="stylesheet" type="text/css" href="demo.css" />
</head>

<body>
  <div id="div1"></div>
  <div id="div2"></div>

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

css部分

#div1{
    width:100px;
    height: 100px;
    margin:200px auto;
    background: olive;
}


#div2{
    width: 200px;
    height: 300px;
    position: absolute;
    left:100px;
    top:500px;
    background: lightpink;
}

js部分

//var _origin = {x: div1.offsetLeft, y:div1.offsetTop}
var _newele = document.createElement('div')

var div1Style = getComputedStyle(div1)

var dropFlag = 0, dragFlag = 0

div1.addEventListener('mousedown', (event) => {

    var _ele = event.target

    _newele.style.width = div1Style.width

    _newele.style.height  = div1Style.height

    _newele.style.backgroundColor = div1Style.backgroundColor

    _newele.style.position = 'absolute'

    _newele.style.left = _ele.offsetLeft + 'px'

    _newele.style.top = _ele.offsetTop + 'px'

    _newele.style.zIndex = 1

    _ele.style.position = 'absolute'

    _ele.style.left = _newele.style.left

    _ele.style.top = _newele.style.top

    _ele.style.margin = '0'

    _ele.style.opacity = .5

    _ele.style.zIndex = 2

    document.body.append(_newele)

    dragFlag = 1

})


div1.addEventListener('mouseup', (event) => {

    dragFlag = 0

    console.log(dropFlag)
    // 恢復原樣,簡易版就直接幹掉div1,否則應該存儲所有的style值,幹掉new div,讓div1迴歸原位
    if(!dropFlag){

        document.body.removeChild(div1)
    }

    else{

        console.log('now drop in div2')

        div2.style.backgroundColor = '#ccc000'
    }
})

div1.addEventListener('mousemove',(event) => {

    if(!dragFlag) return false;

    var _ele = event.target

    _ele.style.left = event.clientX  - parseInt(div1Style.width)/2 + 'px'

    _ele.style.top = event.clientY - parseInt(div1Style.height)/2 + 'px'

    if(isEnter({left: event.clientX, top: event.clientY}, div2)){

        dropFlag = 1

        div1.style.cursor = 'copy'
    }

    else{

        dropFlag = 0

        div1.style.cursor = 'move'
    }

})

//mouseenter事件直到mouseup事件觸發後才觸發,不能用mouseenter了,只能用函數判斷鼠標座標是不是在div2元素的範圍內了

function isEnter( point = {left : 0 ,top : 0}, ele ){

    var minLeft = ele.offsetLeft, maxLeft = ele.offsetLeft + ele.offsetWidth

    var minTop = ele.offsetTop, maxTop = ele.offsetTop + ele.offsetHeight

    if( point.left > minLeft && point.left < maxLeft && point.top > minTop && point.top < maxTop){

        //console.log('enter', ele)

        return true
    }  

    return false
}

效果圖

忽略那個圓圈,,,那個是錄屏軟件的。

這裏寫圖片描述

順帶吐個槽,screencastify 還需要load才能使用,不然安裝了也不行。最後用的是mac自帶的 quicktime

拖拽庫

常用的應該是jquery UI 吧。

還有專門的拖放庫dnd.js

HTML5的拖拽API

解決完畢,再來了解一下html5的原生api:HTML5魔法堂:全面理解Drag & Drop API - ^_^肥仔John - 博客園

html5的原生事件版本

div1.addEventListener('dragstart',(event) => {

    //event.dataTransfer.setDragImage(img, 20, 20)

    event.dataTransfer.setData('Text', event.target.id)
})

div2.addEventListener('dragenter',(e) => {

    console.log('now enter the div2')
})

div2.addEventListener('dragover',(e) => {

    e.dataTransfer.dropEffect = 'copy' //chrome 下默認就是copy, 也可以對鏈接用 link 

    e.preventDefault()

})

div2.addEventListener('drop', (e) => {

    var _id = e.dataTransfer.getData('Text')

    e.target.appendChild(document.getElementById(_id))
})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章