新手村22 - Follow Along Link Highlighter

俗話說的好,一天一蘋果,醫生遠離我

一天一 JS,What the f*ck JavaScript?

small steps every day - 記錄著新手村日記

完成目標

  • 功能
    • 超連結Hover時,白色區塊要出現在該超連結區塊上
  • 畫面
    • 白色區塊的寬高要符合該超連結區塊
    • 滑鼠進入另一個超連結區塊時,白色的區塊不會消失

index_START.html

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
26
27
28
29
30
31
32
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>👀👀👀Follow Along Nav</title>
<link rel="stylesheet" href="style.css">
</head>
<body>

<nav>
<ul class="menu">
<li><a href="">Home</a></li>
<li><a href="">Order Status</a></li>
<li><a href="">Tweets</a></li>
<li><a href="">Read Our History</a></li>
<li><a href="">Contact Us</a></li>
</ul>
</nav>

<div class="wrapper">
<p>Lorem ipsum dolor sit amet, <a href="">consectetur</a> adipisicing elit. Est <a href="">explicabo</a> unde natus necessitatibus esse obcaecati distinctio, aut itaque, qui vitae!</p>
<p>Aspernatur sapiente quae sint <a href="">soluta</a> modi, atque praesentium laborum pariatur earum <a href="">quaerat</a> cupiditate consequuntur facilis ullam dignissimos, aperiam quam veniam.</p>
<p>Cum ipsam quod, incidunt sit ex <a href="">tempore</a> placeat maxime <a href="">corrupti</a> possimus <a href="">veritatis</a> ipsum fugit recusandae est doloremque? Hic, <a href="">quibusdam</a>, nulla.</p>
<p>Esse quibusdam, ad, ducimus cupiditate <a href="">nulla</a>, quae magni odit <a href="">totam</a> ut consequatur eveniet sunt quam provident sapiente dicta neque quod.</p>
<p>Aliquam <a href="">dicta</a> sequi culpa fugiat <a href="">consequuntur</a> pariatur optio ad minima, maxime <a href="">odio</a>, distinctio magni impedit tempore enim repellendus <a href="">repudiandae</a> quas!</p>
</div>

<script>
// 👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀
</script>
</body>
</html>

JS - step by step

首先,透過 querySelectorAll 將所有的 a 連結都找出來吧(這步驟應該很熟練了而且會是一個 NodeList(19) ),並且將帶有 Class highlightspan 附加在 body 上,這邊作者想表達的意思應該是可以透過 JS 來建立元素、新增Class 及寫進 HTML 之中

1
2
3
4
5
6
7
8
9
<script>
// 👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀
const triggers = document.querySelectorAll('a');
console.log(triggers);
const highlight = document.createElement('span');
console.log(highlight);
highlight.classList.add('highlight');
document.body.appendChild(highlight);
</script>

接下來,每當使用者滑鼠移動到連結上就會觸發 mouseenter 事件,概念與 mouseover 大致相同,唯一的差別在於並不會冒泡

mouseenter:https://tinyurl.com/y6g3x4cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
// 👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀
const triggers = document.querySelectorAll('a');
console.log(triggers);
const highlight = document.createElement('span');
console.log(highlight);
highlight.classList.add('highlight');
document.body.appendChild(highlight);

function highlightLink() {

}

triggers.forEach(a => a.addEventListener('mouseenter', highlightLink));
</script>

當使用者觸發事件後,會呼叫 highlightLink 方法,其中會回傳 Element.getBoundingClientRect() 的 DOMRect 返回值對象,一組矩形的集合

Element.getBoundingClientRect():https://tinyurl.com/yyxcclg7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
// 👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀
const triggers = document.querySelectorAll('a');
console.log(triggers);
const highlight = document.createElement('span');
console.log(highlight);
highlight.classList.add('highlight');
document.body.appendChild(highlight);

function highlightLink() {
const linkCoords = this.getBoundingClientRect();
console.log(linkCoords);
}

triggers.forEach(a => a.addEventListener('mouseenter', highlightLink));
</script>

將回傳的長、寬、X軸、Y軸設為變數 coords

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script>
// 👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀
const triggers = document.querySelectorAll('a');
console.log(triggers);
const highlight = document.createElement('span');
console.log(highlight);
highlight.classList.add('highlight');
document.body.appendChild(highlight);

function highlightLink() {
const linkCoords = this.getBoundingClientRect();
console.log(linkCoords);
const coords = {
width: linkCoords.width,
height: linkCoords.height,
top: linkCoords.top + window.scrollY,
left: linkCoords.left + window.scrollX
};
}

triggers.forEach(a => a.addEventListener('mouseenter', highlightLink));
</script>

再當滑鼠滑到連結上時附加CSS

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
26
27
<script>
// 👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀
const triggers = document.querySelectorAll('a');
console.log(triggers);
const highlight = document.createElement('span');
console.log(highlight);
highlight.classList.add('highlight');
document.body.appendChild(highlight);

function highlightLink() {
const linkCoords = this.getBoundingClientRect();
console.log(linkCoords);
const coords = {
width: linkCoords.width,
height: linkCoords.height,
top: linkCoords.top + window.scrollY,
left: linkCoords.left + window.scrollX
};

highlight.style.width = `${coords.width}px`;
highlight.style.height = `${coords.height}px`;
highlight.style.transform = `translate(${coords.left}px, ${coords.top}px)`;
//DOMRect {x: 666.93359375, y: 100, width: 93.8671875, height: 32.5, top: 100, …}
}

triggers.forEach(a => a.addEventListener('mouseenter', highlightLink));
</script>

就大功告成啦!

JS - final

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
26
<script>
// 👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀
const triggers = document.querySelectorAll('a');
console.log(triggers);
const highlight = document.createElement('span');
console.log(highlight);
highlight.classList.add('highlight');
document.body.appendChild(highlight);

function highlightLink() {
const linkCoords = this.getBoundingClientRect();
console.log(linkCoords);
const coords = {
width: linkCoords.width,
height: linkCoords.height,
top: linkCoords.top + window.scrollY,
left: linkCoords.left + window.scrollX
};

highlight.style.width = `${coords.width}px`;
highlight.style.height = `${coords.height}px`;
highlight.style.transform = `translate(${coords.left}px, ${coords.top}px)`;
}

triggers.forEach(a => a.addEventListener('mouseenter', highlightLink));
</script>

本刊同步於個人網站:http://chestertang.site/

本次範例程式碼原作者來源:https://tinyurl.com/yavm5f5n