Skip to content

Commit 507a1fa

Browse files
committed
add day 11~19
1 parent eefa54e commit 507a1fa

File tree

26 files changed

+4611
-56
lines changed

26 files changed

+4611
-56
lines changed

11 - Custom Video Player/README.md

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# JS30-Day11-Custom HTML5 Video Player
2+
實作一個影片撥放器
3+
4+
## 重點整理
5+
### 1. 選取 HTML data 屬性
6+
在教學中看到用 querySelectorAll 選取標籤內的 data,以前不知道可以這樣選取,紀錄一下
7+
```javascript
8+
const skipButtons = player.querySelectorAll('[play-skip]');
9+
```
10+
11+
### 2. timeupdate 事件
12+
屬於 Audio/Video 的事件,這裡用來控制影片進度條
13+
14+
### 3. 小技巧
15+
為了讓滑鼠**實際有點擊**並拉動進度條時才會成功控制影片進度,所以使用 mouseClick 紀錄點擊狀態,當 mouseClick 為 true 時,才觸發後面 controlBar() 此函式
16+
```javascript
17+
progress.addEventListener('mousemove', (e) => mouseClick && controlBar(e));
18+
```

11 - Custom Video Player/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
</div>
2525
</div>
2626

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

3030
</html>

11 - Custom Video Player/scripts-FINISHED.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function updateButton() {
2020
}
2121

2222
function skip() {
23-
video.currentTime += parseFloat(this.dataset.skip);
23+
video.currentTime += parseFloat(this.dataset.skip);
2424
}
2525

2626
function handleRangeUpdate() {
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
const player = document.querySelector('.player'),
2+
video = player.querySelector('.viewer'),
3+
progress = player.querySelector('.progress'),
4+
progressBar = player.querySelector('.progress__filled'),
5+
toggle = player.querySelector('.toggle'),
6+
skipButtons = player.querySelectorAll('[data-skip]'),
7+
range = player.querySelectorAll('.player__slider');
8+
9+
let mouseClick = false;
10+
11+
function togglePlay(e) {
12+
const status = video.paused ? 'play' : 'pause';
13+
const icon = status === 'play' ? '❚ ❚' : '►';
14+
toggle.textContent = icon;
15+
video[status]();
16+
}
17+
18+
function skip() {
19+
video.currentTime += parseInt(this.dataset.skip);
20+
}
21+
22+
function changeRange(e) {
23+
video[e.target.name] = e.target.value;
24+
}
25+
26+
function fillBar() {
27+
const percent = (video.currentTime / video.duration) * 100;
28+
progressBar.style.flexBasis = `${percent}%`;
29+
}
30+
31+
function controlBar(e) {
32+
const time = (e.offsetX / this.offsetWidth) * video.duration;
33+
video.currentTime = time;
34+
}
35+
36+
video.addEventListener('click', togglePlay); // 控制撥放暫停
37+
video.addEventListener('timeupdate', fillBar); // 控制已撥放部分的樣式
38+
toggle.addEventListener('click', togglePlay);
39+
progress.addEventListener('click', controlBar); // 控制影片進度
40+
progress.addEventListener('mousemove', (e) => mouseClick && controlBar(e));
41+
progress.addEventListener('mousedown', () => mouseClick = true);
42+
progress.addEventListener('mouseup', () => mouseClick = false);
43+
skipButtons.forEach(btn => btn.addEventListener('click', skip)); // 控制影片前進/後退
44+
range.forEach(btn => btn.addEventListener('mousemove', changeRange)); // 控制音量/撥放速度

11 - Custom Video Player/style.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ body {
101101
width: 50%;
102102
background: #ffc600;
103103
flex: 0;
104-
flex-basis: 50%;
104+
flex-basis: 0%;
105105
}
106106

107107
/* unholy css to style input type="range" */

12 - Key Sequence Detection/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# JS30-Day12-Key Sequence Detection
2+
監聽鍵盤按鈕的實作,如果你按下 wesbos 的字串,還會出現作者放的圖片XDD

12 - Key Sequence Detection/index-Harry.html

+14
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,20 @@
99

1010
<body>
1111
<script>
12+
const pressed = [],
13+
secretCode = 'wesbos';
14+
15+
window.addEventListener('keyup', (e) => {
16+
console.log(e.key);
17+
pressed.push(e.key);
18+
// 第一個參數是負的話,從陣列後面開始數(-1 為陣列最後一個數)
19+
pressed.splice(-secretCode.length - 1, pressed.length - secretCode.length);
20+
console.log(pressed);
21+
if(pressed.join('').includes(secretCode)) {
22+
console.log('DING DING!');
23+
cornify_add();
24+
}
25+
})
1226
</script>
1327
</body>
1428

13 - Slide in on Scroll/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# JS30-Day13-Slide In on Scroll
2+
一個當滾動視窗到特定點時滑入圖片的實作

13 - Slide in on Scroll/index-Harry.html

+21-1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,26 @@ <h1>Slide in on Scroll</h1>
160160
if (callNow) func.apply(context, args);
161161
};
162162
}
163+
164+
const slideImgs = document.querySelectorAll('.slide-in');
165+
166+
function checkSlide(e) {
167+
slideImgs.forEach(img => {
168+
const scrollTopPos = (window.scrollY + window.innerHeight) - img.height / 2;
169+
const isUpperHalfImg = scrollTopPos > img.offsetTop;
170+
const imgBtm = img.offsetTop + img.height;
171+
const isLowerImg = imgBtm > window.scrollY;
172+
173+
if(isUpperHalfImg && isLowerImg) {
174+
img.classList.add('active');
175+
} else {
176+
img.classList.remove('active');
177+
}
178+
})
179+
180+
}
181+
182+
window.addEventListener('scroll', debounce(checkSlide));
163183
</script>
164184

165185
<style>
@@ -224,4 +244,4 @@ <h1>Slide in on Scroll</h1>
224244

225245
</body>
226246

227-
</html>
247+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# JS30-Day14-Object and Arrays - Reference VS Copy
2+
探討如何複製不會傳同一個參考的陣列和物件
3+
4+
## 重點整理:
5+
### 1. 陣列的複製
6+
以下的這些方法只是淺複製而已,新陣列內的陣列被修改時,原陣列也會被修改
7+
```javascript
8+
const players = ['Wes', 'Sarah', 'Ryan', 'Poppy'];
9+
10+
// 方法1: 利用回傳新陣列的特性
11+
const team2 = players.slice();
12+
13+
// 方法2: 空陣列連接 players,也是出現新陣列
14+
const team3 = [].concat(players);
15+
16+
// 方法3:
17+
const team4 = [...players];
18+
19+
// 方法4: 利用回傳新陣列的特性
20+
const team5 = Array.from(players);
21+
```
22+
23+
### 2. 物件的複製
24+
以下的這些方法只是淺複製而已,新物件內的物件被修改時,原物件也會被修改
25+
```javascript
26+
const person = {
27+
name: 'Wes Bos',
28+
age: 80
29+
};
30+
31+
// 方法1: Object.assign 會複製第二個參數的物件到第一個參數去,第三個參數可為新物件增加屬性
32+
const person2 = Object.assign({}, person, {height: 172});
33+
34+
// 方法2:
35+
const person3 = {...person};
36+
37+
const wes = {
38+
name: 'Wes',
39+
age: 100,
40+
social: {
41+
twitter: '@wesbos',
42+
facebook: 'wesbos.developer'
43+
}
44+
};
45+
46+
// 要避免淺複製的話,可以使用下面的方式:
47+
const dev2 = JSON.parse(JSON.stringify(wes));
48+
```

14 - JavaScript References VS Copying/index-Harry.html

+30-1
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,19 @@
2929
// So, how do we fix this? We take a copy instead!
3030

3131
// one way
32+
// 完整複製一個不是 reference 的陣列: 方法1:
33+
const team2 = players.slice();
3234

3335
// or create a new array and concat the old one in
36+
// 方法2:
37+
const team3 = [].concat(players);
3438

3539
// or use the new ES6 Spread
40+
// 方法3:
41+
const team4 = [...players];
42+
43+
// 方法4:
44+
const team5 = Array.from(players);
3645

3746
// now when we update it, the original one isn't changed
3847

@@ -45,14 +54,34 @@
4554
};
4655

4756
// and think we make a copy:
57+
// 方法1:
58+
const person2 = Object.assign({}, person, {
59+
height: 172
60+
});
61+
62+
// 方法2:
63+
const cap3 = {
64+
...person
65+
};
4866

4967
// how do we take a copy instead?
68+
const wes = {
69+
name: 'Wes',
70+
age: 100,
71+
social: {
72+
twitter: '@wesbos',
73+
facebook: 'wesbos.developer'
74+
}
75+
};
5076

5177
// We will hopefully soon see the object ...spread
78+
const dev = Object.assign({}, wes);
79+
80+
const dev2 = JSON.parse(JSON.stringify(wes));
5281

5382
// Things to note - this is only 1 level deep - both for Arrays and Objects. lodash has a cloneDeep method, but you should think twice before using it.
5483
</script>
5584

5685
</body>
5786

58-
</html>
87+
</html>

15 - LocalStorage/README.md

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# JS30-Day15-LocalStorage and Event Delegation
2+
介紹 LocalStorage 和 Event Delegation 事件委派,並用它們來做一個紀錄食物的實作
3+
4+
## 重點整理
5+
### 1. reset() 方法: 重置表單內的輸入值
6+
```html
7+
<form id="myForm">
8+
First name: <input type="text" name="fname"><br>
9+
Last name: <input type="text" name="lname"><br><br>
10+
<input type="button" onclick="myFunction()" value="Reset form">
11+
</form>
12+
13+
<script>
14+
function myFunction() {
15+
document.getElementById("myForm").reset();
16+
}
17+
</script>
18+
```
19+
20+
### 2. (複習)querySelector
21+
querySelector 裡面不一定要放 id 或 class,用 HTML 內的屬性(例如 href,src,name)也可以
22+
```javascript
23+
document.querySelector('[name=item]')
24+
```
25+
26+
### 3. 比較 map() vs. forEach
27+
這是我在練習時發現的,如果使用 forEach 去遍歷陣列,最後面接 join() 將會出錯(undefined),而 map 則不會出錯,所以我把兩者做一個比較,就比較能了解出錯的原因了
28+
29+
#### map:
30+
1. 遍歷後會返回一個新陣列
31+
2. 用於會修改陣列值的狀況
32+
```javascript
33+
let arr = [1, 2, 3, 4];
34+
let doubled = arr.map(num => {
35+
return num * 2;
36+
});
37+
38+
// doubled = [2, 4, 6, 8]
39+
```
40+
41+
#### forEach:
42+
1. 遍歷後不會返回一個新陣列,而是修改原陣列
43+
2. 因為會修改原陣列,所以主要應用在例如**比較****印出值**或是**存到別的陣列**的狀況
44+
```javascript
45+
let arr = [1, 2, 3, 4];
46+
arr.forEach((num, index) => {
47+
return (arr[index] = num * 2);
48+
});
49+
50+
// arr = [2, 4, 6, 8]
51+
```
52+
53+
所以 forEach 搭配 join() 出錯(undefined)的原因,就是因為它不會 return 值啊~~~
54+
55+
### 4. 客製化 checkbox
56+
如程式碼所示,在 input 和 label 前加上一些小圖示
57+
```css
58+
.plates input {
59+
display: none;
60+
}
61+
62+
.plates input + label:before {
63+
content: '⬜️';
64+
margin-right: 10px;
65+
}
66+
67+
.plates input:checked + label:before {
68+
content: '🌮';
69+
}
70+
```

0 commit comments

Comments
 (0)