移動端拖拽 - 固定定位 fixed

来源:https://www.cnblogs.com/wisewrong/archive/2018/12/13/10113370.html
-Advertisement-
Play Games

移動端的項目經常會引入手勢庫來實現拖拽 不過如果只是一兩個頁面用到拖拽,再引入一個手勢庫就很不划算 最近的項目中就有這麼一個需求: 因為就這一個地方需要拖拽,所以我就沒有引入第三方庫 移動端的拖拽有兩種主流的實現方案: 1. 將元素設置為固定定位,然後在拖拽的時候修改其定位,實現拖拽的效果; 這種 ...


移動端的項目經常會引入手勢庫來實現拖拽

不過如果只是一兩個頁面用到拖拽,再引入一個手勢庫就很不划算

最近的項目中就有這麼一個需求:

因為就這一個地方需要拖拽,所以我就沒有引入第三方庫

 

移動端的拖拽有兩種主流的實現方案:

1. 將元素設置為固定定位,然後在拖拽的時候修改其定位,實現拖拽的效果;

2. 使用 transform 中的平移 translate 屬性實現拖拽。

 

方案一:固定定位 fixed

這種方案的核心就是給元素添加固定定位 position:fixed;

但定位之後,元素會脫離文檔流,會影響原有但佈局

因此在開始拖拽 (觸發 touchstart 事件) 的時候,需要將原本的元素 A 拷貝一份 ( cloneNode() 

給新元素 A2 添加定位,同時給原本的元素 A 設置 visibility: hidden;  使之隱藏並占位

 

1.1 創建遮罩

首先封裝一個創建遮罩的方法,用於放置拷貝出來的元素,並防止誤觸

createModal (id) {
  let modal = document.getElementById(id)
  if (!modal) { // 在沒有遮罩的時候創建遮罩
    modal = document.createElement('div')
    modal.id = id
    modal.style.cssText = `position: fixed; left: 0; top: 0; right: 0; bottom: 0; z-index: 999;`
    document.body.appendChild(modal)
  }
},

 

1.2 開始拖拽

在觸發 touchstart 事件的時候,首先創建遮罩

並通過 getBoundingClientRect() 方法獲取到元素 A 的坐標,記錄起點信息

為了記錄起點信息,需要 data 中創建一個對象 source,用於記錄點擊的位置 client,和初始定位坐標 start

handleTouchstart (e) { // 開始拖拽
  // 創建遮罩層
  this.createModal(this.modalID) // modalID 遮罩層的id,由外部定義

  let element = e.targetTouches[0]
  let target = e.target.cloneNode(true) // 拷貝目標元素
  target.id = this.copyID // copyID 拷貝元素的id,由外部定義

  // 記錄初始點擊位置 client,用於計算移動距離
  this.source.client = {
    x: element.clientX,
    y: element.clientY
  }

  // 算出目標元素的固定位置
  let disX = this.source.start.left = element.target.getBoundingClientRect().left
  let disY = this.source.start.top = element.target.getBoundingClientRect().top
  target.style.cssText = `position: fixed; left: ${disX}px; top: ${disY}px;`

  // 將拷貝的元素放到遮罩中
  document.getElementById(this.modalID).appendChild(target)
},

 

1.3 處理拖拽

拖拽的時候,監聽 touchmove 事件

用【當前滑鼠點位置】減去【初始點擊位置】得到移動的距離

再結合初始坐標信息,更新拖拽元素的坐標 

handleTouchmove (e) { // 拖拽中
  let element = e.targetTouches[0]
  let target = document.getElementById(this.copyID)

  // 根據初始點擊位置 client 計算移動距離
  let left = this.source.start.left + element.clientX - this.source.client.x
  let top = this.source.start.top + element.clientY - this.source.client.y

  // 移動當前元素
  target.style.left = `${left}px`
  target.style.top = `${top}px`
},

 

1.4 拖拽結束

拖拽結束的時候,記錄終點位置,刪除遮罩

handleTouchend (e) { // 拖拽結束
  let end = {
    x: e.changedTouches[0].clientX,
    y: e.changedTouches[0].clientY
  }
  // 刪除遮罩層
  let modal = document.getElementById(this.modalID)
  document.body.removeChild(modal)
  // 處理結果
  this.doingSth(end)
},

不過上面的代碼只實現了拖拽的功能,並沒有對目標元素 A 進行顯示/隱藏的操作

可以根據業務場景自行添加,或者參考方案二

 

 

方案二:平移動畫 translate

 

這種方案更為簡單,不需要創建額外的 DOM 元素

只需對原本的元素添加 transform 屬性,甚至不需要 transition 屬性

然後在拖拽過程中,實時更新 transform: translate(X, Y) 中 x, y 的坐標信息,實現拖拽

 

2.1 開始拖拽

開始拖拽的時候,只需要記錄起點坐標

handleTouchstart (e) { // 開始拖拽
  let element = e.targetTouches[0]// 記錄初始 client 位置,用於計算移動距離
  this.source.client = {
    x: element.clientX,
    y: element.clientY
  }
},

為了防止拖拽的過程中誤觸,建議使用方案一的 createModal() 方法創建一個遮罩

 

2.2 處理拖拽

根據當前坐標和起點坐標,計算出距離,然後更新 translate 的坐標

handleTouchmove (e) { // 拖拽中
  let element = e.targetTouches[0]

  // 根據初始 client 位置計算移動距離
  let x = element.clientX - this.source.client.x
  let y = element.clientY - this.source.client.y

  // 移動當前元素
  element.target.style.cssText = `transform: translate(${x}px, ${y}px);`
},

 

2.3 拖拽結束

拖拽完成後,清除平移動畫

handleTouchend (e) { // 拖拽結束
  // 清除拖拽樣式
  e.target.style.cssText = `transform: none;`
},

 

 

 

小結:

方案一在獲取目標元素的坐標信息的時候使用了 getBoundingClientRect() 方法

但這個方法性能不高,應當少用

而且即時使用了該方法,最後得到的 left 和 top 也不夠精確,touchstart 的時候,元素有明顯的閃動

我的項目使用了 vue.js,但拖拽功能用到 vue 的地方不多,將幾個用於記錄的對象提出來,就能復用於其他框架

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • html文檔結構 1.<!doctype html>聲明為html5文件,必須是html文檔的第一行,在<html>標簽之前; 2.<html>、</html>是文檔開始和結束的標記,是HTML頁面的根元素,在它們之間是文檔的頭部(head)和主體(body); 3.<head>、</head>定義 ...
  • 我們經常將數據存儲在XML 中,在展示的時候需要轉換為其它的形式,這裡介紹使用XSLT 對XML數據進行轉換。 要學習XSLT對XML的轉換,需要先瞭解三個文件。 第一個是存儲數據的XML文件:employees.xml 第二個是存儲XSLT的文件:employees.xslt 第三個是我們進行轉換 ...
  • 聲明 本篇內容摘抄自以下兩個來源: "BootStrap中文網" 感謝大佬們的分享。 正文 響應式佈局(BootStrap) 這次想來講講一個前端開發框架:BootStrap BootStrap 目前已經出了 4 個版本,每個版本都有對應的官網教程,先來看看不同版本里的宣傳語: 簡潔、直觀、強悍的前 ...
  • 概念 Webpack是一個模塊打包機,它可以將我們項目中的所有js、圖片、css等資源,根據其入口文件的依賴關係,打包成一個能被瀏覽器識別的js文件。能夠幫助前端開發將打包的過程更智能化和自動化。 WebPack和Grunt以及Gulp相比有什麼特性 WebPack和Grunt以及Gulp相比有什麼 ...
  • 一、關於選擇器的命名 W3C CSS2.1的 4.1.3 節中提到:標識符(包括選擇器中的元素名,類和ID)只能包含字元[a- zA-Z0-9]和ISO 10646字元編碼U+00A1及以上,再加連字型大小(-)和下劃線(_);它們不能以 數字,或一個連字型大小後跟數字為開頭。它們還可以包含轉義字元加任何I ...
  • 今天工作中使用了這個,感覺很好用啊! 首先: 這個ReactDom是幹嘛用的? 答: react-dom 包提供了 DOM 特定的方法,可以在你的應用程式的頂層使用,如果你需要的話,也可以作為 React模型 之外的特殊操作DOM的介面。 但大多數組件應該不需要使用這個模塊。 其次: 如何引用? 答 ...
  • 首先我們先來林格斯雙擊翻譯一下: split 劈開, 使分裂; splice 接合; 使結合; slice 切成薄片, 切; 我先是這麼區分的:這三個方法最後一個字母是t的是字元串方法,是e的則是數組方法(當然字元串也有slice方法)。 split 是將字元串用符號分割。返回數組。 參數一:指定字 ...
  • 本文主要介紹了vue-router相關基礎知識及單頁面應用的工作原理,寫的十分的全面細緻,具有一定的參考價值,對此有需要的朋友可以參考學習下。如有不足之處,歡迎批評指正。 單頁面工作原理是通過瀏覽器URL的#後面的hash變化就會引起頁面變化的特性來把頁面分成不同的小模塊,然後通過修改hash來讓頁 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...