JavaScript 範例 - scrollIntoView 實現清單自動捲動
5 |
分享一個 JavaScript 小技巧,假設有個很多項目的清單,靠 CSS overflow-y: scroll 啟用垂直捲軸,除了由使用者操作上下捲動,也能用程式控制捲動到指定的一筆嗎?
用講的不容易理解,看示範就清楚吧! 在以下展示中,我用 div 當清單容器放入 16 個項目 div,清單高度只能顯示四筆,但有垂直捲軸可上下捲動,按鈕可捲動到指定項目並標示為藍底:
感覺挺酷的,說穿了不值錢,其實就是用了一個所有可視元素都支援的 API - Element.scrollIntoView(),負責捲動元素所屬容器讓元素出現在可視範圍。
展示網頁的程式碼如下:線上展示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.container {
width: 200px; margin: auto;
}
button {
width: 25px; padding: 0 2px;
}
#list {
width: 96%; height: 92px;
margin-top: 6px; padding: 3px;
border: 1px solid gray;
overflow-y: scroll;
}
.active {
background-color: lightskyblue;
}
</style>
</head>
<body>
<div class="container">
<div id="buttons"></div>
<div id="list"></div>
</div>
<script>
function setFocus(no) {
// 清除目前元素的 .active 樣式
[].forEach.call(document.querySelectorAll('.active'), function (el) {
el.classList.remove('active');
});
var line = document.getElementById('L' + no);
line.classList.add('active');
//捲動 line 所處容器,確保 line 元素在可視範圍
line.scrollIntoView();
document.getElementById('B' + no).classList.add('active');
}
// 在 #list div 加入 16 筆 div,並建立 16 顆連動按鈕
for (var i = 1; i <= 16; i++) {
var line = document.createElement('div');
line.id = 'L' + i;
line.textContent = 'LINE ' + i;
document.getElementById('list').appendChild(line);
var btn = document.createElement('button');
btn.onclick = function () {
setFocus(this.innerText);
};
btn.innerText = i;
btn.id = 'B' + i;
document.getElementById('buttons').appendChild(btn);
}
</script>
</body>
</html>
以上寫法在某些情境會出問題。我遇上網頁左側有個超長導覽選單的狀況,scrollIntoView() 會捲過頭:
要解決其實很簡單。呼叫 scrollIntoView() 時可傳入參數的,alignTop 參數 (true/false) 指定向頂端或向底部看齊;或傳入物件參數 scrollIntoViewOptions 指定 behavior (動畫轉場採 auto 或 smooth)、block (垂直對齊依據:start/center/end/nearest,nearest 指依當下位置找最近的對齊點)、inline (水平對齊依據:start/center/end/nearset) 等參數。未傳參數時等同 alignTop = ture / scrollIntoViewOptions: { block: "start", inline: "nearest" },在這個清單捲動範例中,scrollIntoView(false) 設定 alignTop = false / scrollIntoViewOptions: { block: "end", inline: "nearest" } 即可解決。線上展示
2022-10-05 補充
有讀者反映不易想像捲動到清單項目的應用,再補上一個按字母快速捲動到字母起首項目的範例,希望大家會更有感。
程式碼:線上展示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
#list {
width: 96%;
height: 90px;
margin-top: 6px;
padding: 3px;
border: 1px solid gray;
overflow-y: scroll;
}
#list > div {
cursor: pointer;
}
#list > div:hover {
background-color: #ddd;
}
#sel { width: 96%; margin-top: 5px; }
.container {
width: 250px; font-size: 9pt;
}
</style>
</head>
<body>
<div class="container">
<div>Press A-Z to scroll</div>
<div id="list" tabindex="0"></div>
<input type="text" id="sel">
</div>
<script>
var countries = `Afghanistan
Albania
Algeria
//...省略...
Zambia
Zimbabwe`
</script>
<script>
countries.split('\n').forEach(c => {
var line = document.createElement('div');
line.textContent = c;
document.getElementById('list').appendChild(line);
});
var listBox = document.getElementById('list');
listBox.addEventListener('click', e => {
document.getElementById('sel').value = e.target.innerText;
});
listBox.addEventListener('keydown', e => {
let m = e.code.match('Key([A-Z])');
if (m) {
let found = false;
listBox.childNodes.forEach(line => {
if (!found && line.innerText.startsWith(m[1])) {
line.scrollIntoView();
found = true;
}
});
}
});
</script>
</body>
Example of how to use JavaScript scrollIntoView() API to implementing a list can scroll to selected item automatically.
Comments
# by Jeffery
您好,想請問gif圖片使用者什麼軟體錄製的?
# by Jeffrey
to Jeffery, 地表最強的螢幕擷取軟體 - Snagit,錄製操作影片再轉成 gif
# by Anonymous
免費的如 LICEcap 也不錯使用喔
# by 布丁布丁吃布丁
錄影轉gif也可以用ScreenToGif https://www.screentogif.com/ 選範圍、錄影、編輯結果、存成gif,一氣喝成。
# by IronArks
分享之前有用JQuery做過類似的Code 跟Jeffery的情形不一樣是在於 主要是因為需要將該item拉到頂端(下半有跟資料, 比如用到JqueryUI的According) 用focus的方法會只能保證看到該item(下半可能被遮住) 確保定位要執行二次(因為可能相對位置有時在初始載入不明確) --------------------------------------------------------------------------------------- $("#Content_dialog").scrollTop($("#Content_dialog").scrollTop() + $('#targetItem').position().top); $("#Content_dialog").scrollTop($("#Content_dialog").scrollTop() + $('#targetItem').position().top);