iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 18
0
Modern Web

JS30 錄系列 第 18

Day 18 - Adding Up Time With Reduce

緣起

我們的好朋友,喧猴,有收藏影片跟分享影片的習慣。日積月累下來,喧猴也在自己的網頁上張貼了許多的影片。今天,喧猴心血來潮想要清點一下他所搜集的影片總時間長度為多少,於是,他找上了我們...

任務目標

在影片清單中,每條項目的 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>

作法

思考邏輯如下:

  1. 首先利用 querySelectorAll 存取所有 data-time 屬性的值,得到的資料會是清單的格式
  2. 接著將值轉換成陣列,才能使用陣列方法 reduce() 將其加總為單一值
  3. 將該值轉換為小時/分鐘/秒的格式並輸出

這些都是前幾天用過的東西,開始!
首先利用 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 第十八篇!

Reference

  1. Spread Syntax
  2. 完整程式碼

上一篇
Day 17 - Sort Without Articles
下一篇
Day 19 - Webcam Fun - Part I - Take a Photo from Webcam
系列文
JS30 錄30

尚未有邦友留言

立即登入留言