JS30又來啦~!!要趕在新學期開始前把一些之前落後的東西補上~!
學習低潮這種東西真是可怕~還好我逃出來了 之後再寫分文章分享那段時間的點滴:P
進入正題吧!這是要處理的是客製化video player,使用者可以操作暫停、快進等常見的影片功能,算是蠻有意思的主題,內容同時也較多,需要多一點時間吸收。
HTML
<body></div> <button class="player__button toggle" title="Toggle Play">►</button> <input type="range" name="volume" class="player__slider" min="0" max="1" step="0.05" value="1"> <input type="range" name="playbackRate" class="player__slider" min="0.5" max="2" step="0.1" value="1"> <button data-skip="-10" class="player__button">« 10s</button> <button data-skip="25" class="player__button">25s »</button> </div> </div> </body>CSS
html { box-sizing: border-box; } *, *:before, *:after { box-sizing: inherit; } body { margin: 0; padding: 0; display: flex; background: #7A419B; min-height: 100vh; background: linear-gradient(135deg, #7c1599 0%,#921099 48%,#7e4ae8 100%); background-size: cover; align-items: center; justify-content: center; } .player { max-width: 750px; border: 5px solid rgba(0,0,0,0.2); box-shadow: 0 0 20px rgba(0,0,0,0.2); position: relative; font-size: 0; overflow: hidden; } /* This css is only applied when fullscreen is active. */ .player:fullscreen { max-width: none; width: 100%; } .player:-webkit-full-screen { max-width: none; width: 100%; } .player__video { width: 100%; } .player__button { background: none; border: 0; line-height: 1; color: white; text-align: center; outline: 0; padding: 0; cursor: pointer; max-width: 50px; } .player__button:focus { border-color: #ffc600; } .player__slider { width: 10px; height: 30px; } .player__controls { display: flex; position: absolute; bottom: 0; width: 100%; transform: translateY(100%) translateY(-5px); transition: all .3s; flex-wrap: wrap; background: rgba(0,0,0,0.1); } .player:hover .player__controls { transform: translateY(0); } .player:hover .progress { height: 15px; } .player__controls > * { flex: 1; } .progress { flex: 10; position: relative; display: flex; flex-basis: 100%; height: 5px; transition: height 0.3s; background: rgba(0,0,0,0.5); cursor: ew-resize; } .progress__filled { width: 50%; background: #ffc600; flex: 0; flex-basis: 50%; } /* unholy css to style input type="range" */ input[type=range] { -webkit-appearance: none; background: transparent; width: 100%; margin: 0 5px; } input[type=range]:focus { outline: none; } input[type=range]::-webkit-slider-runnable-track { width: 100%; height: 8.4px; cursor: pointer; box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0); background: rgba(255,255,255,0.8); border-radius: 1.3px; border: 0.2px solid rgba(1, 1, 1, 0); } input[type=range]::-webkit-slider-thumb { height: 15px; width: 15px; border-radius: 50px; background: #ffc600; cursor: pointer; -webkit-appearance: none; margin-top: -3.5px; box-shadow:0 0 2px rgba(0,0,0,0.2); } input[type=range]:focus::-webkit-slider-runnable-track { background: #bada55; } input[type=range]::-moz-range-track { width: 100%; height: 8.4px; cursor: pointer; box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0); background: #ffffff; border-radius: 1.3px; border: 0.2px solid rgba(1, 1, 1, 0); } input[type=range]::-moz-range-thumb { box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0); height: 15px; width: 15px; border-radius: 50px; background: #ffc600; cursor: pointer; }Javascript
// ---------------選取元素--------------- const player = document.querySelector('.player'); const video = player.querySelector('.viewer'); const progress = player.querySelector('.progress'); const progressBar = player.querySelector('.progress__filled'); const toggle = player.querySelector('.toggle'); const skipButtons = player.querySelectorAll('[data-skip]'); const ranges = player.querySelectorAll('.player__slider'); // ---------------建立功能--------------- // 播放功能,注意video僅有paused屬性而沒有play屬性,所以用paused來操作按鈕 function toggle_play() { return video.paused ? video.play() : video.pause() } // 更新按鈕,撥放時將按鈕變更為暫停鍵,反之則恢復為撥放紐 function update_button() { toggle.textContent = video.paused ? '►' : '❚ ❚'; } // skip按鈕,利用data-attribute去操作元素 比用value來得優秀一些 function skip() { video.currentTime += parseFloat(this.dataset.skip) } // 音量、播放速度控制 function handleRangeBar() { video[this.name] = this.value; } // 進度條控制-隨時間更新 function handleProgressBar() { const percent = (video.currentTime / video.duration) * 100 progressBar.style.flexBasis = `${percent}%` } // 進度條控制-滑鼠拖曳 function scrub(e) { console.log(e.offsetX); const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration; video.currentTime = scrubTime } // ---------------設定監聽器--------------- //播放 toggle.addEventListener('click', toggle_play) video.addEventListener('play', update_button) video.addEventListener('pause', update_button) video.addEventListener('timeupdate', handleProgressBar) //快進、快退 skipButtons.forEach(buttons => { buttons.addEventListener('click', skip) }) //音量、播放速度控制 ranges.forEach(ranges => { ranges.addEventListener('change', handleRangeBar) ranges.addEventListener('mousemove', handleRangeBar) }) //進度條控制 let mouseDown = false progress.addEventListener('click', scrub) progress.addEventListener('mousedown', () => mouseDown = true) progress.addEventListener('mouseup', () => mouseDown = false) progress.addEventListener('mousemove', (e) => mouseDown && scrub(e))學習重點
- 複習change & mousemove事件的配合,兩者配合使用才能即時顯示變更
- 複習mousedown,mouseup事件的用法,建立一個flag會好用很多
- 了解如何運用event.offsetX/Y 以及 offsetWidth
- 了解video的常用屬性與方法(currentTime,paused,pause,play,duration等),特別注意video僅具有paused屬性
- 了解 && 的進階用法 ,若運算子左方為true則回傳右方 反之回傳左方 ||運算子則相反
上方學習重點補充說明
&&運算子舉例
console.log(1 && 2) // 2
console.log(0 && 4) // 4
利用這樣的方法可以將函式簡寫before progress.addEventListener('mousemove',()=>{ if (mouseDown) { scrub(e) } })after progress.addEventListener('mousemove', (e) => mouseDown && scrub(e))最終成品
