何謂 Scroll? Scroll 使用情境?

Scroll 就是滾動,例如大家常常聽到的 overflow scroll、無限滾動等都是 Scroll 的常見應用,我們常見的文章錨點功能,點擊標題後滾動到該標題文章區域,也是類似的呈現。

今天要來分享的是我實作滾動時的步驟以及遇到的坑!當初接受到滾動的需求是製作一個排行榜功能,「希望使用者抵達網頁後,網頁自動滾動並聚焦到自己的排名。」 是在前端時常會見到的需求。

Scroll情境
首次 Landing 滾動到指定元素位置,讓指定元素置頂呈現,點擊 Tab 切換主題後,畫面依照不同位置做出一樣的效果。

如何實踐 Scroll?

1. window.toScroll

最簡單的方法就是使用 window.toScroll 這個 Web API,可以設定畫面位置來達成滾動到指定目標。需要計算距離網頁頂部或是底部的距離,是 window.toScroll 的限制,也就是說如果你今天是想抵達特定元素,你就必須先計算該元素距離網頁頂部的距離,再透過 window.scrollTo(x-coord,y-coord ) 這樣的方式達成。

以下為 window.scrollTo 的實踐方式

1
2
3
4
5
6
7
8
9

window.scrollTo( 0, 1000 );

// 可以設置 Smooth 讓滾動有平滑的效果
window.scrollTo({
top: 1000,
behavior: "smooth"
});

但排行榜的元素有這麼多,每次要滾動到的位置都不一樣,要計算太麻煩了!於是我又繼續找能夠滾動到「指定元素」的方式。

2. Scroll-Into-View

這是我最終使用的 Web API,覺得這個套件使用方式很簡單,也能達成我的需求,以下跟大家分享使用方式:

Step 1. 起手式

1
2
3
4
5
6
7
8
//TypeScript 開發
npm install --save @types/scroll-into-view

//JavaScript 開發
npm install scroll-into-view

// 在使用的頁面 import
import scrollIntoView from 'scroll-into-view';

Step 2. 改變目標元素的 ClassName

我的專案剛好是使用 Antd design,Antd table 就有 RowClassName 的 API 可以使用,但若你是自己手刻元件的話,也可以在JavaScript 中使用 getElementById 更改 CSS 屬性,這邊就不贅述,感興趣的人可以再去 Google 關鍵字唷!一但 ClassName 設定好了之後我們就可以給他下 Scroll 的 Function 啦!

以下是的程式碼,當該欄位的 id 等於我網頁的 UserId,就讓 ClassName 改為 ‘hightLightStyle’,若不符合則為空值。

1
2
3
4
rowClassName={(record: any, index: number)=>
record?.userId === id
? 'hightLightStyle'
: ''}

Step 3. Handle Scroll Function

設定好 CSS 樣式名稱後,就可以在監聽之後給他一個 Scroll Function 啦!因為我的第一個滾動效果是在 Landing 後需要出現,所以我就設計在 UseEffect 初始渲染當中。

1
2
3
4
5
6
7
8
const handleScroll = () => {
const element = document.querySelector('.hightLightStyle') as HTMLElement;
scrollIntoView(element, {
align: {
top: 0,
},
});
};

這裡踩了第一個坑,原本是將 handleScroll 放在第一次呼叫 API 後,但後來發現於首次載入資料時若來不及改變 ClassName 就呼叫 Scroll,會沒有滾動效果。如果你也遇到這個問題,可以放入一個 setMount(true) 在 UseEffect 裡,在監測 mount 變動後再呼叫 handleScroll(),就可以排除此問題。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const [mount, setMount] = useState(false);

// 初始呼叫 API 取得排行榜資料
useEffect(() => {
getDataAPI()
.then((response) => {
---略---
if (Data) {
setMount(true);
}
})
.catch((error) => {
---略---
});
}, []);

//畫面渲染完成再 scroll
useEffect(() => {
handleScroll();
}, [mount]);

//切換排行榜也要重新 scroll
useEffect(() => {
handleScroll();
}, [tabKey]);

Step 4. 切換多個分頁都要有 Scroll 效果

在切換不同主題的排行榜時,我發現 Scroll 效果又消失了!迎來第二個坑,由於三個 tab 裡的資料其實是「同步取得」的,若使用者剛好在三個排行榜都榜上有名,那就代表 UserId 並不是唯一值,而會有三個!但 Scroll 的 ClassName 需具備唯一性,這樣 Scroll 才會明確地知道他的滾動目的地,太多個他會不知道該往哪滾。

所以當你有多個 Tab(頁籤)切換,但是又不是設計成分頁的話,每一個 Tab 的 Key 值或是 Id 值也需要拿出來比對,新增這個比對後就解決了一分頁 Scroll 就失效的問題囉!

1
2
3
4
rowClassName={(record: any, index: number)=>
record?.userId === id && record?.topic === tabKey
? 'hightLightStyle'
: ''}

以上就是簡單的 Scroll 特效的使用方式,以及踩過的坑!如果你也有實作類似效果的經驗或是方法也歡迎跟我分享唷!