Ban đầu được đăng trên www.florin-pop.com
Các chủ đề cho tuần #15 của Thử thách viết mã hàng tuần là:
Tìm kiếm tức thì
Chúng ta sống trong một thế giới nhanh và chúng ta muốn mọi thứ phải NHANH CHÓNG, bao gồm cả kết quả tìm kiếm, đây là lý do tại sao chức năng tìm kiếm tức thì trở thành một tính năng “phải có” thay vì một tính năng “có thì tốt”.
Trong bài viết này, chúng ta sẽ xây dựng tính năng này, nhưng chỉ sử dụng Vanilla JavaScript :smiley:.
Dưới đây là Bản xem trước trực tiếp về những gì chúng ta sẽ xây dựng trong bài viết này. Hãy tìm kiếm qua các Quốc gia trên thế giới để xem Dân số và Cờ của họ:
Ghi chú: rằng bạn có thể sử dụng React, Vue, Angular hoặc bất kỳ khung/thư viện nào khác để tạo chức năng này, mặc dù làm cho nó trong Vanilla JavaScript thú vị hơn nhiều. ?
HTML
Chúng tôi sẽ cần 2 thứ trong HTML của mình:
- Một
search
cánh đồng - Một
results
div nơi chúng tôi sẽ hiển thị kết quả tìm kiếm
<input type="text" id="search" placeholder="Search for a Country" />
<div id="results"></div>
Thông thường chúng ta sẽ đi vào phần tạo kiểu tiếp theo, nhưng trong trường hợp này do chúng ta chưa có toàn bộ phần đánh dấu (bạn sẽ thấy trong giây lát), chúng ta sẽ chuyển sang phần JS trước. ?
JavaScript
Hãy lập một kế hoạch trước khi chúng ta thực sự gõ bất kỳ mã nào. Những việc chúng ta cần làm là:
- Thu thập danh sách tất cả các quốc gia trên thế giới
- Hiển thị danh sách các quốc gia
- Cập nhật kết quả dựa trên truy vấn tìm kiếm
Khá tuyệt phải không? ?
Bước một – lấy dữ liệu
Tôi đã tìm thấy một API hay mà chúng tôi có thể sử dụng để lấy danh sách các quốc gia mà chúng tôi cần. Đó là: RestCountries.eu.
Chúng tôi sẽ sử dụng API Tìm nạp tích hợp để truy xuất tất cả các quốc gia và chúng tôi sẽ lưu trữ chúng trong một biến: countries
.
let countries;
const fetchCountries = async () => {
countries = await fetch(
'https://restcountries.eu/rest/v2/all?fields=name;population;flag'
).then(res => res.json());
};
Như bạn có thể thấy, chúng tôi đã tạo một chức năng không đồng bộ; Bạn có thể đọc thêm về điều này ở đây.
Ngoài ra, lưu ý rằng chúng tôi chỉ muốn 3 trường từ API (tên, dân số và cờ) vì vậy đây là những gì chúng tôi sẽ nhận được từ API bằng cách đặt fields
tham số truy vấn.
Bước hai – hiển thị dữ liệu
Bây giờ, chúng ta cần tạo cấu trúc danh sách của mình để hiển thị dữ liệu và để làm được điều đó, chúng ta sẽ tạo tất cả các thành phần mà chúng ta cần (ul
, li
tiêu đề, v.v.) bên trong một hàm và chúng tôi sẽ chèn chúng vào results
div chúng tôi đã khai báo trong HTML của mình.
Chúng tôi cũng sẽ gọi cho chúng tôi fetchCountries
chức năng ở đây vì chúng tôi muốn lặp qua các quốc gia để tạo các phần tử tương ứng:
const results = document.getElementById('results');
const showCountries = async () => {
// getting the data
await fetchCountries();
const ul = document.createElement('ul');
ul.classList.add('countries');
countries.forEach(country => {
// creating the structure
const li = document.createElement('li');
li.classList.add('country-item');
const country_flag = document.createElement('img');
// Setting the image source
country_flag.src = country.flag;
country_flag.classList.add('country-flag');
const country_name = document.createElement('h3');
country_name.innerText = country.name;
country_name.classList.add('country-name');
const country_info = document.createElement('div');
country_info.classList.add('country-info');
const country_population = document.createElement('h2');
country_population.innerText = numberWithCommas(country.population);
country_population.classList.add('country-population');
const country_popupation_text = document.createElement('h5');
country_popupation_text.innerText="Population";
country_popupation_text.classList.add('country-population-text');
country_info.appendChild(country_population);
country_info.appendChild(country_popupation_text);
li.appendChild(country_flag);
li.appendChild(country_name);
li.appendChild(country_info);
ul.appendChild(li);
});
results.appendChild(ul);
};
// display initial countries
showCountries();
// From StackOverflow https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
Có một chút mã ở trên, vì vậy hãy chia nhỏ nó. ?
Đầu tiên, chúng tôi có danh sách của chúng tôi (ul
) với li
s được tạo ra trong forEach
vòng.
Tất cả li
s có ba người con:
- Lá cờ –
img
- Tên của tiêu đề quốc gia –
h3
- Một
div
trong đó giữ: (a) cácpopulation
con số –h2
– và (b) Các'Population'
chữ –h5
Chúng tôi đã sắp xếp chúng theo cách này vì CSS sẽ dễ dàng căn chỉnh mọi thứ hơn bằng cách sử dụng hộp linh hoạt.
Bên cạnh đó, chúng tôi đã thêm một class
cho từng phần tử vì chúng tôi muốn tạo kiểu riêng cho chúng trong CSS và sau đó chúng tôi đã sử dụng appendChild
để thêm các phần tử này vào DOM ở cuối forEach
chức năng.
Và cuối cùng, chúng ta có một numberWithComma
chức năng từ StackOverflow sẽ thêm dấu phẩy dưới dạng dấu phân cách nghìn cho population
con số.
Bước 3 – cập nhật chế độ xem dựa trên truy vấn tìm kiếm
Trong bước cuối cùng này, chúng ta sẽ lấy truy vấn tìm kiếm từ input
bằng cách đính kèm một eventListener
trên đó, và chúng tôi sẽ sửa đổi showCountries
hoạt động để nó sẽ filter
ra các giá trị chúng tôi không muốn được hiển thị. Hãy xem làm thế nào chúng ta có thể làm điều đó:
const search_input = document.getElementById('search');
let search_term = '';
search_input.addEventListener('input', e => {
// saving the input value
search_term = e.target.value;
// re-displaying countries based on the new search_term
showCountries();
});
const showCountries = async () => {
// clear the results
results.innerHTML = '';
// see code above at Step 2.
countries
.filter(country =>
country.name.toLowerCase().includes(search_term.toLowerCase())
)
.forEach(country => {
// see code above at Step 2.
});
// see code above at Step 2.
};
Như bạn có thể thấy, chúng tôi đã thêm hai điều mới trong showCountries
chức năng:
- Chúng tôi đang xóa trước đó
results
bằng cách thiết lậpinnerHTML
đến một chuỗi rỗng - Chúng tôi đang lọc
countries
bằng cách kiểm tra nếu đã nhậpsearch_term
Làincluded
bên trongname
của quốc gia và chúng tôi cũng đang chuyển đổi hai giá trị nàytoLowerCase
vì người dùng có thể nhập chữ in hoa và chúng tôi vẫn muốn hiển thị quốc gia tương ứng
Toàn bộ mã JS
Dưới đây bạn có thể tìm thấy toàn bộ mã JS trong trường hợp bạn muốn sao chép nó:
const search_input = document.getElementById('search');
const results = document.getElementById('results');
let search_term = '';
let countries;
const fetchCountries = async () => {
countries = await fetch(
'https://restcountries.eu/rest/v2/all?fields=name;population;flag'
).then(res => res.json());
};
const showCountries = async () => {
results.innerHTML = '';
await fetchCountries();
const ul = document.createElement('ul');
ul.classList.add('countries');
countries
.filter(country =>
country.name.toLowerCase().includes(search_term.toLowerCase())
)
.forEach(country => {
const li = document.createElement('li');
li.classList.add('country-item');
const country_flag = document.createElement('img');
country_flag.src = country.flag;
country_flag.classList.add('country-flag');
const country_name = document.createElement('h3');
country_name.innerText = country.name;
country_name.classList.add('country-name');
const country_info = document.createElement('div');
country_info.classList.add('country-info');
const country_population = document.createElement('h2');
country_population.innerText = numberWithCommas(country.population);
country_population.classList.add('country-population');
const country_popupation_text = document.createElement('h5');
country_popupation_text.innerText="Population";
country_popupation_text.classList.add('country-population-text');
country_info.appendChild(country_population);
country_info.appendChild(country_popupation_text);
li.appendChild(country_flag);
li.appendChild(country_name);
li.appendChild(country_info);
ul.appendChild(li);
});
results.appendChild(ul);
};
showCountries();
search_input.addEventListener('input', e => {
search_term = e.target.value;
showCountries();
});
// From StackOverflow https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
CSS
Cuối cùng, hãy thêm một số kiểu dáng cho ứng dụng nhỏ của chúng ta:
@import url('https://fonts.googleapis.com/css?family=Roboto:300,500&display=swap');
* {
box-sizing: border-box;
}
body {
background-image: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
font-family: 'Roboto', sans-serif;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
min-height: 100vh;
}
.countries {
padding: 0;
list-style-type: none;
width: 480px;
}
.country-item {
background-color: #fff;
border-radius: 3px;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.3);
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 10px;
margin: 10px 0;
}
.country-item:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
}
.country-flag {
width: 40px;
}
.country-name {
flex: 2;
font-weight: normal;
letter-spacing: 0.5px;
margin: 0 5px;
text-align: center;
}
.country-info {
border-left: 1px solid #aaa;
color: #777;
padding: 0 15px;
flex: 1;
}
.country-population {
font-weight: 300;
line-height: 24px;
margin: 0;
margin-bottom: 12px;
}
.country-population-text {
font-weight: 300;
letter-spacing: 1px;
margin: 0;
text-transform: uppercase;
}
input {
font-family: 'Roboto', sans-serif;
border-radius: 3px;
border: 1px solid #ddd;
padding: 15px;
width: 480px;
}
Bởi vì nó không có gì lạ mắt nên tôi sẽ không đi sâu vào chi tiết về CSS, nhưng nếu bạn có bất kỳ câu hỏi nào liên quan đến CSS, vui lòng liên hệ với tôi và tôi sẽ sẵn lòng trả lời câu hỏi của bạn! ?
Phần kết luận
Như đã đề cập ở trên, ứng dụng nhỏ này có thể được thực hiện đơn giản hơn nhiều với React, Vue hoặc Angular và bạn có thể tự do làm như vậy nếu muốn để gửi, nhưng tôi muốn thử với Vanilla JS và đó là một trải nghiệm thú vị cho tôi! ?
Như mọi khi, hãy chắc chắn rằng bạn chia sẻ những gì bạn sẽ tạo!
Mã hóa vui vẻ! ?