[JavaScript] 六角學院鼠年全馬鐵人挑戰 API 查詢介面(上) — 主要功能說明(時間排序、手寫搜尋) _ sort、filter、includes

itsems
itsems_frontend
Published in
10 min readMar 22, 2020
Photo by Evgeni Tcherkasski on Unsplash

前幾個禮拜老師釋出了馬拉松的 API,徵求勇者幫老師刻列表介面,並列出了需求:

1. 我希望讀者可以看到文章列表排序(時間由新到舊)
2. 我可以用關鍵字搜尋想了解的標題
3. 我能夠看到每位挑戰者的排序
4. 我可以收藏追蹤挑戰者資料,並觀看他當週是否有更新 (用 blogurl 與 name 來確認身份)

當時還沒有參賽,但是因為也想自己試試,就動工了,先看 成果

用到什麼:

  1. sort 時間排序
  2. forEach / for
  3. 搜尋功能大臣:includes
  4. localStorage 紀錄收藏挑戰者
  5. Date() 計算挑戰者當周是否更新
  6. window 原生滾動螢幕

用到的套件:

  • axios
  • bootstrap

很多同學也自己刻了查詢介面,助教 Ray 有整理出來放在 API 的 github 上,高手在民間,大家可以找一套用起來最習慣的自己留著看。

就從老師的需求一點一點來看好了:

1. 我希望讀者可以看到文章列表排序(時間由新到舊)

這句話總共要做兩件事情:抓文章時間排序

抓文章

抓文章就是 axios 上場了,很單純的把老師的 api GET 回來:

npm install axios:

$ npm install axios

HelloWorld.vue (抱歉我很懶連 component 名字都沒改):安裝好後 script 要記得 import,並先定義一個 data 拿來儲存抓回來的 api 資料

現在 BlogData 就有抓回來的 json 了,json 的格式如下圖,一個人一個物件,並內含了 blogList, blogUrl, name … 等的資訊。

為了不要醜得不堪入目,我載入了 bootstrap 的 css,咖省時一點,不然調 css 會粉久:

$ npm install bootstrap

不過我不需要 bootstrap 的 js (或jQuery),所以只有 import 了他的 css:

/main.js

import "bootstrap/dist/css/bootstrap.css";

豪!開始寫 table 🏊🏊🏊

在規劃欄位上,我們會需要 挑戰者他的文章更新時間 ,用 v-for 把資料在 table 跑出來:

filterBlogData 是 computed filter 篩選後的資料,還沒有寫到搜尋,所以他在這邊就等於拿回來的 BlogData ,要注意的是這邊寫了兩個 v-for ,第一個 v-forelfilterBlogData 的每一個物件,等於每一個人。第二個 v-forart 表示每個人的每篇文章

這樣子就可以把每個人的名字、文章和更新時間抓回來了

補充:因為參賽可以選擇不公開姓名或暱稱,所以有用了 forEach 把姓名為 null 的人改為不公開:

this.BlogData.forEach(item => {
if (item.name == null) item.name = "不公開";
});

時間排序新到舊

這邊會用到的是 sort ,來複習下:

  1. 英文字串會依字母排序
var mm = ["emma", "medium", "w3Hexschool", "amazing",];
mm.sort();
// amazing,emma,medium,w3Hexschool

ps. 若有大小寫分,大寫在前面

剛剛的陣列改為:
var mm = ["Emma", "medium", "W3Hexschool", "amazing",];
mm.sort();
// Emma,W3Hexschool,amazing,medium

2. 比較函式 (optional)

array.sort(compareFunction)

在比較函式中,會依計算結果 return 回來的 負值、0、正值作為大小比較

舉例:

var mm= [40, 100, 15, 5, 25, 10];
mm.sort(function(a, b){return a-b});
// 5,10,15,25,40,100

40 和 100 比較的時候,40–100=-60,是負值,所以 sort 就會當作他比 100 還要小,把他排在 100 前面,以此類推就會可以把整個陣列排序完成,倒序的話就是反過來 b-a 就可以了。

回到我們的專案,我們要排序的是大家的更新時間,在 json 中回傳回來的是「2020/3/5 上午 12:18:34」像是這樣的字串,不是原生 Date 物件,無法直接排序,很多人推薦使用 Moment.js 這個套件,可以省去很多處理的時間,但是想要自己搞懂 Date() 的一切,就手寫了。

Date() 又是一個小複雜的題目,花了一點時間研究,打算再另外寫一篇整理,這邊先附上目前的處理方式:

再來第二個需求:

2. 我可以用關鍵字搜尋想了解的標題

🔍 搜尋功能出現啦 🔍

搜尋這邊用到的是 includesfilter ,先來看一下 includes

Basic Usage:

var str = "Welcome to itsems's medium.";
var n = str.includes("it");
console.log(n);
// true

includes 會 return 字串中是否包含特定字串,回傳 true/false ,並 includes 是有分大小寫的

Syntax:

string.includes(searchvalue, start)

searchvalue 就是想要尋找是否包含的字串,start 則是想要開始搜尋的位置(optional),舉例:

var str = "Hello from here";
var n = str.includes("Hello",5);
console.log(n);
// false

start 的位置設定在 Hello 後面,所以沒有找到

再接著來看 filter

Basic Usage:

var aa = [30, 13, 90];
aa.filter(el =>{
return el > 18;
})
// [30, 90]

這邊的 el 是陣列中的每個值,filer 會 return 一個符合條件的陣列,不會改變原本的陣列

Syntax

array.filter(function(currentValue, index, arr), thisValue)

currentValue(required) 是陣列中的每一個值,index(optional) 是在陣列中的位置,arr(optional) 則是陣列本人,thisValue(optional) 則可以設定為這個 function 的 this 是什麼。來看看會印出些什麼:

var aa = [30, 13, 90];
aa.filter(function(currentValue, index, arr){
console.log(currentValue, index, arr);
})

加上條件的話:

console.log(
aa.filter(function(currentValue, index, arr) {
return currentValue > 18;
})
);
// [30, 90]

回到專案,我將搜尋挑戰者搜尋文章兩種方法分開,先建好輸入的 input 和 model 要控制的 data:

<input v-model="searchAuthor"/>
<input v-model="searchBlogList" />

搜尋作者:

整段話的意思是,在 BlogData 中篩選出每一個人的名字轉成小寫之後包含了 this.searchAuthor 轉成小寫的內容,達到不分大小寫的搜尋功能。

這邊的el代表每一位挑戰者,內圈的 return 會丟符合條件(true)的挑戰者回來,外圈的 return 則會 filter 出 el 是 true 的挑戰者陣列回來。

搜尋文章:

搜尋這邊多做了一層 for,因為要往裡面找每個人的文章標題

接下來就是最後一個需求了

4. 我可以收藏追蹤挑戰者資料,並觀看他當週是否有更新 (用 blogurl 與 name 來確認身份)

挑戰者的排序在第一個需求那邊也排好了,現在要來做的是用 localStorage 來收藏挑戰者

在剛剛顯示列表中的 table,加上一個可以點擊的「+」的按鈕:

<p @click="addFollow(idx)">
<img class="add" src="../assets/add.png" alt />
</p>

addFollow(idx) 就是將作者加入追蹤清單的 methods,這邊帶入的 idx 則是在 table 上 v-for 生成出來的每一筆單獨的 key index,這樣才能分辨出是哪一位作者,另外我們還要另外定義一個 savedAuthor 這個陣列 data,拿來儲存收藏的作者用

addFollow(idx) 中把作者塞進 localStorage:

this.savedAuthor.push(this.filterBlogData[idx]);
localStorage.setItem("MyAuthor", JSON.stringify(this.savedAuthor));

push 可以把這筆資料推進 savedAuthor 中,在塞進 localStorage 的時候,因為 localStotage 沒辦法儲存陣列,所以要直接把整個陣列變成 JSON字串,再整個塞進去,這樣就可以把作者收藏了。

在收藏作者的時候,也要注意是否已經重複收藏,可以以 blogUrl 來檢查:

(ps. Ray 助教後來在 API 欄位中新增了 keyID 這個欄位,所以也可以用 keyID 來檢查)

然後要怎麼檢查挑戰者這周有沒有更新文章呢?

我的想法是假設挑戰者是星期三更新文章,那我是不是只要拿到那一周的第一天,只要他上傳文章的時間大於那周的第一天,就可以當作當周有更新?

所以我先用 getDay() 拿到今天星期幾,假設今天是 29 號星期六,那麼這周的第一天就是 29 號 -6 天=23 號星期日

拿到當周第一天之後,再檢查這位挑戰者的文章更新日期有沒有大於當第一天,就完成比對了

以上就差不多把主要的功能說明完了,還有一些細節就不贅述,可以看附在結尾的 source code,在這邊也想再分享一個這次研究發現的小功能,以前在寫頁面的 gotop 總是使用 jQeury 的 scroll,這次查了才發現原來 window 自己就有了,而且用起來非常簡便:

backToTop() {
window.scroll({
top: 0,
behavior: "smooth"
});
}

如果不需要指定 behavior,也可以只要

window.scrollTo(0, 1000);  // window視窗滾到y 1000高度的地方

第一個參數是 x,第二個是 y,比較不方便的地方是沒有辦法設定執行的秒數。

這次的練習也再複習了一個觀念: forEach/for 之間的差異

但是寫得有點累了,下一篇再說好了,我要去洗香香了 🛁

Demo

Source

--

--

itsems
itsems_frontend

Stay Close to Anything that Makes You Glad You are Alive.