【輪播圖】H5端輪播圖、橫向滑動、劃屏效果實現方案——Vue3+CSS position/CSS scroller

文章目錄

  • 定位實現滑屏效果
    • 前置知識
      • CSS: touch-action屬性
      • CSS: transform屬性
      • 觸摸事件
      • forEach
      • 回調占位符
    • 準備階段
    • 實現移動效果
    • 實現跟手效果
    • 觸摸結束優化
    • 完整代碼
  • 滾動實現滑屏效果
    • 前置知識
      • CSS: scroll-snap-type屬性
    • 準備階段
    • 實現滑動效果
    • 實現吸附效果
    • 滾動條隱藏
    • 存在問題
    • 完整代碼
  • scrollLeft實現滑屏效果(最佳實踐)
    • 前置知識
      • DOM: scrollLeft
      • DOM: scrollWidth
      • @scroll事件
    • 準備階段

????本文將詳細介紹如何使用Vue3實現移動端流暢的劃屏交互效果。我們將深入探討觸摸事件處理、頁面動態切換和動畫優化的完整實現方案。文章將重點解析三個關鍵方法: handleTouchStart記錄觸摸起點、 handleTouchMove實現實時跟手效果、 handleTouchEnd處理頁面切換邏輯,特別會講解 pages.forEach循環在重置頁面位置和恢復過渡動畫中的重要作用。同時會分享性能優化技巧,包括transform動畫的優勢、直接DOM操作與Vue響應式的平衡,以及滑動閾值的合理設置,幫助開發者掌握移動端滑動交互的核心實現原理。


定位實現滑屏效果

實現了一個典型的移動端頁面滑動容器,具有以下特點:

  • 支持左右滑動切換不同顏色的頁面
  • 滑動時有實時跟手效果
  • 滑動結束后有平滑的過渡動畫
  • 邊界檢測防止越界

前置知識

CSS: touch-action屬性

touch-action 是 CSS 的一個屬性,用來控制元素如何響應觸摸操作(如滑動、縮放等)。

常見取值:

  • auto:默認,瀏覽器自行處理觸摸行為。
  • none:完全禁用瀏覽器默認的觸摸行為(如滾動、縮放)。
  • pan-x:允許水平滑動,禁止垂直滑動和縮放。
  • pan-y:允許垂直滑動,禁止水平滑動和縮放。
  • manipulation:允許滑動,但禁用雙擊縮放(提高響應速度)。

示例:

/* 禁用默認觸摸行為,防止滾動 */
.prevent-scroll {touch-action: none;
}/* 只允許垂直滑動 */
.vertical-only {touch-action: pan-y;
}

適用場景:

  • 自定義觸摸手勢(如畫板、游戲)。
  • 防止滑動沖突(如地圖內嵌滾動列表)。

簡單說,它讓開發者能精細控制觸摸交互,避免瀏覽器默認行為的干擾

CSS: transform屬性

transform: 是 CSS 中**把元素當成一張圖來變形**的屬性。
一次可以寫多個 2D/3D 函數,空格隔開,按從左到右的順序逐個執行。

  1. 常用 2D 函數
函數說明例子
translate(x, y)平移transform: translate(20px, -10px)
translateX(x) / translateY(y)單軸平移translateX(50%)
scale(sx, sy)縮放scale(1.2, .8)
rotate(angle)旋轉rotate(45deg)
skew(ax, ay)傾斜skew(30deg, 10deg)
  1. 常用 3D 函數
函數說明
translate3d(x,y,z)三維平移
scale3d(sx,sy,sz)三維縮放
rotateX(a) / rotateY(a) / rotateZ(a)繞各軸旋轉
  1. 組合示例
.box {transform: translateX(100px) rotate(45deg) scale(1.2);
}

先右移 100 px,再旋轉 45°,最后放大 1.2 倍。

  1. 性能與注意點
  • 不占文檔流:變形后原位置仍保留(不像 position:absolute 會脫離)。
  • 硬件加速:大多數瀏覽器對 transform 開 GPU 加速,動畫較流暢。
  • 不影響兄弟元素:不會像 margin 那樣推擠別人。

觸摸事件

HTML 的觸摸事件有 4 個核心,按觸發順序:

  • touchstart:手指剛碰到屏幕
  • touchmove:手指在屏幕上滑動(連續觸發)
  • touchend:手指離開屏幕
  • touchcancel:系統中斷(如來電、彈窗)

每個事件對象里都帶 touches / changedTouches 等列表,可拿到觸點坐標。

事件對象屬性:

  • touches:當前屏幕上所有接觸點集合。
  • targetTouches:事件綁定元素上的接觸點集合。
  • changedTouches:觸發此事件時狀態改變的接觸點集合(touchstart時即新出現的點)。

forEach

forEach 是數組的每個元素都跑一次的方法——給它一個回調函數,它把數組里的元素挨個傳進去執行,不返回新數組,純粹“副作用”。

基本語法:

array.forEach((value, index, array) => {/* 干點啥 */
});
  • value:當前元素
  • index:當前下標(可選)
  • array:原數組本身(幾乎不用)

示例:

['a','b','c'].forEach((v,i)=>console.log(i,v));
// 0 a
// 1 b
// 2 c

回調占位符

在 JavaScript 的 forEach 回調里:

pages.forEach((_, i) => { ... })

_ 就是占位符:

  • 含義:“這個位置的參數我不打算用,隨便起個名字占坑”。

  • 這里_對應的是數組元素(page 對象),但循環體里只用索引 i,所以用_表示“忽略它”。

這是一種常見習慣寫法,讀代碼的人一看就明白“這個值被故意忽略了”。

準備階段

基本結構代碼:

<template><divclass="page-container"@touchstart="handleTouchStart"@touchmove="handleTouchMove"@touchend="handleTouchEnd"><!-- 頁面內容 --><divv-for="(page, index) in pages":key="page.id"class="page":style="{ backgroundColor: page.color }">{{ page.name }}</div></div>
</template><script setup>
import { ref } from "vue";const pages = [{ color: "#ff7675", name: "屏幕 1", id: 0 },{ color: "#74b9ff", name: "屏幕 2", id: 1 },{ color: "#55efc4", name: "屏幕 3", id: 2 },{ color: "#a29bfe", name: "屏幕 4", id: 3 },{ color: "#ffcb20", name: "屏幕 5", id: 4 },
];// 觸摸開始
const handleTouchStart = (e) => {};// 觸摸移動
const handleTouchMove = (e) => {};// 觸摸結束
const handleTouchEnd = () => {};</script><style scoped>
.page-container {}
.page {}
</style>

目前沒有樣式的效果如下:
在這里插入圖片描述
所有內容都是堆疊在一起的,而目前我們想要的效果是每個屏幕沾滿一個頁面,然后通過滑動來切換,

先給內容來個沾滿全屏的寬度高度

.page-container {width: 100vw;height: 100vh;
}
.page {width: 100%;height: 100%;
}

在這里插入圖片描述
在處理一下page中的文字樣式吧:

.page {width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;font-size: 50px;font-weight: 700;color: aliceblue;
}

在這里插入圖片描述
現在所有頁面都是呈現豎向排列的,與我們橫向滑動的效果相違背,所以需要使用定位效果將 所有頁面重疊在一起,然后再做移動效果來實現劃屏效果

.page-container {width: 100vw;height: 100vh;position: relative;overflow: hidden;touch-action: none;
}
.page {width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;font-size: 50px;font-weight: 700;color: aliceblue;position: absolute;
}

在這里插入圖片描述

現在,所有屏幕都堆疊在一起了! 接下來使用transform屬性讓所有屏幕從左至右以此排列:
在這里插入圖片描述

:style="{transform: `translateX(${index * 100}%)`,backgroundColor: page.color,}"

可能看不出效果,我們可以調小page 的寬高查看:width: 20%; height: 20%;
在這里插入圖片描述

實現移動效果

接下來的內容就是重點啦!🫵💯

移動實現原理:視窗不變,讓每個page分別向負方向移動
在這里插入圖片描述

<!-- 頁面內容 --><divv-for="(page, index) in pages":key="page.id"class="page":style="{transform: `translateX(${index * 100 - currentIndex * 100}%)`,backgroundColor: page.color,}">{{ page.name }}</div>// 聲明一個currentIndex 
import { ref } from "vue";
const currentIndex = ref(0); // 當前頁面索引

可以通過改變const currentIndex = ref(2);中的變量來查看頁面效果。
在這里插入圖片描述
曉得了切換原理,接下來實現觸摸事件啦🫴
流程示意圖:
在這里插入圖片描述

const currentIndex = ref(0); // 當前頁面索引
const startX = ref(0);
const moveX = ref(0);
// 觸摸開始:記錄起點
const handleTouchStart = (e) => {startX.value = e.touches[0].clientX;
};// 觸摸移動:實時跟隨手指滑動
const handleTouchMove = (e) => {moveX.value = e.touches[0].clientX - startX.value;
};// 觸摸結束:判斷滑動方向并切換頁面
const handleTouchEnd = () => {if (Math.abs(moveX.value)) {if (moveX.value > 0 && currentIndex.value > 0) {currentIndex.value--; // 向右滑,上一頁} else if (moveX.value < 0 && currentIndex.value < pages.length - 1) {currentIndex.value++; // 向左滑,下一頁}}
};

現在就可以通過滑動屏幕來實現切換效果了:
在這里插入圖片描述

觸發的有點靈敏,我們給handleTouchEnd添加一個滑動閾值

const handleTouchEnd = () => {const threshold = 50; // 滑動閾值(像素)if (Math.abs(moveX.value) > threshold) {if (moveX.value > 0 && currentIndex.value > 0) {currentIndex.value--; // 向右滑,上一頁} else if (moveX.value < 0 && currentIndex.value < pages.length - 1) {currentIndex.value++; // 向左滑,下一頁}}
};

再添加一個css平滑過渡效果:

.page {//...transition: transform 0.3s ease; /* 平滑過渡 */
}

在這里插入圖片描述

實現跟手效果

現在就要點絲滑😻效果了,不過還不夠還要添加跟手效果

  <!-- 頁面內容 -->
<divv-for="(page, index) in pages":key="page.id"class="page"ref="pageRef":style="{transform: `translateX(${index * 100 - currentIndex * 100}%)`,backgroundColor: page.color,}"
>{{ page.name }}
</div>const pageRef = ref(null);
// 觸摸移動:實時跟隨手指滑動
const handleTouchMove = (e) => {moveX.value = e.touches[0].clientX - startX.value;// 跟手效果pages.forEach((_, i) => {const page = pageRef.value[i];if (page) {page.style.transform = `translateX(${i * 100 - currentIndex.value * 100 + moveX.value / 10}%)`;page.style.transition = "none"; // 禁用過渡效果,保證跟手效果流暢}});
};

在這里插入圖片描述

實現原理詳解

  1. 獲取移動距離
    • moveX.value = e.touches[0].clientX - startX.value 計算出手指從觸摸開始到當前位置的水平移動距離
  2. 實時更新頁面位置
    • 遍歷所有頁面元素,為每個頁面計算新的transform
    • 基礎位置:i * 100 - currentIndex.value * 100 確保頁面按順序排列
    • 跟手偏移:+ moveX.value / 10 添加移動距離的1/10作為跟手效果(除以10是為了降低跟手靈敏度)
  3. 禁用過渡效果
    • page.style.transition = "none" 臨時禁用CSS過渡效果,確保跟手時的即時響應

觸摸結束優化

// 觸摸結束:判斷滑動方向并切換頁面
const handleTouchEnd = () => {//....// 重置位置并啟用過渡動畫pages.forEach((_, i) => {const page = document.querySelectorAll(".page")[i];if (page) {page.style.transform = `translateX(${i * 100 - currentIndex.value * 100}%)`;page.style.transition = "transform 0.3s ease";}});moveX.value = 0;
};

handleTouchEnd 里那段 pages.forEach(...) 只有一句話:把 5 張“頁面”一次性擺到正確位置,并補上過渡動畫

  1. 計算目標位置

    i * 100 - currentIndex.value * 100
    
    • i * 100:第 i 張默認排在“第 i 屏”位置(0%、100%、200% …)。
    • 減去 currentIndex * 100:把當前要顯示的那一頁拉回 0%(即屏幕正中)。
      結果:所有頁瞬間排成一排,當前頁居中,其余頁在左右兩側。
  2. 設置樣式

    • transform 賦剛才算出的值,讓頁面“歸位”。
    • transition = "transform 0.3s ease":把被 handleTouchMove 關掉的過渡重新打開,回彈時有動畫。
  3. 重置 moveX.value = 0:為下一次手勢準備。

最后得到的效果如下:( 對此我們的輪播圖實現效果也完成啦🎉)
在這里插入圖片描述

完整代碼

<template><divclass="page-container"@touchstart="handleTouchStart"@touchmove="handleTouchMove"@touchend="handleTouchEnd"><!-- 頁面內容 --><divv-for="(page, index) in pages":key="page.id"class="page"ref="pageRef":style="{transform: `translateX(${index * 100 - currentIndex * 100}%)`,backgroundColor: page.color,}">{{ page.name }}</div></div>
</template><script setup>
import { ref } from "vue";const pages = [{ color: "#ff7675", name: "屏幕 1", id: 0 },{ color: "#74b9ff", name: "屏幕 2", id: 1 },{ color: "#55efc4", name: "屏幕 3", id: 2 },{ color: "#a29bfe", name: "屏幕 4", id: 3 },{ color: "#ffcb20", name: "屏幕 5", id: 4 },
];
const currentIndex = ref(0); // 當前頁面索引
const startX = ref(0);
const moveX = ref(0);
// 觸摸開始:記錄起點
const handleTouchStart = (e) => {startX.value = e.touches[0].clientX;
};const pageRef = ref(null);
// 觸摸移動:實時跟隨手指滑動
const handleTouchMove = (e) => {moveX.value = e.touches[0].clientX - startX.value;// 跟手效果pages.forEach((_, i) => {const page = pageRef.value[i];if (page) {page.style.transform = `translateX(${i * 100 - currentIndex.value * 100 + moveX.value / 10}%)`;page.style.transition = "none"; // 禁用過渡效果,保證跟手效果流暢}});
};// 觸摸結束:判斷滑動方向并切換頁面
const handleTouchEnd = () => {const threshold = 200; // 滑動閾值(像素)if (Math.abs(moveX.value) > threshold) {if (moveX.value > 0 && currentIndex.value > 0) {currentIndex.value--; // 向右滑,上一頁} else if (moveX.value < 0 && currentIndex.value < pages.length - 1) {currentIndex.value++; // 向左滑,下一頁}}// 重置位置并啟用過渡動畫pages.forEach((_, i) => {const page = pageRef.value[i];if (page) {page.style.transform = `translateX(${i * 100 - currentIndex.value * 100}%)`;page.style.transition = "transform 0.3s ease";}});moveX.value = 0;
};
</script><style scoped>
.page-container {width: 100vw;height: 100vh;position: relative;overflow: hidden;touch-action: none;
}
.page {width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;font-size: 50px;font-weight: 700;color: aliceblue;position: absolute;transition: transform 0.3s ease; /* 平滑過渡 */
}
</style>

使用節流優化性能

方法一: 通過lodash庫

安裝lodash:

npm install lodash-es
<script setup>
import { ref } from "vue";
import { throttle } from 'lodash-es'; // 或者使用自定義節流函數// ... existing code ...const handleTouchMove = throttle((e) => {moveX.value = e.touches[0].clientX - startX.value;// 跟手效果pages.forEach((_, i) => {const page = pageRef.value[i];if (page) {page.style.transform = `translateX(${i * 100 - currentIndex.value * 100 + moveX.value / 10}%)`;page.style.transition = "none";}});
}, 16); // 約60fps的間隔// ... existing code ...
</script>

或者使用自定義的簡單節流實現:

<script setup>
import { ref } from "vue";// ... existing code ...let lastTime = 0;
const handleTouchMove = (e) => {const now = Date.now();if (now - lastTime < 16) return; // 約60fpslastTime = now;moveX.value = e.touches[0].clientX - startX.value;// ... rest of the original code ...
};// ... existing code ...
</script>

滾動實現滑屏效果

前置知識

CSS: scroll-snap-type屬性

scroll-snap-type 是 CSS 中的一個屬性,用于控制滾動容器的滾動行為,特別是當用戶滾動時,內容是否以及如何“吸附”到特定的停止點。
這個屬性定義在滾動容器上,它決定了滾動的軸向以及吸附行為的嚴格程度。

基本語法:

scroll-snap-type: none | [ x | y | block | inline | both ] [ mandatory | proximity ]?;

取值說明:

  1. 軸向 (Axis)
    • none:不啟用滾動吸附。這是默認值。
    • x:在水平軸上啟用滾動吸附。
    • y:在垂直軸上啟用滾動吸附。
    • block:在塊級方向上啟用吸附(在大多數書寫模式下等同于 y)。
    • inline:在內聯方向上啟用吸附(在大多數書寫模式下等同于 x)。
    • both:在兩個軸上都啟用吸附。
  2. 嚴格程度 (Strictness)
    • mandatory:強制吸附。當滾動操作結束時(例如用戶松開鼠標、手指或滾動停止),視口必須停留在一個吸附點上。如果內容區域不足以滾動到下一個/上一個點,用戶可能無法滾動。
    • proximity:鄰近吸附。滾動操作結束時,如果當前視口位置足夠接近一個吸附點,瀏覽器會自動滾動到該點。但如果用戶停止在兩個吸附點之間較遠的位置,可能不會發生吸附。用戶體驗更靈活。

示例:

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>滾動吸附示例</title><style>body {font-family: Arial, sans-serif;margin: 0;padding: 20px;}h1 {text-align: center;margin-bottom: 30px;}/* 垂直方向強制吸附 */.container {scroll-snap-type: y mandatory;overflow-y: scroll;height: 400px;border: 2px solid #333;margin-bottom: 40px;}/* 水平方向鄰近吸附 */.horizontal-slider {display: flex;scroll-snap-type: x proximity;overflow-x: scroll;scroll-behavior: smooth;border: 2px solid #333;margin-bottom: 40px;}/* 子元素需要設置吸附點 */.item {scroll-snap-align: start;flex: 0 0 100%;height: 300px;display: flex;align-items: center;justify-content: center;font-size: 24px;font-weight: bold;color: white;}/* 垂直容器中的項目樣式 */.container .item {height: 400px;}/* 為不同項目設置不同背景色 */.item:nth-child(1) {background-color: #FF5733;}.item:nth-child(2) {background-color: #33FF57;}.item:nth-child(3) {background-color: #3357FF;}.item:nth-child(4) {background-color: #F333FF;}</style>
</head>
<body><h1>滾動吸附效果演示</h1><h2>垂直滾動吸附(強制)</h2><div class="container"><div class="item">垂直項目 1</div><div class="item">垂直項目 2</div><div class="item">垂直項目 3</div><div class="item">垂直項目 4</div></div><h2>水平滾動吸附(鄰近)</h2><div class="horizontal-slider"><div class="item">水平項目 1</div><div class="item">水平項目 2</div><div class="item">水平項目 3</div><div class="item">水平項目 4</div></div><p>說明:垂直滾動容器設置了強制吸附(y mandatory),滾動結束后會精確停在項目頂部。水平滾動容器設置了鄰近吸附(x proximity),滾動結束后可能會停在項目附近。</p>
</body>
</html>

在這里插入圖片描述

準備階段

基本結構代碼:

<template><div class="scroll-container"><!-- 頁面內容 --><divv-for="(page, index) in pages":key="page.id"class="page":style="{ backgroundColor: page.color }">{{ page.name }}</div></div>
</template><script setup>
import { ref, onMounted } from "vue";const pages = [{ color: "#ff7675", name: "屏幕 1", id: 0 },{ color: "#74b9ff", name: "屏幕 2", id: 1 },{ color: "#55efc4", name: "屏幕 3", id: 2 },{ color: "#a29bfe", name: "屏幕 4", id: 3 },{ color: "#ffcb20", name: "屏幕 5", id: 4 },
];</script><style scoped>
.scroll-container {
}
.page {
}
</style>

和上面步驟一樣,同樣的給內容來個沾滿全屏的寬度高度以及page重點文字樣式:

.scroll-container {height: 100vh;width: 100vw;
}
.page {width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;font-size: 50px;font-weight: 700;color: aliceblue;
}

實現滑動效果

接下來的布局就是和上面不同的時候啦🤗,我們要給scroll-container一個flex屬性,讓所有的子元素橫向排列,排列完之后大家會發現page子元素并沒有想我們想想中的那樣沾滿這個頁面以此排列,而是都擠在一個頁面了。

在這里插入圖片描述
這是因為flex布局的緣由,使得每個page的寬度被壓縮了。要讓頁面不被壓縮,需要修改 .page 的樣式,將 flex-shrink: 0 添加到樣式中,這樣 flex 容器就不會壓縮這些頁面了。

.scroll-container {/*...*/overflow-x: auto;
}
.page {/*...*/flex-shrink: 0; /* 添加這行防止頁面被壓縮 */
}

現在就解決了頁面布局問題啦😄。

實現吸附效果

添加上scroll-snap-type屬性,讓滾動條有吸附效果:

.scroll-container {/*...*/scroll-snap-type: x mandatory;-webkit-overflow-scrolling: touch; /* 啟用平滑滾動 */
}
.page {/*...*/flex-shrink: 0; /* 添加這行防止頁面被壓縮 */scroll-snap-align: start;
}

劃劃屏幕,是不是發現現在就已經實現了我們之前想要實現的劃屏效果啦😲!沒錯,就是這么簡單,幾乎純CSS樣式就可以搞定啦🤩!

滾動條隱藏

接下來優化一下下細節,先來去掉底部下方的橫向滾動條:
在這里插入圖片描述
要去掉橫向滾動條,可以修改 .scroll-container 的樣式,將 overflow-x 從 auto 改為 hidden。

.scroll-container {/*...*//* 使用瀏覽器私有偽元素隱藏滾動條? */scrollbar-width: none; /* Firefox */-ms-overflow-style: none; /* IE/Edge */
}
/* WebKit 瀏覽器:隱藏滾動條但保留滾動功能 */
.scroll-container::-webkit-scrollbar {display: none; /* Chrome/Safari/Opera */
}

存在問題

可以很清晰的觀察到一個現象——當用力滑動時會一下子跳過多頁。
在這里插入圖片描述

這是因為 scroll-snap-type: x mandatory 在慣性滾動下的典型表現。瀏覽器的滾動捕捉機制雖然會強制最終停在某個捕捉點上,但它不會限制滾動的“速度”或“距離”。當你用力快速滑動時,系統會產生很大的慣性,滾動容器會高速“掠過”中間的捕捉點,最終可能停在更遠的一個點上。
遺憾的是,純 CSS 目前沒有直接的屬性可以限制“每次滾動只移動一個捕捉點”。mandatory 只保證“停在點上”,不保證“只移動一步”。小編這里也是還沒有找到適合的實現方式👉👈,就當作是這個方法的缺陷吧😖。

完整代碼

<template><div class="scroll-container" ><!-- 頁面內容 --><divv-for="(page, index) in pages":key="page.id"class="page":style="{ backgroundColor: page.color }">{{ page.name }}</div></div>
</template><script setup>
import { ref, onMounted } from "vue";const pages = [{ color: "#ff7675", name: "屏幕 1", id: 0 },{ color: "#74b9ff", name: "屏幕 2", id: 1 },{ color: "#55efc4", name: "屏幕 3", id: 2 },{ color: "#a29bfe", name: "屏幕 4", id: 3 },{ color: "#ffcb20", name: "屏幕 5", id: 4 },
];</script><style scoped>
.scroll-container {height: 100vh;width: 100vw;display: flex;overflow-x: auto;scroll-snap-type: x mandatory;-webkit-overflow-scrolling: touch; /* 啟用平滑滾動 *//* 使用瀏覽器私有偽元素隱藏滾動條? */scrollbar-width: none; /* Firefox */-ms-overflow-style: none; /* IE/Edge */
}
/* WebKit 瀏覽器:隱藏滾動條但保留滾動功能 */
.scroll-container::-webkit-scrollbar {display: none; /* Chrome/Safari/Opera */
}
.page {width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;font-size: 50px;font-weight: 700;color: aliceblue;flex-shrink: 0; /* 添加這行防止頁面被壓縮 */scroll-snap-align: start;
}
</style>

scrollLeft實現滑屏效果(最佳實踐)

為了解決上面使用滾動實現的劃屏效果痛點,我們不得不拋棄CSS屬性,該用JS來實現我們想要的效果。具體是那種JS方法呢? 其實你已經學過了,就是第一種中的方法,通過觸摸事件來控制屏幕滑動,不過這一次我們不是控制定位位置來改變位置,而是通過控制橫向滾動條的滾動位置來改變位置。

前置知識

DOM: scrollLeft

scrollLeft 是一個 JavaScript DOM 屬性,它用于獲取或設置一個可滾動元素(如 div, body 等)的水平滾動條相對于最左側的偏移量。

作用:

  • 獲取:讀取元素當前水平滾動多少像素。
  • 設置:將元素的水平滾動移動到指定的位置。

基本語法:

// 獲取元素當前的水平滾動偏移量(像素)
let currentScroll = element.scrollLeft;// 設置元素的水平滾動偏移量(像素)
element.scrollLeft = value;
  • element:一個具有滾動能力的 DOM 元素(即其 overflow 屬性為 autoscroll,并且內容超出其寬度)。
  • value:一個非負的數值,表示希望滾動條距離最左側的像素數。

PS:

  • 一個元素可滾動的最大 scrollLeft 值可以通過 element.scrollWidth - element.clientWidth 計算得出。
  • scrollTop 用于垂直方向的滾動。

實例:

<div id="scroller" style="width: 200px; overflow-x: auto; white-space: nowrap;"><span>這是一個很長很長很長很長很長很長的文本行,需要水平滾動才能看完。</span>
</div>
<button onclick="scrollToRight()">滾動到底部</button>
const scroller = document.getElementById('scroller');// 獲取當前滾動位置
console.log('當前水平滾動位置:', scroller.scrollLeft); // 例如: 0// 將滾動條滾動到最右側
scroller.scrollLeft = scroller.scrollWidth - scroller.clientWidth;// 或者滾動到特定位置
scroller.scrollLeft = 50;// 滾動一定距離(例如向右滾動 20 像素)
scroller.scrollLeft += 20;// 檢測是否滾動到了最右邊
if (scroller.scrollLeft >= scroller.scrollWidth - scroller.clientWidth) {console.log('已滾動到底部!');
}

DOM: scrollWidth

scrollWidth 是一個 只讀 的 JavaScript DOM 屬性,它返回一個元素的內容(包括由于溢出而不可見的部分)的整個寬度,以像素為單位。
簡單來說,scrollWidth 告訴你這個元素的“內容”到底有多寬,即使這些內容因為容器大小限制而被隱藏(溢出)了。
“scrollWidth = 可視內容寬 + 被卷起來的內容寬”

  • 內容區域的總寬度(包括由于溢出而在視口外不可見的部分)。
  • 包含 元素的 padding,不包含 border、margin、垂直滾動條的寬度。
  • 如果元素沒有溢出,scrollWidth 與 clientWidth(可見區域寬度)通常相等;出現水平溢出時,scrollWidth > clientWidth

與相關屬性的對比(橫向):

屬性包含內容包含 padding包含 border包含 margin包含隱藏部分
scrollWidth?????
clientWidth?????
offsetWidth?????

垂直方向把 “Width” 換成 “Height” 即可。

@scroll事件

@scroll 是 Vue.js 框架中的一個事件監聽修飾符,用于監聽 DOM 元素上的 scroll 事件。
基本語法:

<template><!-- 監聽某個元素的滾動 --><div @scroll="handleScroll" class="scrollable-container"><!-- 可滾動的內容 --></div><!-- 或者監聽整個窗口的滾動 (通常在 mounted 鉤子中用 addEventListener) --><!-- 但在 Vue 模板中,@scroll 通常用于具體元素 -->
</template><script>
export default {methods: {handleScroll(event) {// event 是原生的 UIEvent 對象console.log('滾動了!');// 獲取滾動元素const element = event.target;// 獲取滾動位置console.log('scrollTop:', element.scrollTop);console.log('scrollLeft:', element.scrollLeft);// 其他滾動相關的邏輯...}}
}
</script>

核心作用:@scroll 事件在元素的滾動條滾動時被觸發

它可以用于:

  • 監聽滾動位置:獲取 scrollTopscrollLeft,判斷用戶滾動到了哪里。
  • 實現懶加載:當用戶滾動到頁面底部或某個區域附近時,動態加載更多內容。
  • 實現吸頂效果:當頁面滾動超過某個元素的位置時,改變該元素的樣式(如 position: fixed)。
  • 檢測滾動方向:通過比較前后兩次的 scrollTop 值來判斷用戶是向上還是向下滾動。
  • 滾動動畫控制:根據滾動位置觸發動畫或改變元素狀態。

準備階段

基本結構代碼:

<template><divclass="scroll-container"ref="containerRef"@touchstart="touchstart"@touchend="touchend"><!-- 頁面內容 --><divv-for="(page, index) in pages":key="page.id"class="page":style="{ backgroundColor: page.color }">{{ page.name }}</div></div>
</template><script setup>
import { ref, onMounted } from "vue";const pages = [{ color: "#ff7675", name: "屏幕 1", id: 0 },{ color: "#74b9ff", name: "屏幕 2", id: 1 },{ color: "#55efc4", name: "屏幕 3", id: 2 },{ color: "#a29bfe", name: "屏幕 4", id: 3 },{ color: "#ffcb20", name: "屏幕 5", id: 4 },
];const containerRef = ref(null);const touchstart = (e) => {};
const touchend = (e) => {};
</script><style scoped>
.scroll-container {height: 100vh;width: 100vw;display: flex;overflow-x: auto;scroll-snap-type: x mandatory;-webkit-overflow-scrolling: touch; /* 啟用平滑滾動 *//* 使用瀏覽器私有偽元素隱藏滾動條? */scrollbar-width: none; /* Firefox */-ms-overflow-style: none; /* IE/Edge */touch-action: none; /* 禁止觸摸動作 */
}
/* WebKit 瀏覽器:隱藏滾動條但保留滾動功能 */
.scroll-container::-webkit-scrollbar {display: none; /* Chrome/Safari/Opera */
}
.page {width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;font-size: 50px;font-weight: 700;color: aliceblue;flex-shrink: 0; /* 添加這行防止頁面被壓縮 */scroll-snap-align: start;
}
</style>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/92121.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/92121.shtml
英文地址,請注明出處:http://en.pswp.cn/web/92121.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

忘記了WordPress管理員密碼的找回方法

WordPress管理員密碼找回方法 如果您忘記了WordPress管理員密碼&#xff0c;可以通過以下幾種方法找回或重置&#xff1a; 方法1&#xff1a;通過電子郵件重置(最簡單) 訪問您的WordPress登錄頁面(通常是wodepress.com/wp-admin或wodepress.com/wp-login.php) 點擊”忘記密…

RAFT:讓語言模型更聰明地用文檔答題

RAFT&#xff1a;讓語言模型更聰明地用文檔答題 作者注&#xff1a; 本文旨在面向零基礎讀者介紹 UC Berkeley 提出的 RAFT&#xff08;Retrieval-Augmented Fine-Tuning&#xff09;方法。它是一種訓練語言模型的新方式&#xff0c;讓模型更好地利用“外部知識”——比如文檔、…

【緊急預警】NVIDIA Triton推理服務器漏洞鏈可導致RCE!

2025 年 8 月 4 日消息&#xff0c;NVIDIA 旗下的 Triton 推理服務器&#xff08;一款支持 Windows 和 Linux 系統、用于大規模運行 AI 模型的開源平臺&#xff09;被曝出一系列安全漏洞。這些漏洞一旦被利用&#xff0c;攻擊者有可能完全接管存在漏洞的服務器。 Wiz 安全公司…

基于深度學習的醫學圖像分析:使用PixelCNN實現醫學圖像生成

前言 醫學圖像分析是計算機視覺領域中的一個重要應用&#xff0c;特別是在醫學圖像生成任務中&#xff0c;深度學習技術已經取得了顯著的進展。醫學圖像生成是指通過深度學習模型生成醫學圖像&#xff0c;這對于醫學研究、疾病模擬和圖像增強等任務具有重要意義。近年來&#x…

React ahooks——副作用類hooks之useDebounceFn

useDebounceFn 是 ahooks 提供的用于函數防抖的 Hook&#xff0c;它可以確保一個函數在連續觸發時只執行最后一次。一、基本用法import { useDebounceFn } from ahooks; import { Button } from antd;const Demo () > {const { run } useDebounceFn(() > {console.log(…

【機器學習深度學習】 知識蒸餾

目錄 前言 一、什么是知識蒸餾&#xff1f; 二、知識蒸餾的核心意義 2.1 降低算力與成本 2.2 加速推理與邊緣部署 2.3 推動行業應用落地 2.4 技術自主可控 三、知識蒸餾的本質&#xff1a;大模型的知識傳承 四、知識蒸餾的“四重紅利” 五、DeepSeek的知識蒸餾實踐 …

Python高級編程與實踐:Python高級數據結構與編程技巧

高級數據結構&#xff1a;掌握Python中的高效編程技巧 學習目標 通過本課程&#xff0c;學員將深入了解Python中的高級數據結構&#xff0c;包括列表推導式、字典推導式、集合推導式和生成器表達式。學員將學習如何利用這些結構來編寫更簡潔、更高效的代碼&#xff0c;并了解它…

【C++】Stack and Queue and Functor

本文是小編鞏固自身而作&#xff0c;如有錯誤&#xff0c;歡迎指出&#xff01;本次我們介紹STL中的stack和queue和其相關的一些容器和仿函數一.stack and queue1.適配器stack和queue其實不是真正意義上的容器&#xff0c;而是容器適配器&#xff0c;而容器適配器又是什么呢&am…

Python爬蟲實戰:研究OpenCV技術構建圖像數據處理系統

1. 引言 1.1 研究背景 在當今數字化時代,圖像作為一種重要的信息載體,廣泛存在于各類網站、社交媒體和在線平臺中。這些圖像數據涵蓋了從自然風光、人物肖像到商品展示、新聞事件等豐富內容,為數據分析和模式識別提供了寶貴的資源。隨著計算機視覺技術的快速發展,對大規模…

電感矩陣-信號完整性分析

電感矩陣:正如電容矩陣用于存儲許多信號路徑和返回路徑的所有電容量&#xff0c;我們也需要一個矩陣存儲許多導線的回路自感和回路互感值。需要牢記的是&#xff0c;這里的電感元件是回路電感。當信號沿傳輸線傳播時&#xff0c;電流回路沿信號路徑傳輸&#xff0c;然后立即從返…

JUC相關知識點總結

Java JUC&#xff08;java.util.concurrent&#xff09;是Java并發編程的核心工具包&#xff0c;提供了豐富的并發工具類和框架。以下是JUC的主要知識點&#xff0c;按難易程度分類&#xff0c;供你參考&#xff1a; 1. 基礎概念與工具類 1.1 并發與并行&#xff08;易&#x…

激光頻率梳 3D 測量方案革新:攻克光學掃描遮擋,130mm 深孔測量精度達 2um

一、深孔測量的光學遮擋難題在精密制造領域&#xff0c;130mm 級深孔&#xff08;如航空發動機燃油孔、模具冷卻孔&#xff09;的 3D 測量長期受困于光學遮擋。傳統激光掃描技術依賴直射光束&#xff0c;當深徑比超過 10:1 時&#xff0c;孔壁中下部形成大量掃描盲區&#xff0…

clickhouse 中文數據的正則匹配

中文數據的正則匹配 在ClickHouse中,正則匹配通常用于數據的篩選、格式化等操作。以下是一些常用的正則匹配技巧: 1. 匹配中文字符 要匹配中文字符,可以使用以下正則表達式: SELECT * FROM my_table WHERE my_column REGEXP [\\x{4e00}-\\x{9fa5}];這里的 \\x{4e00}-\\…

[驅動開發篇] Can通信進階 --- CanFD 的三次采樣

驅動開發篇] Can通信進階 --- Can報文的三次采樣一、CAN FD的采樣次數1.1. 標準規定1.2. 傳統標準CAN采樣1.3. CAN FD的采樣策略1.3.1. 基礎采樣策略1.4. 配置位置1.5. 常見步驟二、CAN FD與標準CAN在采樣機制上的主要區別三、使用建議四. 芯片廠商實現4.1. 實際市面情況4.2. 例…

分布式文件系統06-分布式中間件彈性擴容與rebalance沖平衡

分布式中間件彈性擴容與rebalance沖平衡176_如果宕機的數據節點事后再次重啟會發生什么事情&#xff1f;某個之前某個宕機的數據節點DataNode-A又重啟后&#xff0c;肯定會再次注冊&#xff0c;并進行全量上報的流程&#xff0c;此時&#xff0c;就會導致DataNode-A上的文件副本…

芯祥科技:工業/車規級BMS芯片廠商 規格選型對比

芯祥科技公司專注于工業和車規級BMS芯片&#xff0c;電源芯片及可編程模擬芯片的研發與銷售&#xff0c;客戶遍及新能源儲能&#xff0c;汽車&#xff0c;電腦&#xff0c;服務器及電動工具等領域。并具有創業公司成功經驗&#xff0c;平均具有逾17年以上的芯片研發和市場銷售經…

莫隊基礎(Mo‘s algorithm)

莫隊算法簡介 莫隊算法是一種用于高效處理離線區間查詢問題的算法&#xff0c;由莫濤&#xff08;Mo Tao&#xff09;在2009年提出。其核心思想是通過對查詢區間進行分塊和排序&#xff0c;利用前一次查詢的結果來減少計算量&#xff0c;從而將時間復雜度優化至接近線性。 莫…

板卡兩個ADC,一個JESD204b sync正常,另一個JESD204B同步不上的問題

目錄 1.問題來源: 2.問題分析 進一步測試表現: 抓取204B高速鏈路數據如上所示。 說明不是配置流程的問題 1.問題來源: 在工控機上和部分電腦上面出現時鐘鎖不住的現象,無法正常使用板卡。 經過分析,發現板卡上有兩片ADC,其中一片的ADC的sync信號經過測量,是正常的,…

Android10 系統休眠調試相關

Android10 系統休眠調試相關實時打印休眠日志(實測好像沒作用)&#xff1a;echo 1 > /sys/module/printk/parameters/console_suspend查看喚醒鎖&#xff1a;cat sys/power/wake_lock msm8953_64:/ # cat sys/power/wake_lock PowerManager.SuspendLockout PowerManagerServ…

一文掌握Bard機器翻譯,以及用python調用的4種方式(現已升級為 Gemini)

文章目錄一、Bard機器翻譯概述1.1. Bard機器翻譯介紹1.2 Bard機器翻譯的核心特點1.3 技術背景1.4 與同類模型對比二、Bard機器翻譯案例2.1 官方 REST API&#xff08;推薦生產&#xff09;2.2 通過Google Cloud API調用2.3 私有化部署方案2.4 開源鏡像 PyBard&#xff08;無需 …