我們的好朋友,喧猴,有收藏影片跟分享影片的習慣。日積月累下來,喧猴也在自己的網頁上張貼了許多的影片。今天,喧猴心血來潮想要清點一下他所搜集的影片總時間長度為多少,於是,他找上了我們...
在影片清單中,每條項目的 data-time
屬性記錄著該影片的長度。利用 JS 將其加總並輸出為小時/分鐘/秒的格式。HTML如下:
<ul class="videos">
<li data-time="5:43">
Video 1
</li>
<li data-time="2:33">
Video 2
</li>
<!-- ...中間略 -->
<li data-time="4:04">
Video 58
</li>
</ul>
思考邏輯如下:
querySelectorAll
存取所有 data-time
屬性的值,得到的資料會是清單的格式reduce()
將其加總為單一值這些都是前幾天用過的東西,開始!
首先利用 querySelectorAll
存取所有的 data-time
,程式碼如下:
const videos = document.querySelectorAll('[data-time]');
得到的資料會以 NodeList
,也就是某種 DOM 清單的方式顯示,其為類陣列,並不具備陣列所有的原型方法。
將其轉換成陣列,如此才能使用陣列方法處理數據。程式碼如下:
const totalSeconds = [...videos]
.map(video => toSeconds(video.dataset.time))
.reduce((total, sec) => total + sec);
// 用來轉換 data-time 值的自訂函數
function toSeconds(time) {
const separateTime = time.split(':').map(parseFloat);
return separateTime[0] * 60 + separateTime[1];
}
這次我們使用 Spread Syntax 將類陣列轉換成陣列。先看 [...videos]
這段, ...
稱為 Spread Syntax,會將接在後方的清單拆成一項一項的內容,在外頭用空陣列 []
將內容括住,就成了一個內容完全相同的陣列。
轉換為陣列後,用 map
方法製造出一個內容只有每項 data-time
屬性值的新陣列, map
方法 Day 4 有提到。對於每項被 map
的元素, 我們用 toSeconds
函式處理之。原因是從 data-set
抽出的資料,是格式為「分 / 秒」的字串,因此我們先用字串的 split
方法拆出代表分與秒的字串,用 parseFloat
數值化後轉換成秒數再回傳。
接著利用 Day 4 提到的 reduce
方法將所有 data-time
累加,即可得到總秒數。
最後只需要將其轉換成小時/分鐘/秒的格式輸出即可。 程式碼如下:
const HMS = toHMS(totalSeconds);
function toHMS(secondsLeft) {
const hr = Math.floor(secondsLeft / 3600);
const min = Math.floor(secondsLeft % 3600 / 60);
const sec = secondsLeft % 60;
return {
hr: hr,
min: min,
sec: sec,
};
}
到此告一段落!
當我們協助喧猴算出他的影片總長度時,喧猴掐指一算,決定讓我們再替他算算每部影片的觀賞人數加總。為了不打擊他的信心,我們斷然拒絕了這個新請求。
氣噗噗的喧猴為了挽救人氣瓶頸,開始規劃他的直播影片第一季「跟著喧猴做家事」...
以上是 JS30 第十八篇!