[JavaScript] 六角學院鼠年全馬鐵人挑戰 API 查詢介面(上) — 主要功能說明(時間排序、手寫搜尋) _ sort、filter、includes
前幾個禮拜老師釋出了馬拉松的 API,徵求勇者幫老師刻列表介面,並列出了需求:
1. 我希望讀者可以看到文章列表排序(時間由新到舊)
2. 我可以用關鍵字搜尋想了解的標題
3. 我能夠看到每位挑戰者的排序
4. 我可以收藏追蹤挑戰者資料,並觀看他當週是否有更新 (用 blogurl 與 name 來確認身份)
當時還沒有參賽,但是因為也想自己試試,就動工了,先看 成果 吧
用到什麼:
- sort 時間排序
- forEach / for
- 搜尋功能大臣:includes
- localStorage 紀錄收藏挑戰者
- Date() 計算挑戰者當周是否更新
- 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-for
的 el
是 filterBlogData
的每一個物件,等於每一個人。第二個 v-for
的 art
表示每個人的每篇文章。
這樣子就可以把每個人的名字、文章和更新時間抓回來了
補充:因為參賽可以選擇不公開姓名或暱稱,所以有用了 forEach 把姓名為 null
的人改為不公開:
this.BlogData.forEach(item => {
if (item.name == null) item.name = "不公開";
});
時間排序新到舊
這邊會用到的是 sort
,來複習下:
- 英文字串會依字母排序
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. 我可以用關鍵字搜尋想了解的標題
🔍 搜尋功能出現啦 🔍
搜尋這邊用到的是 includes
和 filter
,先來看一下 includes
:
Basic Usage:
var str = "Welcome to itsems's medium.";
var n = str.includes("it");
console.log(n);// true
includes
會 return 字串中是否包含特定字串,回傳 true/false
,並 includes 是有分大小寫的
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 一個符合條件的陣列,不會改變原本的陣列
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,比較不方便的地方是沒有辦法設定執行的秒數。