拖放(Drag 和 drop)功能的简单实现

950 阅读4分钟

说拖拽功能实现的步骤:

1.将想要拖拽的东西设置为可拖拽

2.拖拽的东西要放入目的地

3. 将东西进行上传(如github传输文件到自己的远程仓库)

今天我就对1和2两个进行探讨一下,

一、拖拽单个元素:

<div class="src">    
    <div class="dragable">      
    <div class="txt" id="txt">        
        所有的文字都可以拖拽        
        <p draggable="true">此段文字设置了属性draggable="true"</p>     
     </div>    
    </div>    
    <div id="target">Drop here</div>  
</div>

首先将"此段文字设置了属性draggable="true""设置为鼠标可以进行移动,只要添加属性draggable="true",我们就可以将这段文字进行拖动。

此段文字设置了属性draggable="true"

接着就是对拖拽的元素进行监听,探寻元素到底如何变化?

监听中的事件:

ondrag                          当某个对象被拖动时触发此事件 [活动事件]

ondragdrop                   一个外部对象被鼠标拖进当前窗口或者帧

ondragend                    当鼠标拖动结束时触发此事件,即鼠标的按钮被释放了

ondragenter                  当对象被鼠标拖动的对象进入其容器范围内时触发此事件

ondragleave                  当对象被鼠标拖动的对象离开其容器范围内时触发此事件

ondragover                   当某被拖动的对象在另一对象容器范围内拖动时触发此事

ondragstart                   当某对象将被拖动时触发此事件

ondrop                         在一个拖动过程中,释放鼠标键时触发此事件

事件监听方式:

进行监听要获得监听的对象,并使用监听事件**,使用document.getElementById(" ") 得到的是一个对象。**

let dragSrc = document.getElementById('txt'); // drag

let target = document.getElementById('target'); // drop

dragSrc.ondragstart = handle_start;

事件监听 左事件 右处理函数 其中drag和drop都可以添加监听事件

在Drop here的盒子中释放鼠标键,在ondrap事件进行写入函数(target.innerHTML = dragSrc.innerText;),可以将鼠标拖拽的元素放入Drop here的盒子中

例如: 将"此段文字设置了属性draggable="true""放入id为target盒子中,

还可以在拖拽元素进入目的地实现样式的改变,使用target.classList.add('hover');

在触发函数时, 添加css(.hover)

drag + drop 良好用户体验模拟 css中可以添加cursor:move 拖拽时鼠标会变成手,实现鼠标抓那一下的动作

实现拖拽代码为:

<script>  
let dragSrc = document.getElementById('txt'); // drag   
let target = document.getElementById('target'); // drop 
 target.ondragenter = handle_enter;  
target.ondrop = handle_drop  
function handle_drop(event) {    
event.preventDefault();    
target.innerHTML = dragSrc.innerText;  
}
function handle_enter(event) {    
event.preventDefault();    
// ('handle_enter -当元素进入目的地时触发');    
target.classList.add('hover');  }  }  
</script>

二、拖拽多个元素:

<div class="main">
<div class="left" id="left">
    <div class="txt-show">左边区域</div>      
    <div class="dargable txt" id="txt1" draggable="true">可移动的文字一</div>      
    <div class="dargable txt" id="txt2" draggable="true">可移动的文字二</div>     
    <div class="dargable txt" id="txt3" draggable="true">可移动的文字三</div>     
         <div class="dargable txt" id="txt4" draggable="true">可移动的文字四</div>     
         <div class="dargable txt" id="txt5" draggable="true">可移动的文字五</div>   
     </div>    
    <div class="right" id="right">      
        <div class="txt-show">右边区域</div>    
    </div>  
</div>

进行监听要获得监听的对象,在此处五个元素, 怎么设置它的事件?

不可以在伪数组元素上一次性注册事件, 得一个个来,由于js 事件有冒泡机制 可以设置事件在它们的父元素上。然后使用addEventListener()可以添加事件处理程序,

addEventListener 添加事件处理(一般有三个属性)

    1.事件名 2.事件处理函数 3.一个布尔值

let left = document.getElementById('left')

let target = document.getElementById('right')

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

const target = event.target;

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

})

event.target; 在拖拽元素中,event会返回一个target属性告诉我们那个元素在进行拖动。left.addEventListener('dragstart', (event)在left的对象上添加(ondragstart)事件,当这个对象将被拖动时触发此事件

event.dataTransfer.setData('Text', target.id)拖拽, dataTransfer 属性 好像邮寄一个包裹把target.id带上去并命名为Text

target.addEventListener('drop', (event) => {

event.preventDefault();

let drag_id = event.dataTransfer.getData('Text');

target.appendChild(document.getElementById(drag_id))

})

event.dataTransfer.getData('Text');得到包裹Text('key')中的值

target.appendChild(document.getElementById(drag_id))

向target下最后一个结点后添加一个子节点(document.getElementById(drag_id)

大部分APP和浏览器会有默认的拖拽行为(会用整个显示拖拽内容)

event.preventDefault()可以阻止

实现拖拽代码为:

<script>  
let left = document.getElementById('left') 
 let target = document.getElementById('right')  
left.addEventListener('dragstart', (event) => {   
 const target = event.target;    
event.dataTransfer.setData('Text', target.id)  
})  
left.addEventListener('drag', (event) => {    
console.log('drag');  }) 
 left.addEventListener('dragend', (event) => {    
console.log('dragend');  })  
target.addEventListener('dragenter', (event) => {   
 event.preventDefault();    console.log('dragenter')  })  
target.addEventListener('dragover', (event) => {   
 event.preventDefault();   
 console.log('dragover')  })  
target.addEventListener('dragleave', (event) => {    
event.preventDefault();    
console.log('dragleave')  })  
target.addEventListener('drop', (event) => {    
event.preventDefault();    
let drag_id = event.dataTransfer.getData('Text');    
target.appendChild(document.getElementById(drag_id))    
console.log('拖拽元素离开与原位置,来到目标地址');  })   
 </script>

**三、**拖拽过来的元素完成拖回去:

只有对元素的原地添加相应的事件处理可以了,在id为left对象中添加ondrap事件,再将拖拽回来的内容再将它首位子节点

target.addEventListener('dragstart', (event) => {    
const target = event.target;    
event.dataTransfer.setData('Txt', target.id)  
})
left.addEventListener('drop', (event) => { 
event.preventDefault(); 
let targe_id = event.dataTransfer.getData('Txt');    
left.appendChild(document.getElementById(targe_id)) 
 })

总结:

github 拖拽上传功能中巨大的坑

巨坑1:大部分APP和浏览器会有默认的拖拽行为(会用整个显示拖拽内容)

event.preventDefault()可以阻止

巨坑2:在一个盒子下的五个元素, 怎么设置它的事件?

解释:js 事件有冒泡机制 可以设置事件在它们的父元素上

document

.getElementById('left')

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

console.log('父元素上');

})

但会有 event.target会监听哪个子元素发生拖拽