移動端列表頁需實現類似微信的交互:列表項左滑顯示「刪除」按鈕,右滑顯示「編輯」按鈕。核心需求是精準判斷手指滑動方向(左/右/上/下),並區分滑動與點擊、長按等手勢。
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 原生 Touch 事件 | 零依賴、體積小、完全可控 | 需手寫閾值邏輯、跨瀏覽器兼容性差 | 極簡專案、不想引入庫 |
| Hammer.js | 專業手勢識別、支援多點觸控、擴展性強 | 體積 7KB+、API 較複雜 | 複雜手勢識別需求 |
| jQuery Mobile | 內建 swipeleft/swiperight 事件、語法簡潔 | 庫巨大(~200KB)、維護停滯 | 舊專案已引入 jQM |
| TouchSwipe (jQuery 插件) | 輕量(~10KB)、專注滑動、配置豐富 | 需 jQuery 依賴 | jQuery 體系專案首選 |
touchstart 時的 clientX/clientYtouchmove 時計算位移 deltaX/deltaY|deltaX| > |deltaY| 為水平滑動,deltaX > 0 右滑,反之左滑touchend 觸發回調,傳遞方向與位移量function bindSwipe(element, callbacks) {
let startX, startY, startTime;
element.addEventListener('touchstart', e => {
const touch = e.touches[0];
startX = touch.clientX;
startY = touch.clientY;
startTime = Date.now();
}, { passive: true });
element.addEventListener('touchmove', e => {
if (!startX) return;
const touch = e.touches[0];
const deltaX = touch.clientX - startX;
const deltaY = touch.clientY - startY;
// 防止頁面滾動干擾:水平滑動超過閾值時阻止默認
if (Math.abs(deltaX) > 30 && Math.abs(deltaX) > Math.abs(deltaY)) {
e.preventDefault();
}
}, { passive: false });
element.addEventListener('touchend', e => {
if (!startX) return;
const deltaX = e.changedTouches[0].clientX - startX;
const deltaY = e.changedTouches[0].clientY - startY;
const duration = Date.now() - startTime;
// 有效滑動判斷:位移>30px、耗時<300ms、水平為主
if (Math.abs(deltaX) > 30 && duration < 300 && Math.abs(deltaX) > Math.abs(deltaY)) {
callbacks.onSwipe(deltaX > 0 ? 'right' : 'left', Math.abs(deltaX));
}
startX = startY = null;
});
}
// 使用示例
const listItems = document.querySelectorAll('.list-item');
listItems.forEach(item => {
bindSwipe(item, {
onSwipe: (direction, distance) => {
if (direction === 'left') showDeleteBtn(item);
else showEditBtn(item);
}
});
});
transform: translateX() + transition 實現按鈕滑出,避免 JS 頻繁操作 DOM 導致卡頓touchmove 必須設 passive: false 才能調用 preventDefault() 阻止頁面滾動<html> 加 touch-action: pan-y 允許垂直滾動touchend 不觸發,需兼容 touchcancel