該種實現方式不同於輪播等css控制,可以直接嵌入到web頁面,不會破壞頁面結構,即拿即用。
需求分析
web端頁面如果採用長頁面模式,參考特斯拉官網,對於在同一頁面需要展示很多圖片內容的網站來說,通常瀏覽器默認的滾動條一次滾動的距離,對於用戶體驗很不友好,同時對於頁面完整性的展示效果也有影響,比如
三星官網
這種長頁面,用戶需要頻繁使用滾輪。
參考特斯拉官網之後,使用js實現了使用鼠標滾輪,控制滾動條的滾動距離,讓用戶在一次滾輪滾動中,可以看到一個完整的頁面。
效果
對比
正常滾動 | 滾動控制 |
---|---|
實現思路
首先明確,我們的頁面中有多少需要滾動定位的元素,比如有這樣一個列表[ele1,ele2,ele3],當用戶滾動滾輪時,需要暫時讓滾輪事件停止響應,因爲滾輪事件的觸發條件是滾輪裏的卡點(滾動時明顯的停頓感)每動一下就要觸發,所以一次觸發後需要先停止一會(防止反覆觸發),並且,在觸發後,如果由代碼實現滾動,還需要阻止用戶滾輪的默認行爲,否則兩種滾動方式都會運行,頁面會卡住不動。
明確滾輪事件的原理之後,需要確認是向上滾動還是向下,一次滾動的距離是多少。根據滾輪事件,向上向下很好判斷。滾動距離需要根據實際情況,比如,我們在頁面中抓了3個點,獲取這3個點距離文檔頂部的距離就可以了,之後實現頁面滾動的函數,讓頁面滾動到我們希望的位置。
技術點/知識點
需要了解一下技術點:
- preventDefault ,阻止瀏覽器默認事件;
- window.scrollTo 頁面進行滾動;
- mousewheel 鼠標滾輪觸發事件;
- document.querySelector 選取頁面元素;
- element.offsetTop 當前元素距離文檔頂部距離;
瞭解了這幾點,就能實現我們的需求了。
在代碼中,
有2個關鍵的變量,一個是cur_index,描述當前滾動到哪個元素。
invoke,描述當前是否在滾動中,在moveTo函數中,先判斷該變量,避免重複觸發。
踩坑記錄
最開始期望使用scroll事件,控制瀏覽器的滾動條。實際編寫時發現,監聽scroll事件時,改變高度是無效的。
原因是scroll事件監聽的是,任何改變文檔位置的觸發的函數或者用戶觸發的動作,所以當監聽用戶動作時,改變文檔高度是不可行的,這會循環觸發scroll事件,導致頁面不停觸發scroll,不能實現該功能。
而mousewheel事件只監聽滾輪,所以最終實現了該功能。
示例代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<style>
.a,.b,.c{
width: 100%;
height: 100vh;
background:red;
}
.b{
background: blue;
}
.other{
width: 100%;
height: 30vh;
background:black;
}
.other_1{
background:white;
}
.other_2{
background:black;
}
.other_3{
background:white;
}
</style>
<body>
<div class="other other_0"></div>
<div class="other other_1"></div>
<div class="other other_2"></div>
<div class="other other_3"></div>
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<script>
window.addEventListener("mousewheel",WheelGo)
var cur_index = -1
var invoke = false
list = [{ele:"other_0"},{ele:"other_1"},{ele:"other_2"},{ele:"other_3"},{ ele: "a" }, { ele: "b" }, { ele: "c" }]
list = initSrollPosition("body",list)
function initSrollPosition(ele,list){
var container = document.querySelector(ele)
for(var i in list){
list[i].position = document.querySelector("."+list[i].ele).offsetTop
}
return list
}
//window.addEventListener("mousewheel",go)
//
// window.addEventListener("scroll",judge)
// function judge(e){
// console.log(e)
// var scrollPosition = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
// var first_position = list[0].position/2
// console.log(scrollPosition)
// if(scrollPosition>=first_position){
// }
// }
// function loseWheelControl(){
// window.removeEventListener("mousewheel",go)
// console.log("loseWheelControl")
// }
function stopDefault(e){
e.preventDefault()
return false
}
function WheelGo(e){
//判斷當前所處位置
var isDown = e.deltaY>0?true:false
stopDefault(e)
if(invoke){
return
}
moveTo(isDown)
}
function moveTo(isDown){
var cur_state
if(isDown){
cur_index = cur_index>=list.length-1?list.length-1:cur_index+1
var cur_state = list[cur_index]
}else{
cur_index = cur_index<=0?0:cur_index-1
cur_state = list[cur_index]
}
console.log("invoke")
invoke = true
window.scrollTo({top:(cur_state.position),left:0,behavior:"smooth"})
setTimeout(()=>{
invoke = false
},500)
}
</script>
</body>
</html>