Skip to content

Commit 2e1234b

Browse files
committed
add day 26~30
1 parent 2a5b549 commit 2e1234b

File tree

14 files changed

+256
-22
lines changed

14 files changed

+256
-22
lines changed

Diff for: 24 - Sticky Nav/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# JS30-Day24-Sticky Nav
2-
實作一個常見固定在網頁上方的 nav bar
2+
實作一個常見固定在網頁上方的 nav bar

Diff for: 26 - Stripe Follow Along Nav/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# JS30-Day25-Stripe Follow Along Dropdown
2+
一個滑鼠 hover 到超連結後會出現下拉選單的實作

Diff for: 26 - Stripe Follow Along Nav/index-Harry.html

+36-1
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,43 @@ <h2>Cool</h2>
233233
</style>
234234

235235
<script>
236+
const triggers = document.querySelectorAll('.cool > li');
237+
const background = document.querySelector('.dropdownBackground');
238+
const nav = document.querySelector('.top');
239+
240+
function handleEnter() {
241+
this.classList.add('trigger-enter');
242+
// 有 trigger-enter class 才觸發後面的程式碼
243+
setTimeout(() => { this.classList.contains('trigger-enter') && this.classList.add('trigger-enter-active'); }, 150);
244+
background.classList.add('open');
245+
246+
const dropdown = this.querySelector('.dropdown');
247+
const dropdownCoords = dropdown.getBoundingClientRect();
248+
// 為了減去 nav 元素上面的元素所佔的位置,所以也要取到 nav 的位置並減掉它
249+
const navCoords = nav.getBoundingClientRect();
250+
251+
const coords = {
252+
width: dropdownCoords.width,
253+
height: dropdownCoords.height,
254+
top: dropdownCoords.top - navCoords.top,
255+
left: dropdownCoords.left - navCoords.left
256+
}
257+
258+
background.style.setProperty('width', `${coords.width}px`);
259+
background.style.setProperty('height', `${coords.height}px`);
260+
// translate(x, y)
261+
background.style.setProperty('transform', `translate(${coords.left}px, ${coords.top}px)`);
262+
}
263+
264+
function handleLeave() {
265+
this.classList.remove('trigger-enter', 'trigger-enter-active');
266+
background.classList.remove('open');
267+
}
268+
269+
triggers.forEach(trigger => trigger.addEventListener('mouseenter', handleEnter));
270+
triggers.forEach(trigger => trigger.addEventListener('mouseleave', handleLeave));
236271
</script>
237272

238273
</body>
239274

240-
</html>
275+
</html>

Diff for: 27 - Click and Drag/README.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# JS30-Day27-Click and Drag to Scroll
2+
一個滑鼠點擊網頁後可以左右拉動的實作
3+
4+
## 重點整理
5+
### 1. e.scrollLeft
6+
代表元素左邊和橫軸滾動條的距離
7+
8+
MDN 介紹:
9+
https://developer.mozilla.org/zh-CN/docs/Web/API/Element/scrollLeft

Diff for: 27 - Click and Drag/index-Harry.html

+32-1
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,39 @@
3737
</div>
3838

3939
<script>
40+
const slider = document.querySelector('.items');
41+
let isDown = false,
42+
startX,
43+
scrollLeft;
44+
45+
slider.addEventListener('mousedown', (e) => {
46+
isDown = true;
47+
slider.classList.add('active')
48+
// 設定目前頁面距離
49+
startX = e.clientX - slider.offsetLeft;;
50+
// 設定卷軸左距
51+
scrollLeft = slider.scrollLeft;
52+
});
53+
54+
slider.addEventListener('mouseleave', () => {
55+
isDown = false;
56+
slider.classList.remove('active');
57+
});
58+
59+
slider.addEventListener('mouseup', () => {
60+
isDown = false;
61+
slider.classList.remove('active');
62+
})
63+
64+
slider.addEventListener('mousemove', (e) => {
65+
if(!isDown) return;
66+
e.preventDefault();
67+
const x = e.clientX;
68+
const walkDistance = (x - startX) * 3;
69+
slider.scrollLeft = scrollLeft - walkDistance;
70+
})
4071
</script>
4172

4273
</body>
4374

44-
</html>
75+
</html>

Diff for: 28 - Video Speed Controller/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# JS30-Day28-Video Speed Controller UI
2+
實作一個可以控制影片撥放速度的控制條

Diff for: 28 - Video Speed Controller/index-FINISHED.html

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
<div class="wrapper">
1111
<video class="flex" width="765" height="430" src="http://clips.vorwaerts-gmbh.de/VfE_html5.mp4" loop controls></video>
12-
<p>
1312
<div class="speed">
1413
<div class="speed-bar"></div>
1514
</div>

Diff for: 28 - Video Speed Controller/index-Harry.html

+19-5
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,38 @@
11
<!DOCTYPE html>
22
<html lang="en">
3-
43
<head>
54
<meta charset="UTF-8">
65
<title>Video Speed Scrubber</title>
76
<link rel="stylesheet" href="style.css">
87
</head>
9-
108
<body>
119

1210
<div class="wrapper">
13-
<video class="flex" width="765" height="430" src="http://clips.vorwaerts-gmbh.de/VfE_html5.mp4" loop
14-
controls></video>
11+
<video class="flex" width="765" height="430" src="http://clips.vorwaerts-gmbh.de/VfE_html5.mp4" loop controls></video>
1512
<div class="speed">
1613
<div class="speed-bar"></div>
1714
</div>
1815
</div>
1916

2017
<script>
18+
const speed = document.querySelector('.speed');
19+
const bar = speed.querySelector('.speed-bar');
20+
const video = document.querySelector('.flex');
21+
22+
function handleMove(e) {
23+
const percent = (e.clientY - this.offsetTop) / this.offsetHeight,
24+
min = 0.5,
25+
max = 4;
26+
height = Math.floor(percent * 100) + '%';
27+
let speed = percent * (max - min) + min;
28+
29+
bar.style.height = height;
30+
bar.textContent = speed.toFixed(2) + 'x';
31+
video.playbackRate = speed;
32+
}
33+
34+
speed.addEventListener('mousemove', handleMove);
2135
</script>
2236
</body>
2337

24-
</html>
38+
</html>

Diff for: 29 - Countdown Timer/README.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# JS30-Day29-Countdown Clock
2+
建立一個倒數計時器
3+
4+
## 重點整理
5+
### 1. new Date() vs. Date.now()
6+
透過這個實作重新複習一次兩者取出的值
7+
8+
`new Date()` 取出的是有星期幾,年月日幾點幾分幾秒的格式,而 `Date.now()` 取出的是從現在的時間到 1970 年 1 月 1 日開始的毫秒數值
9+
![](https://i.imgur.com/Yh6oBu3.png)
10+
11+
`new Date()` 內也可以放置 timestamp,取得過去的時間
12+
![](https://i.imgur.com/8dvB5rZ.png)
13+
14+
### 2. 可以使用屬性 name 來綁定監聽事件
15+
```html
16+
<form name="customForm" id="custom">
17+
<input type="text" name="minutes" placeholder="Enter Minutes">
18+
</form>
19+
```
20+
21+
這裡使用表單名字 customForm 綁定監聽事件
22+
```javascript
23+
document.customForm.addEventListener('submit', function(e) {
24+
e.preventDefault();
25+
// ...
26+
});
27+
```

Diff for: 29 - Countdown Timer/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ <h1 class="display__time-left"></h1>
2424
</div>
2525
</div>
2626

27-
<script src="scripts-START.js"></script>
27+
<script src="scripts-Harry.js"></script>
2828
</body>
2929
</html>

Diff for: 29 - Countdown Timer/scripts-Harry.js

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
const timerDisplay = document.querySelector('.display__time-left'),
2+
endTime = document.querySelector('.display__end-time'),
3+
buttons = document.querySelectorAll('[data-time]');
4+
let countdown;
5+
6+
// 倒數計時器主體
7+
function timer(seconds) {
8+
clearInterval(countdown);
9+
displayTimeLeft(seconds);
10+
11+
const now = Date.now(),
12+
then = now + seconds * 1000;
13+
displayEndTime(then);
14+
15+
countdown = setInterval(() => {
16+
const secondsLeft = Math.round((then - Date.now()) / 1000);
17+
if (secondsLeft < 0) {
18+
clearInterval(countdown);
19+
return;
20+
}
21+
22+
displayTimeLeft(secondsLeft);
23+
}, 1000);
24+
}
25+
26+
// 呈現時間用
27+
function displayTimeLeft(seconds) {
28+
const minutes = Math.floor(seconds / 60),
29+
remainderSeconds = seconds % 60,
30+
display = `${minutes} : ${remainderSeconds < 10 ? '0':''}${remainderSeconds}`;
31+
32+
document.title = display;
33+
timerDisplay.textContent = display;
34+
}
35+
36+
// 呈現結束時間
37+
function displayEndTime(timestamp) {
38+
const end = new Date(timestamp),
39+
hours = end.getHours() > 12 ? end.getHours() - 12 : end.getHours(),
40+
minutes = end.getMinutes(),
41+
display = `Be Back At ${hours} : ${minutes < 10 ? '0':''}${minutes}`;
42+
43+
endTime.textContent = display;
44+
}
45+
46+
function startTimer() {
47+
const seconds = parseInt(this.dataset.time);
48+
timer(seconds);
49+
}
50+
51+
buttons.forEach(button => button.addEventListener('click', startTimer));
52+
document.customForm.addEventListener('submit', function (e) {
53+
e.preventDefault();
54+
timer(this.minutes.value * 60);
55+
this.reset();
56+
})

Diff for: 30 - Whack A Mole/README.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# JS30-Day30-Whack A Mole Game
2+
最後一天!實作一個打地鼠的遊戲
3+
4+
## 重點整理
5+
### 1. e.isTrusted()
6+
判斷事件是否由使用者操作而觸發,若是則為 true,若是由程式碼或是透過 `EventTarget.dispatchEvent()` 來觸發,則為 false
7+
8+
MDN 介紹:
9+
https://developer.mozilla.org/zh-TW/docs/Web/API/Event/isTrusted

Diff for: 30 - Whack A Mole/index-Harry.html

+51-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,57 @@ <h1>Whack-a-mole! <span class="score">0</span></h1>
3838
const holes = document.querySelectorAll('.hole');
3939
const scoreBoard = document.querySelector('.score');
4040
const moles = document.querySelectorAll('.mole');
41+
let lastHole,
42+
timeUp = false,
43+
score = 0;
44+
45+
// 地鼠出現在地面的時間
46+
function randomTime(min, max) {
47+
return Math.round(Math.random() * (max - min) + min);
48+
}
49+
50+
// 隨機一個地鼠出現
51+
function randomHole(holes) {
52+
const id = Math.floor(Math.random() * holes.length),
53+
hole = holes[id];
54+
55+
if(hole === lastHole) {
56+
return randomHole(holes);
57+
}
58+
lastHole = hole;
59+
return hole;
60+
}
61+
62+
// 控制出現地鼠
63+
function peep() {
64+
const time = randomTime(200, 1000);
65+
const hole = randomHole(holes);
66+
hole.classList.add('up');
67+
setTimeout(() => {
68+
hole.classList.remove('up');
69+
if(!timeUp) peep();
70+
}, time);
71+
}
72+
73+
// 開始遊戲
74+
function startGame() {
75+
scoreBoard.textContent = 0;
76+
score = 0;
77+
timeUp = false;
78+
peep();
79+
setTimeout(() => { timeUp = true }, 10000);
80+
}
81+
82+
// 點到地鼠加分
83+
function bonk(e) {
84+
if(!e.isTrusted) return;
85+
this.parentNode.classList.remove('up');
86+
score++;
87+
scoreBoard.textContent = score;
88+
}
89+
90+
moles.forEach(mole => mole.addEventListener('click',bonk));
4191
</script>
4292
</body>
4393

44-
</html>
94+
</html>

Diff for: readme.md

+11-11
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ https://github.com/wesbos/JavaScript30
2929
| 17 | Sort Without Articles | N/A | [DEMO](https://a90100.github.io/JavaScript30/17%20-%20Sort%20Without%20Articles/index-Harry.html) |
3030
| 18 | Adding Up Times with Reduce | N/A | [DEMO](https://a90100.github.io/JavaScript30/18%20-%20Adding%20Up%20Times%20with%20Reduce/index-Harry.html) |
3131
| 19 | Webcam Fun | [筆記](https://github.com/a90100/JavaScript30/tree/master/19%20-%20Webcam%20Fun) | [DEMO](https://a90100.github.io/JavaScript30/19%20-%20Webcam%20Fun/index.html) |
32-
| 20 | Speech Detection | | |
33-
| 21 | Geolocation | | |
34-
| 22 | Follow Along Link Highlighter | | |
35-
| 23 | Speech Synthesis | | |
36-
| 24 | Sticky Nav | | |
37-
| 25 | Event Capture, Propagation, Bubbling and Once | | |
38-
| 26 | Stripe Follow Along Nav | | |
39-
| 27 | Click and Drag | | |
40-
| 28 | Video Speed Controller | | |
41-
| 29 | Countdown Timer | | |
42-
| 30 | Whack A Mole | | |
32+
| 20 | Speech Detection | [筆記](https://github.com/a90100/JavaScript30/tree/master/20%20-%20Speech%20Detection) | [DEMO](https://a90100.github.io/JavaScript30/20%20-%20Speech%20Detection/index-Harry.html) |
33+
| 21 | Geolocation | [筆記](https://github.com/a90100/JavaScript30/tree/master/21%20-%20Geolocation) | [DEMO](https://a90100.github.io/JavaScript30/21%20-%20Geolocation/index-Harry.html) |
34+
| 22 | Follow Along Link Highlighter | [筆記](https://github.com/a90100/JavaScript30/tree/master/22%20-%20Follow%20Along%20Link%20Highlighter) | [DEMO](https://a90100.github.io/JavaScript30/22%20-%20Follow%20Along%20Link%20Highlighter/index-Harry.html) |
35+
| 23 | Speech Synthesis | [筆記](https://github.com/a90100/JavaScript30/tree/master/23%20-%20Speech%20Synthesis) | [DEMO](https://a90100.github.io/JavaScript30/23%20-%20Speech%20Synthesis/index-Harry.html) |
36+
| 24 | Sticky Nav | N/A | [DEMO](https://a90100.github.io/JavaScript30/24%20-%20Sticky%20Nav/index-Harry.html) |
37+
| 25 | Event Capture, Propagation, Bubbling and Once | N/A | [DEMO](https://a90100.github.io/JavaScript30/25%20-%20Event%20Capture%2C%20Propagation%2C%20Bubbling%20and%20Once/index-Harry.html) |
38+
| 26 | Stripe Follow Along Nav | N/A | [DEMO]() |
39+
| 27 | Click and Drag | [筆記]() | [DEMO]() |
40+
| 28 | Video Speed Controller | N/A | [DEMO]() |
41+
| 29 | Countdown Timer | [筆記]() | [DEMO]() |
42+
| 30 | Whack A Mole | | [DEMO]() |

0 commit comments

Comments
 (0)