一開始長這樣,什麼也沒有
先取得元素
video.paused
是一個屬性,是判斷影片是否正在暫停狀態
影片暫停, video.paused
會顯示 true ,反之顯示 false。作者透過這個來做一些判斷。
console.dir(video)
可以查看到此屬性:
先監聽video
有click事件時,觸發影片切換播放或暫停
再來監聽video
是play事件、pause事件,都觸發按鈕的圖示,以及監聽按鈕是click事件,觸發切換影片播放或暫停
再來製作skip button,一個是退後10秒,一個是往前25秒
this.dataset.skip
是字串,所以要轉成數字讓 video.currentTime
可以加。
Q:為什麼用parseFloat轉成數字?是因為影片秒數是小數點關係嗎?
設定音量和播放速率
作者特別將這兩個 range 的 name 設定跟 video 裡面的屬性一樣名字:name="volume"
、name="playbackRate"
最後是進度條了!
因為是用 flex-basis 來顯示播放進度位置,所以設計 flex-basis 的百分比對應影片時間
作者說用 timeupdate 事件來觸發
根據影片播放不斷更新百分比
進度條也需要有點擊的方式
所以去找整個進度條的 offset
可以看到progress的是640px,如點擊一半就是 offetX 屬性為320的位置
透過console.log(e)來查看我click progress中的offsetX為多少
但影片跟不上mousemove位置,所以需要再寫條件判斷
(e) => mousedown && scrub(e)
這寫法特別??
Q:offsetWidth是蝦咪?元素的完整可見寬度
Q:progress.offsetWidth為什麼不是this.offsetWidth?
完整程式碼:
輸入一段特定字串之後出現特定的畫面,稱為 key senquence。
把輸入的key,push到 pressed 陣列
作者為了要讓 pressed 陣列長度都不會超過secretCode的長度
-secretCode.length - 1
:意思是從 pressed 陣列最後面往前數到-5的位置,因為secretCode.length
長度為4,只要長度超過4,就刪除pressed.length - secretCode.length
:這個位置是要刪除元素數量。所以長度超過 secretCode.length
的元素都是多餘元素,讓 pressed 的長度都保持不超過 secretCode.length
splice(-5,1)
,表示從陣列的倒數第5個元素開始,刪除1個元素那既然都是刪除最前面一個字,為什麼不直接寫0就好?
測試這樣寫也沒問題XD
可以看到第5個開始,就開始刪除最前面的元素,維持陣列內是4個元素,直到符合secretCode字串就執行之後的程式碼。
完整程式碼:
使用 scroll 事件,會發現他不斷觸發
例如將此網頁從頭滾動到底部,就觸發了 scroll 事件179次
透過 debounce 函式,讓整個事件觸發幾次就好
作者也是上網找 debounce 函式套用而已
可以看到同樣都是從頭滾動到底部,觸發次數只有13次
再來設計當滾動到此圖片的高度50%,就增加圖片的動畫滑入
window.innerHeight:是視窗高度
window.scrollY:是瀏覽器頂部向下滾動多少
好難懂作者的計算方式。。。。先照抄
完整程式碼:
這邊講「傳值」概念
這邊講「傳址」概念
複製array的方法(不會有傳參考)
物件也有傳址
Object.assign 只能對第一層屬性shallow copy ,第二層還是會被修改
如需要deep copy,須使用JSON.stringify先轉成字串,再用JSON.parse轉回物件,這樣修改第二層之後的內容都不會動到原物件
修改物件第二層資料:
family的資料不會被改動
Q1: document.querySelector
的 document
是什麼?
document
是window物件之一,代表整個HTML文件(DOM)。
所以這段程式碼意思是,JS會從HTML文件中找尋class為 add-items
的元素並存入變數 addItems
。如有符合就回傳第一個找到的元素,如沒有則回傳null
。
當縮小到特定範圍了,就可以直接在該元素使用querySelector
,不需要再用document.querySelector()
,因為JS只會在該元素內尋找,而不是整個document
,會更有效率。
例如:
Q2: 為什麼不是監聽 input[type="text"]
按鈕就好?而是監聽整個 <form>
表單?
<form>
的 submit
事件,確保觸發表單提交的方式都被攔截並處理,例如:輸入後可以直接按enter鍵提交。<form>
會比針對單一 input[type="submit"]
更靈活,例如:表單新增其他元素提交,就不需修改程式碼。因為事件傳遞機制是先捕捉後冒泡,所以不管點擊任何li都會回到ul身上,所以把listener放在ul,透過父節點統一處理子節點的事件就是事件委派。
Q3: 這裡的this指向誰?
addItems
,也就是<form>
,當提交表單時,addItem函式才會被執行。測試輸入abc,並提交,this印出
<form>
內容
Q4: 事件處理的參數(e / event)?
是event物件(事件物件),當事件發生時,瀏覽器自動把event物件傳進事件處理函式,如不需使用到event物件,則可以省略不寫。
為了阻止瀏覽器的預設行為。
瀏覽器默認情況下,當表單提交時會刷新頁面,或將數據發送到server端 ; 不是所有事件都有預設行為。
Event: preventDefault() method
查找 event 物件中的 preventDefault 方法,從SubmitEvent物件
沿著原型在Event物件
找到了~
Element, and its children, as well as Document and Window, are the most common event targets, but other objects can be event targets, too.
最常見的eventTarget,例如:element和其子元素、document、window
EventTarget 的實例方法:
EventTarget.addEventListener()
EventTarget.removeEventListener()
EventTarget.dispatchEvent()
因為 document.querySelector(".add-items")
會回傳一個 HTMLElement,HTMLElement 繼承自 Element,Element 又繼承自 Node,Node 最終繼承自 EventTarget。所以平常使用document.querySelector(".add-items")
才可以使用 EventTarget的方法!
(addEventListener/removeEventListener/dispatchEvent)
將表單欄位初始狀態
試著輸入noodles和pizza並按新增,印出資料如下:
物件done:false
是什麼作用?A:之後用來判斷checkbox是否checked
在<input>
裡面寫是否checked的判斷
Q5: 為什麼要寫三元判斷?A:用來判斷每個品項的狀態是否打勾,因為當重新渲染頁面時,有打勾的就維持。
渲染HTML出來後長這樣:
因為刷新頁面後,剛剛輸入的內容都不會保留,所以需要出動 localStorage
本地儲存。
可將文本儲存在瀏覽器的儲存空間
MDN
是window
裡面的物件
在devTools的 application
可以查看
只能儲存String
,如果不是字串,會自己轉型,例如Object轉成"[Object Object]"
。使用JSON.stringify
把物件轉字串
The keys and the values stored with localStorage are always in the UTF-16 string format, which uses two bytes per character. As with objects, integer keys are automatically converted to strings.
刷新頁面,資料都不會消失(但會發現原本打勾的又沒打勾了)
Q6:JSON.parse(localStorage.getItem("food"))
拿到不是物件嗎?這樣怎麼運作array methods?
A: JSON.parse(localStorage.getItem("food"))
解析出來的值會是一個 array
!! (自己看錯XD)
截圖確認
頁面加載的時候,檢查const items = JSON.parse(localStorage.getItem("items")) || [];
是否有東西,沒東西就給空陣列
最後因為頁面每次加載後,有 checked 的會變成沒打勾狀態,所以新增 toggleDone 函式處理。
因為每次點擊勾選時,都會同時兩個 pointerEvent 出現,印出來看是 <label>
和 <input type="checkbox">
所以用 event.target
方式,假如不是 "input"
的就跳過。所以確保選到<input>
標籤。
運用加在 <input type="checkbox">
的 data-index=${index}
,將itemList陣列的每一個元素的done做反向(true->false或 false->true)
完成後把結果儲存在localStorage,並將結果渲染至頁面。
完整程式碼:
offsetWidth / offsetHeight是元素實際顯示的寬度/高度
包含:width、padding、border,但不包含margin
橘色框是div,紅色框是h1
可以看到,當滑鼠滑到h1時,因為h1是div裡面的元素,offset會變成h1去計算,為了讓滑鼠移動不會因為裡面有元素而重新計算,判斷如下:
offsetLeft與offsetTop的理解圖:
補充:
用clientX / clientY
就可以避免元素不同的offset問題!不用再寫if判斷(灑花~~~)
設定陰影的偏移量,作者設定100px,表示偏移量為 -50px~50px ,左上角為 (-50,-50)
,右下角為 (50,50)
用Math.round取四捨五入
最後加上text也就是h1的陰影樣式,可以加上多個,設定不同方向的陰影