進入JS30的第六天,今天要將第四天學到的陣列方法,結合正規表達式,實作出有篩選功能的表單頁面。
在作者的範例中,當我們輸入英文字母時,下方將會顯示出相符的城市資訊,並且相同的地方會被強調出來。
實作連結
其實作者尚未點開接取API資料的技能,所以一開始的時候,是將網址內的資料複製到檔案內。到目前也只知道照著做就能取得API資料,因此這邊先不多加贅述。完成影片中的步驟後,我們會取得一由物件所組成的陣列,物件中的屬性為美國各城市的相關資料。
const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';
let locationData = [];
fetch(endpoint)
.then(function (blob) {
return blob.json();
}).then(function (data) {
locationData = data;
});
首先我們先將指定的元素加上監聽事件,當我們在搜尋區塊輸入字母時,便觸發事件並執行函式。而這邊我們將<input>
元素的監聽事件,設為前面提過的oninput
事件,並加上執行的函式displayMatches()
:
document.querySelector('input').addEventListener('input', displayMatches);
在我們執行的displayMatches()
函式中,需要包含以下的功能:
搜尋欄位的輸入值與陣列中的物件屬性我們知道如何取得,但是輸入的字母可能同時包含大小寫,要怎麼輕鬆的比對這兩筆資料呢?這時就要帶大家來認識正規表達式。
正規表達式是一種被用來比對字串中字元組合的模式。[2][3]
g
:表示查詢全部文本 (global match),i
: 表示不限大小寫 (ignore case)。/pattern/modifiers;
下圖是正規表達式的標準格式,而pattern中含有非常多可以利用的特殊字符,可以組合出不同比對規則。[4]
//1. 使用RegExp常數,包含兩個 / 字元之間的模式
var re = /ab+c/gi;
//2. 呼叫RegExp物件的建構子函數
var re = new RegExp("ab+c", "gi");
match()
:此方法會回傳一含比對成功字串為元素的陣列,若無符合字元則回傳null
。var test = new RegExp("a","gi");
let a ='abcAbca'
console.log(a.match(test));
//['a', 'A', 'a']
search()
:此方法會回傳第一個符合字元的index,若無符合字元則回傳-1。var test = new RegExp("ba","ig");
let a ='bcAbca'
console.log(a.search(test));
//2
replace()
:此方法會尋找符合的字元,將他們取代成設定的新字元。var test = new RegExp("ab","ig");
let a ='ababab'
console.log(a.replace(test, "cd"));
//cdcdcd
split()
:此方法會將符合的字元作為切割點,將原本的字串切割成一個陣列。var test = new RegExp("bc","ig");
let a ='abcdabcdabcd'
console.log(a.split(test));
//["a", "da", "da", "d"]
了解正規表達式之後,我們就可以在函式加入正規表達式,利用他來幫助我們判斷符合的物件。透過event.target.value
方法,我們可以取得<input>
元素觸發事件時的值,並且利用第四天所學的array.fitler()
方法,結合正規表達式的功能,過濾出包含符合字元的物件的陣列:
function displayMatches(event) {
let checkWord = event.target.value;
const matchArray = cities.filter(function(place) {
const regex = new RegExp(checkWord, 'gi');
return place.city.match(regex) || place.state.match(regex);
});
};
要將資料呈現在頁面上,就要透過在HTML上新增元素,而目前的HTML中DOM的結構如下:
<form class="search-form">
<input type="text" class="search" placeholder="City or State">
<ul class="suggestions">
<li>Filter for a city</li>
<li>or a state</li>
</ul>
</form>
在觸發函式之後,我們需要將原本ul
容器中的<li>
元素清除,然後加上含有符合的資料的<li>
元素,因此我們將透過修改ul
容器中的innerHTML
,將我們符合的資料呈現在頁面上。透過array.map()
方法,使每一個符合的物件,轉為我們需要的資料格式。但因array.map()
方法最後回傳的值為一個陣列,因此需要透過.join('')
將陣列轉為字串格式並消除之間的陣列元素之間的,
,最後再填入ul
元素中,否則陣列中的,
會因被加入HTML中而被呈現在頁面上。
將相符字元轉換顏色的方法,則是利用前面提到的replace()
方法。透過將原本的字元取代成<span class = "hl" ${checkWord} </span>
,我們就可以將原本的字元處理成<span>
元素,並透過class
將CSS屬性加上。將每個步驟的code結合起來的內容如下:
// input元素監聽事件
document.querySelector('input').addEventListener('input', displayMatches);
//選取ul元素
const suggestions = document.querySelector('.suggestions');
//觸發的函式
function displayMatches(event) {
let checkWord = event.target.value;
//篩選符合的物件
const matchArray = cities.filter(function(place) {
//設定正規表達式的篩選條件為全文以及不分大小寫
const regex = new RegExp(checkWord, 'gi');
return place.city.match(regex) || place.state.match(regex);
});
//將需要的資料轉成html格式
const html = matchArray.map(function(place) {
const regex = new RegExp(checkWord, 'gi');
//將匹配的字元獨立一個<span>元素並加上class
const cityName = place.city.replace(regex, `<span class="hl">${checkWord}</span>`);
const stateName = place.state.replace(regex, `<span class="hl">${checkWord}</span>`);
//設定回傳元素的資料格式
return `
<li>
<span class="name">${cityName},${stateName}</span>
<span class="population">${(place.population)}</span>
</li>
`;
//將陣列轉為字串
}).join('');
//將`ul`容器中的HTML內容改為符合的資料內容
suggestions.innerHTML = html;
};
作者在最後加上了一個正規表達式,利用replace()
將人口數中每三個數字的位置中間加入,
,我們來看看這個正規表達式做了什麼。這邊先提供一個參考網站,他可以偵測條件以及符合的字串,讓各位在使用時會比較好理解及判斷。[5]
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); ''
};
此正規表達式/\B(?=(\d{3})+(?!\d))/g
中使用到的特殊符號:
\B
:尋找字串中符合的位置。?=
:字串的篩選條件。\d
:d是數字(digit)的意思,這邊是指所有數字0-9。{}
:代表字元出現次數。+
:代表+前面的字元可出現1次或多次。x(?!y)
:符合'x',且後接的不是'y'。我們可以得知\B(?=...)
是要尋找符合篩選條件的字串位置,而字串的篩選條件為(\d{3})+(?!\d)
。(?!\d)
代表的是非數字的地方,而(\d{3})
代表每三個數字為一組,透過+
組合起來的意思即為以每三個任意數字為一組,從最後非數字的地方,往前尋找一組或多組以上的間隔位置。再將此位置透過replace()
轉換成,
,就可以出現作者範例中的樣式囉。
在今天課題當中,我們學到以下的技能:
array.filter()
以及array.map()
使用資料。innerHTML
將資料呈現在頁面上。在今天的範例中,我們成功將一比資料,透過正規表達式以及陣列的方法,將需要的資料篩選出來並呈現在頁面上,而這些都算是web前端工程師的基礎技能,希望有志成為web前端工程師的讀者,都可以跟我們一起來熟悉這些功能。以上是今天的實作與感想,感謝您的閱讀。