作為一名前端萌新,今天終于搞懂了HTML5的拖拽功能!原來(lái)那些像iPad一樣絲滑的拖拽交互,背后是這么實(shí)現(xiàn)的。我們先看看具體效果
下面是我的學(xué)習(xí)筆記,保證通俗易懂,一起看看吧~
一、HTML5拖拽為啥這么牛?
看看你手機(jī)里的APP就知道:拖拽排序、拖拽上傳、拖拽分享...這些操作完全符合人類直覺!HTML5把這種體驗(yàn)帶到了網(wǎng)頁(yè)里,核心就靠draggable
屬性和幾個(gè)神奇的事件:
<div class="fill" draggable="true"></div>
這個(gè)簡(jiǎn)單的屬性就能激活瀏覽器的原生拖拽引擎,比用鼠標(biāo)事件模擬流暢多了!難怪連Google都在用拖拽上傳文件呢。
二、拖拽的完整生命周期
想象一下拖拽的物理過(guò)程:
- 抓起物體 →
dragstart
- 懸停在目標(biāo)上方 →
dragenter
+ dragover
- 移出目標(biāo)區(qū)域 →
dragleave
- 松手放下 →
drop
- 全程結(jié)束 →
dragend
三、手把手實(shí)現(xiàn)圖片拖拽
直接上代碼!這里實(shí)現(xiàn)的是把圖片拖到空白容器中:
?? HTML結(jié)構(gòu)
<body>
<div class="empty">
<div class="fill" draggable="true"></div>
</div>
<div class="empty"></div>
<div class="empty"></div>
<div class="empty"></div>
<div class="empty"></div>
</body>
?? CSS樣式(核心技巧)
* {
box-sizing: border-box;
}
body {
background-color: steelblue;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
margin: 0;
}
.empty {
background: white;
height: 150px;
width: 150px;
margin: 10px;
border: 3px solid #000;
}
.fill {
background-image: url('https://img1.baidu.com/it/u=400864332,910444934&fm=253&fmt=auto&app=138&f=JPEG?w=514&h=500');
width: 145px;
height: 145px;
cursor: pointer;
background-size: cover;
}
.hovered {
background-color: #333;
border-color: white;
border-style: dashed;
}
.hold {
border: 5px solid #ccc;
}
.invisible {
opacity: 0.4;
}
? JavaScript事件處理
const fill = document.querySelector('.fill');
const empties = document.querySelectorAll('.empty');
const body = document.body;
body.addEventListener('dragstart', dragStart);
body.addEventListener('dragend', dragEnd);
for (let empty of empties) {
empty.addEventListener('dragover', dragOver);
empty.addEventListener('dragenter', dragEnter);
empty.addEventListener('dragleave', dragLeave);
empty.addEventListener('drop', drag);
}
function dragStart(e) {
if (!e.target.classList.contains('fill')) {
e.preventDefault();
return;
}
fill.classList.add('hold');
setTimeout(() => {
fill.className = 'invisible';
}, 0);
}
function dragEnd(e) {
fill.className = 'fill';
}
function dragOver(e) {
e.preventDefault();
}
function dragEnter(e) {
e.preventDefault();
e.target.classList.add('hovered');
}
function dragLeave(e) {
e.preventDefault();
e.target.classList.remove('hovered');
}
function drag(e) {
this.className = 'empty';
this.appendChild(fill);
}
四、必知的三個(gè)關(guān)鍵細(xì)節(jié)
阻止默認(rèn)行為是必須的!
function dragStart(e) {
if (!e.target.classList.contains('fill')) {
e.preventDefault();
return;
}
fill.classList.add('hold');
setTimeout(() => {
fill.className = 'invisible';
}, 0);
}
瀏覽器默認(rèn)不允許元素被"扔"到其他元素上。!e.target.classList.contains('fill')
這一點(diǎn)很重要, 否則其他默認(rèn)可拖拽的元素也會(huì)被拖拽,比如圖片
透明化的技巧
setTimeout(() => {
fill.className = 'invisible'
}, 0)
這個(gè)setTimeout
妙在讓瀏覽器先渲染.hold
樣式,再變透明,避免閃爍
classList的精準(zhǔn)控制
用classList.add/remove
代替直接操作className
,避免覆蓋其他樣式
五、移動(dòng)端適配黑科技:媒體查詢
同一個(gè)網(wǎng)頁(yè)在手機(jī)和電腦上顯示不同?全靠這個(gè)神器:
@media (max-width: 800px) {
body {
flex-direction: column;
}
}
這就是響應(yīng)式設(shè)計(jì)的核心!理解這個(gè)就能搞定多設(shè)備適配:
max-width: 800px
→ 小于800px寬度的設(shè)備生效(通常是手機(jī))- 媒體查詢就像CSS的
if語(yǔ)句
:如果屏幕滿足條件,就應(yīng)用這些樣式
可以看到具體效果,當(dāng)右上角的寬度小于800px就會(huì)改變彈性布局的方式 
六、總結(jié):今日重點(diǎn)收獲
技術(shù)點(diǎn) | 核心知識(shí) | 代碼示例 |
---|
拖拽初始化 | draggable="true" 屬性 | <div draggable="true"> |
拖拽事件流 | dragstart → dragover → drop → dragend | 6個(gè)關(guān)鍵事件 |
視覺反饋 | .hold/.hovered樣式類 | 邊框變化+背景色變化 |
阻止默認(rèn)行為 | e.preventDefault() | dragover和dragenter中必須調(diào)用 |
響應(yīng)式布局 | @media媒體查詢 | 根據(jù)屏幕寬度調(diào)整布局 |
經(jīng)驗(yàn)之談:調(diào)試拖拽功能時(shí),一定要在Chrome開發(fā)者工具中打開移動(dòng)設(shè)備模式,測(cè)試手機(jī)上的觸屏操作是否正常!
轉(zhuǎn)自https://juejin.cn/post/7535390325939241001
該文章在 2025/8/7 17:06:15 編輯過(guò)