JS 30 是由加拿大的全端工程師 Wes Bos 免費提供的 JavaScript 簡單應用課程,課程主打 No Frameworks
、No Compilers
、No Libraries
、No Boilerplate
在30天的30部教學影片裡,建立30個JavaScript的有趣小東西。
另外,Wes Bos 也很無私地在 Github 上公開了所有 JS 30 課程的程式碼,有興趣的話可以去 fork 或下載。
實作出能夠按住滑鼠左右拖曳的水平捲軸。
捲軸(div.items
)由內部的25個div.item
共同組成。
<div class="items">
<div class="item item1">01</div>
<div class="item item2">02</div>
<div class="item item3">03</div>
<!--中間省略...-->
<div class="item item23">23</div>
<div class="item item24">24</div>
<div class="item item25">25</div>
</div>
宣告常數slider
取得捲軸(div.items
)元素。
宣告變數isDown
作為判斷滑鼠是否有被按住的 flag,給定預設值是 false。
宣告變數startX
用來放入之後取得的移動起始點座標。
宣告變數scrollLeft
用來取得div.items
下方 scrollbar 的位置,最左方是 0。
const slider = document.querySelector('.items');
let isDown = false; //flag variable
let startX;
let scrollLeft;
當滑鼠被按住(mousedown) : 把isDown
設為true
。
當滑鼠離開 slider 的範圍(mouseleave) : 把isDown
設為false
,因為離開 slider 範圍不應再有拖拉的效果(不執行mousemove
裡面的內容)。
當放開滑鼠(mouseup) : 把isDown
設為false
,因為mouseup
代表已放開滑鼠。
當滑鼠在 slider 裡移動(mousemove) : 先判斷滑鼠是否被按住,若沒被按住(isDown = false
)則直接跳出方法不往下執行。
slider.addEventListener('mousedown', () => {
isDown = true;
});
slider.addEventListener('mouseleave', () => {
isDown = false;
});
slider.addEventListener('mouseup', () => {
isDown = false;
});
slider.addEventListener('mousemove', () => {
if(!isDown) return; //stop the function from running
});
接下來在按住滑鼠時,在 slider 上添加.active
這個 class,而在滑鼠離開 slider 範圍或放開滑鼠時,移除 slider 上的.active
。
.active
這個 CSS class 選擇器,用來設定拖拉捲軸時產生的效果,例如處於拖拉狀態,捲軸(.items
)會比原來的大小略為放大一點。
event.preventDefault()
用來取消DOM
的預設功能,在這裡是避免被 browser 認為想要選取文字之類的。
slider.addEventListener('mousedown', () => {
isDown = true;
slider.classList.add('active');
});
slider.addEventListener('mouseleave', () => {
isDown = false;
slider.classList.remove('active');
});
slider.addEventListener('mouseup', () => {
isDown = false;
slider.classList.remove('active');
});
slider.addEventListener('mousemove', () => {
if(!isDown) return; //stop the function from running
e.preventDefault();
});
在 slider 裡面按住滑鼠(mousedown),首先要做的是取得滑鼠在整個 HTML 文件的座標(會隨著捲軸移動改變),所以先呼叫e.pageX
。那為什麼還要減去slider.offserLeft
呢? 因為我們要取得的是在 slider 裡面的 x 座標,而 slider 剛好有左 margin,所以要減掉offsetLeft
修正再放回startX
(滑鼠在 slider 裡的 x 座標)。
宣告常數scrollLeft
放入按住滑鼠時 slider 下方 scrollbar 的位置。
slider.addEventListener('mousedown', (e) => {
//省略...
//know where we click on the slider
startX = e.pageX - slider.offsetLeft;// if the slider has the margin left then we should correct it
scrollLeft = slider.scrollLeft;
console.log(startX);
console.log(scrollLeft);
});
在mousemove event handler
裡,宣告常數x
不斷更新滑鼠在 slider 內移動的座標,跟上面一樣要把 e.pageX 減去 slider.offsetLeft 作 slider 有左 morgin 時的修正。
常數walk
放入移動時的x座標減去起始點的x座標作為移動下方 scrollbar 的依據,把算出來的值乘上3是為了讓 scrollbar 移動的距離更加大、明顯。
最後,為了讓移動時更加順暢,把先前取得的 scrollLeft 減去 walk,指定捲軸移動的位置和距離大小,這裡一定要用減的,因為移動方向和算出來的值剛好差負號。
舉例來說按住滑鼠向左拉,此時的捲軸應該要往右(+)移動,但算出的 walk 會是負的,所以要再加上-
號修正。
slider.addEventListener('mousemove', (e) => {
//省略...
const x = e.pageX - slider.offsetLeft;
const walk = (x - startX)*3;
slider.scrollLeft = scrollLeft - walk;
});
Element.scrollLeft
HTMLElement.offsetLeft
MouseEvent.pageX
JS一秒區分clientX,offsetX,screenX,pageX之間關係