這次的章節,對於正規表達式不熟悉的我,是個非常難理解的,花了大概半天才理解清楚,程式碼全部的意思,也希望如果有地方寫得不好,請見諒,或是大大能夠補充,謝謝!
這次的功能是很常見的搜尋功能,給予關鍵字,並會在搜尋欄下面呈現符合條件的資料。
首先我們要獲取資料,排除axios之外,獲取資料又有分為兩種方式
一種為fetch,一種為XTMLHttp,兩者最大差異在於一個用callback,一個用promise
fetch雖操作較XML簡單,但目前不支持進度條,超時,錯誤不會被拒絕。
XMLHttpRequest雖較複雜,但支持許多功能
XMLHttpRequest寫法:
function requestHandler() {
if (this.readyState !== 4) return;
if (this.status === 200) {
console.log(JSON.parse(this.response));
} else {
console.log('HTTP error');
}
}
let req = new XMLHttpRequest();
req.addEventListener('load', requestHandler);
// endpoint為要獲取的資料
req.open('GET', endpoint);
req.send();
fetch寫法:
// endpoint為要獲取的資料
fetch(endpoint)
.then(item => item.json())
.then(data => console.log(data))
.catch(error => console.log(error));
fetch獲取資料又有兩種方式:一是直接賦值,二是解構後放進去。
let為變數宣告
,除非我們所設的值是可變的用let。const為常數宣告
,在設置常數,陣列,物件,函數等類型都用const。
// 直接設置空值,賦值並獲取資料
// 由於cosnt一定要有值,所以不可用const宣告
let cities = null;
fetch(endpoint)
// 將資料解析(json())
.then(item => item.json())
.then(data => cities = data)
// 已成功獲取資料
.then(cities => console.log(cities));
// 一種設置空陣列,並利用解構一個個放進去
const citiess = [];
fetch(endpoint)
.then(item => item.json())
.then(data => citiess.push(...data));
獲取完資料後,我們要獲取輸入的關鍵字,也就是獲取我們的input並增加監聽事件,當關鍵字改變時觸發,input、或keyup事件也可不用change事件
,因為在< input >,< select >,< textarea >內的值改變時且不是 focus 狀態時觸發
,也就是要當鼠標不在欄位,才會觸發,故不適合。
document.querySelector('.search').addEventListener('input', inputHandler);
而在觸發後,呼叫一個函數,用來處理資料,如過濾資料、關鍵字的反黃,人口數的格式等。
首先,將我們的關鍵字以及全部資料傳入至一個專門處理資料,但不影響原資料的Purefunction。
// 將我們所輸入的值(第一個參數),及全部的資料(第二個參數),傳入findMatches並進行過濾
const matchArray = findMatches(this.value, cities);
正則表達式就是用於查找符合某些複雜規則的字符串的工具
,在 JavaScript 中,正規表達式也是物件。
常見的寫法有兩種:
一種為: 用RegExp常數,包含兩個 / 字元之間的模式
const regex = /bc/gi;
一種為: 呼叫RegExp物件的建構子函數
const regex = new RegExp('los', 'gi');
正規表達模式由數個簡易字元組成,例如 /abc/,或是由簡易字元及特殊符號組合而成,每種組合都代表不同意思
。
\B:放在前面,代表前面要有東西(英文、數字、_),放在後面反之。
\b :放在前面,代表前面要沒有東西,後面反之。
(?=xxx):要符合xxx。
\d:d是數字,這邊是指所有數字0-9。
{}:代表字元出現次數。
+:代表+前面的字元可出現1次或多次。
(?!=xxx) : 不能符合xxx。
g : 會匹配全部
extra common
^ : 要符合在首位,ex:/^B/,Beach符合,DoBule不符合
$ : 要符合在末位,ex:/d$/,bad符合,dark不符合
. : 只要沒有換行符號都符合,ex:/.a/,w a h符合,abc不符合
i : 不分大小寫匹配
米字號 : 放在字後面,代表有0個對應字或多個字,ex:/ab*c/,abbbc符合,acb不符合
本實作程式碼:
由後往前比較,g為匹配全部的資料,而最後一個不能為數字,且前面必須為三個數字,且可以為一組以上,而最前面要有東西結論就是最前面要有東西,且要符合每三個數字為一組,至少一組(三個數字)以上,且最後面不為數字才符合
。
function populationHandler(num) {
return num.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};
他會利用正規表達式來比對搜尋字串
。
string.match(regexp)
參數為regexp(正規表達式物件),如果不是,會被隱式的使用new RegExp(obj)轉化成正規表達式物件。
而下面這段代碼,在const regex部分,創建一個正規表達式,第一個參數為我們所輸入的關鍵字,
第二個參數g為比對全部資料,i為不分大小寫,而在最後return部分,就是在比對資料,符合的話就返回。
// purefunction,也就是不會改變這個function以外的東西(如word,cities),
// 經過這個function,word,cities不變,只是拿進來使用,處理完後,最後回傳一個陣列。
function findMatches(word, cities) {
return cities.filter(place => {
// 利用正規表達式,去篩選符合條件的資料
const regex = new RegExp(word, 'gi');
// 只要其中一項(資料的城市或地區)符合,就回傳以陣列型式且符合的資料
return place.city.match(regex) || place.state.match(regex)
});
}
注意replace如果第一個參數為正則,可以把全部都替換,如果單純用replace,換完第一個就會停止
如
const a = '88cdefg88';
const regex = new RegExp('88', 'gi');
參數為正則,全部替換
a.replace(regex,gg); // ggcdefgg
參數為常數,替換一個就停止
a.replace('88',gg); // ggcdef88
此外,除了使用正規表達式來設置數字格式之外,我們還可利用toLocaleString來達到效果。
function populationHandler(num) {
// 因為在json中資料(population)是以字串型式,所以為了使用toLocaleString,
// 要將資料轉為數值,故利用*1強制轉型即可
return (num * 1).toLocaleString();
};
不加上參數的話預設以,隔開,此處用空不加上join的話,每個Li中間都會有逗號隔開(因為陣列關係)。
如下圖
function inputHandler() {
// 將我們所輸入的值(第一個參數),及全部的資料(第二個參數),傳入findMatches並進行過濾
const matchArray = findMatches(this.value, cities);
console.log(matchArray); // 會獲取條件過濾後的資料
// 獲取過濾完的資料後,以列表呈現在搜尋框下
const html = matchArray.map(place => {
const regex = new RegExp(this.value, 'gi');
// 將地區及城市的關鍵字,以有顏色的字體去取代
const cityName = place.city.replace(regex, `<span class="hl">${this.value}</span>`);
const stateName = place.state.replace(regex, `<span class="hl">${this.value}</span>`);
// 最後回傳符合條件的城市,地區,及處理好的對應人口
return `
<li>
<span class="name">${cityName}, ${stateName}</span>
<span class="population">${numberWithCommas(place.population)}</span>
</li>
`;
// join將字串以括號內的元素合成一個字串,預設為,,此處用空
// 不加join的話每個Li中間都會有逗號隔開(因為陣列關係)
}).join('');
console.log(html);
document.querySelector('.suggestions').innerHTML = html;
}
而我們再拿到過濾完的資料後,需要將資料呈現出來,因為回傳的資料是以陣列型式
,故利用map對每個資料做處理,利用replace方法去改變每筆符合資料,關鍵字的顏色
,並回傳一個以正規表達式處理好的人口數,然後將整個陣列,用join方法切割並合併
成一個字串,最後放進ul裡面即可
完整結果如下圖