移動端拖拽 - 固定定位 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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...