溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

js如何實(shí)現(xiàn)滑動穿透

發(fā)布時間:2021-06-29 15:26:51 來源:億速云 閱讀:281 作者:小新 欄目:web開發(fā)

這篇文章將為大家詳細(xì)講解有關(guān)js如何實(shí)現(xiàn)滑動穿透,小編覺得挺實(shí)用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

場景

當(dāng)頁面出現(xiàn)浮層的時候,滑動浮層的內(nèi)容,正常情況下預(yù)期應(yīng)該是浮層下邊的內(nèi)容不會滾動;然而事實(shí)并非如此。

js如何實(shí)現(xiàn)滑動穿透

如圖所示,浮層下邊的內(nèi)容并沒有如想象中不受影響。

解決

先去github上搜索一番,發(fā)現(xiàn)有解決此問題的開源包,簡單粗暴直接挑選了其中star的最高的(body-scroll-lock)操作一番!
使用后發(fā)現(xiàn)有一些問題:

  1. 安卓端全掛

  2. ios端偶爾會有鎖不住的情況

查源碼發(fā)現(xiàn)該包在iOS端使用禁止touchmove的方式單獨(dú)處理,但是在其他端只是給body加overflow: hidden簡單處理。
于是決定寫一個針對多端通用的包來處理類似的問題。

 探索一:overflow: hidden

看到下邊的滾動肯定立刻就想到了是整個viewport的滾動,那么如果給body設(shè)置overflow: hidden,此時body的內(nèi)容就只有一屏了,肯定不會滾動了;

body { overflow: hidden; }

此方案在pc端完美解決了我們的問題,然而事情并沒有那么簡單;

再試試移動端:

js如何實(shí)現(xiàn)滑動穿透

移動端中并沒有出現(xiàn)期待的效果。。。

既然pc端已經(jīng)有了完美的方案,下邊我們繼續(xù)探索移動端的解決方案。

探索二:body定位

上邊想到給body設(shè)置overflow: hidden在移動端并不能解決我們的問題,是否在于body的height沒有設(shè)置

  1. 將html、body的高度都設(shè)置為100%;

  2. 給body設(shè)置絕對定位(fixed);

同時使用這兩個操作似乎完美滿足了我們的需求;

js如何實(shí)現(xiàn)滑動穿透

但是如圖所示,每次都會將頁面拉到最頂上的位置,這樣看起來又不完美了;

既然使用了定位,那么給一個top值不就定位到我們想要的位置了(聰明如我)。

tips: body 設(shè)置 relative 定位會頁面自身拉上去,下邊留白

多次實(shí)驗(yàn)發(fā)現(xiàn)這個方案在android端中完美達(dá)到了我們想要的結(jié)果,但是在ios端并不理想;每次定位的時候會有閃動的問題;好事多磨,接著探索ios端的方案。

探索三:禁止touchmove

如果禁止掉頁面的touchmove是否可行呢?話不多說就是干!
當(dāng)彈出浮層的時候禁掉頁面元素的touchmove

document.addEventListener('touchmove', function (event) {
  event.preventDefault()
})

測試發(fā)現(xiàn)沒有達(dá)到想象中的效果,感覺這個結(jié)果并不能接受啊,禁止document 的touchmove都不能禁止?jié)L動的嗎?
進(jìn)一步的探索后發(fā)現(xiàn)原因竟是這個屬性

passive addEventListener第三個參數(shù)中傳入

原來是瀏覽器做的一些優(yōu)化,chrome passive-event-listeners
Passive Event Listeners是Chrome提出的一個新的瀏覽器特性:Web開發(fā)者通過一個新的屬性passive來告訴瀏覽器,當(dāng)前頁面內(nèi)注冊的事件監(jiān)聽器內(nèi)部是否會調(diào)用preventDefault函數(shù)來阻止事件的默認(rèn)行為,以便瀏覽器根據(jù)這個信息更好地做出決策來優(yōu)化頁面性能。當(dāng)屬性passive的值為true的時候,代表該監(jiān)聽器內(nèi)部不會調(diào)用preventDefault函數(shù)來阻止默認(rèn)滑動行為,Chrome瀏覽器稱這類型的監(jiān)聽器為被動(passive)監(jiān)聽器。
知道問題就好說了,給addEventListener傳入第三個參數(shù)

document.addEventListener('touchmove', function (event) {
  event.preventDefault()
}, { passive: false })

大功告成! 突然想到,如果浮層中還需要滾動那就不GG了! so,是不是可以有選擇性的禁止?jié)L動(在浮層中元素滾動到最頂部或者最底部之后禁止?jié)L動)。 單獨(dú)處理浮層中需要滾動的元素;

targetElement.ontouchmove = function (event) {
  const clientY = event.targetTouches[0].clientY - initialClientY

  if (targetElement && targetElement.scrollTop === 0 && clientY > 0) {
    return preventDefault(event)
  }

  if (targetElement && (targetElement.scrollHeight - 1 - targetElement.scrollTop <= targetElement.clientHeight) && clientY < 0) {
    return preventDefault(event)
  }

  event.stopPropagation()
  return true
}

這個方案在ios中完美實(shí)現(xiàn),但是在 android中還是有一點(diǎn)問題;浮層內(nèi)容拉到最頂部或者最底部的時候依然會帶動頁面的內(nèi)容有一定程度的移動。

js如何實(shí)現(xiàn)滑動穿透

tua-body-scroll-lock

終極方案來啦!

tua-body-scroll-lock即是在ios、android和PC各個端單獨(dú)處理,保證在每個端都可以實(shí)現(xiàn)完美的效果!

demo

安裝

$ npm i -S tua-body-scroll-lock
# OR
$ yarn add tua-body-scroll-lock

使用

移動端

import { lock, unlock } from 'tua-body-scroll-lock'

// 禁止滑動后還需要內(nèi)部可以滾動的元素(針對移動端ios處理)
const targetElement = document.querySelector("#someElementId");

lock(targetElement)
unlock(targetElement)

PC端

tips: PC端不需要targetElement, 不傳targetElement也不想要控制臺提示可以傳null

import { lock, unlock } from 'tua-body-scroll-lock'

lock()
unlock()

關(guān)于“js如何實(shí)現(xiàn)滑動穿透”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

js
AI