vanilla_使用Vanilla JavaScript即时搜索

顾宏朗
2023-12-01

vanilla

Originally posted on www.florin-pop.com

最初发布在www.florin-pop.com

The theme for week #15 of the Weekly Coding Challenge is:

每周编码挑战第15周的主题是:

即时搜寻 (Instant Search)

We live in a fast world and we want everything to be FAST, including search results, this is why instant search functionality became pretty much a "must have" feature instead of a "nice to have" feature.

我们生活在一个瞬息万变的世界中,我们希望一切都变得快速,包括搜索结果,这就是为什么即时搜索功能几乎变成了“必备”功能而不是“必备”功能的原因。

In this article we're going to build this feature, but only using Vanilla JavaScript :smiley:.

在本文中,我们将构建此功能 ,但仅使用Vanilla JavaScript:smiley:。

Below is the Live Preview of what we are going to build in this article. Let's search through the Countries of the world to see their Population and Flag:

下面是我们将在本文中构建的实时预览。 让我们搜索世界各国以查看其人口和国旗:

Note: that you can use React, Vue, Angular or any other framework/library to create this functionality, although making it in Vanilla JavaScript is much more fun. ?

注意 :尽管可以使用Vanilla JavaScript进行娱乐,但您可以使用React,Vue,Angular或任何其他框架/库来创建此功能。 ?

HTML (The HTML)

We'll need 2 things in our HTML:

我们HTML需要两件事:

  1. A search field

    search领域

  2. A results div where we'll display the search results

    results div,我们将在其中显示搜索结果

<input type="text" id="search" placeholder="Search for a Country" />
<div id="results"></div>

Usually we are going into the styling part next, but in this case considering that we don't yet have the entire markup (you'll see in a moment), we'll get to the JS part first. ?

通常,我们接下来将进入样式部分,但是在这种情况下,考虑到我们还没有完整的标记(您稍后会看到),我们将首先进入JS部分。 ?

JavaScript (The JavaScript)

Let's make a plan before we actually type any code. The things that we need to do are:

在实际键入任何代码之前,让我们先制定一个计划。 我们需要做的事情是:

  1. Gather a list of all the countries in the world

    收集世界上所有国家的清单
  2. Display the list of countries

    显示国家列表
  3. Update the results based on the search query

    根据搜索查询更新结果

Pretty awesome, eh? ?

太棒了,是吗? ?

第一步-获取数据 (Step one - getting the data)

I found a nice API we can use to get the list of countries we need. It is: RestCountries.eu.

我找到了一个不错的API,可以用来获取所需的国家/地区列表。 它是: RestCountries.eu

We're going to use the built in Fetch API in order to retrieve all the countries, and we're going to store them in a variable: countries.

我们将使用内置的Fetch API来检索所有国家,并将它们存储在一个变量中: countries

let countries;

const fetchCountries = async () => {
    countries = await fetch(
        'https://restcountries.eu/rest/v2/all?fields=name;population;flag'
    ).then(res => res.json());
};

As you can see, we created an async function; You can read more about this here.

如您所见,我们创建了一个异步函数; 您可以在此处了解更多信息。

Also, note that we only want 3 fields from the API (name, population and flag) so this is what we're going to get from the API by setting the fields query parameter.

另外,请注意,我们只需要API中的3个字段(名称,填充和标志),因此我们将通过设置fields查询参数从API中获得此fields

第二步-显示数据 (Step two - displaying the data)

Now, we need to create the structure of our list in order to display the data and for that we're going to create all the elements that we need (ul, li, headings, etc) inside of a function and we'll insert them into the results div we declared in our HTML.

现在,我们需要创建列表的结构以显示数据,为此,我们将在函数内部创建我们需要的所有元素( ulli ,headings等),然后插入它们放入我们在HTML中声明的results div中。

We're also going to call our fetchCountries function here because we want to loop over the countries in order to create the corresponding elements:

我们还将在这里调用fetchCountries函数,因为我们想遍历各个国家以创建相应的元素:

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, ',');
}

There is a "little" bit of code above, so let's break it down. ?

上面有一些“小”代码,所以让我们分解一下。 ?

First, we have our list (ul) with the lis that are created in the forEach loop.

首先,我们有列表( ul )以及在forEach循环中创建的li

All the lis have three children:

所有的li都有三个孩子:

  1. The flag - img

    国旗img

  2. The name of the country heading - h3

    国家标题的名称h3

  3. A div which holds: (a) the population number - h2 - and (b) The 'Population' text - h5

    包含以下内容的div :(a) populationh2和(b) 'Population'文本h5

We organized them in this manner because it'll be easier in the CSS to align everything using flexbox.

我们以这种方式组织它们,因为CSS中使用flexbox对齐所有内容将更加容易。

Alongside that, we added a class for each element because we want to style them individually in the CSS and then we used the appendChild to add these elements into the DOM at the end of the forEach function.

除此之外,我们为每个元素添加了一个class ,因为我们想在CSS中分别对它们进行样式设置,然后使用appendChild将这些元素添加到forEach函数末尾的DOM中。

And lastly, we have a numberWithComma function from StackOverflow which will add a comma as a thousand separator for the population number.

最后,我们有StackOverflow的numberWithComma函数,该函数将逗号populationpopulation数的千位分隔符。

第3步-根据搜索查询更新视图 (Step 3 - update the view based on the search query)

In this final step we're going to get the search query from the input by attaching an eventListener on it, and we're going to modify our showCountries function so that it will filter out the values we don't want to be displayed. Let's see how we can do that:

在这最后一步中,我们将通过在input附加一个eventListener来从input获取搜索查询,并且将修改showCountries函数,以便它将不需要的值filter掉。 让我们看看如何做到这一点:

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.
};

As you can see we added two new things in the showCountries function:

如您所见,我们在showCountries函数中添加了两个新内容:

  1. We are clearing the previous results by setting the innerHTML to an empty string

    我们通过将innerHTML设置为空字符串来清除先前的results

  2. We are filtering the countries by checking if the entered search_term is included in the name of the country, and we're also converting these two values toLowerCase as the user might type in upperCase letters and we still want to display the corresponding country

    我们过滤countries通过如果输入的检查search_termincludedname中的国家,而我们也将在这两个值toLowerCase为用户可能用大写字母输入,我们仍然要显示相应的国家

整个JS代码 (The entire JS Code)

Below you can find the entire JS code in case you want to copy it:

您可以在下面找到完整的JS代码,以备复制:

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 (The CSS)

Finally, let's add some styling to our little app:

最后,让我们为我们的小应用程序添加一些样式:

@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;
}

Because it's nothing fancy I'm not going into details about the CSS, but if you have any questions regarding it feel free to contact me and I'll be happy to answer your questions! ?

因为这没什么花哨的,所以我不会详细介绍CSS,但是如果您对此有任何疑问,请随时与我联系,我们将很乐意回答您的问题! ?

结论 (Conclusion)

As mentioned above, this small app could probably be done much simpler with React, Vue or Angular, and you are free to do so if you want for your submission, but I wanted to play around with Vanilla JS and it was a fun experience for me! ?

如上所述,可以使用React,Vue或Angular来简化此小型应用程序,如果您要提交,则可以随意这样做,但是我想与Vanilla JS一起玩,这对于我! ?

As always, make sure you share what you're going to create!

与往常一样,请确保您共享要创建的内容!

Happy Coding! ?

编码愉快! ?

翻译自: https://www.freecodecamp.org/news/instant-search-with-vanilla-javascript/

vanilla

 类似资料: