0

0

构建原生JS搜索过滤器:添加“无匹配项”提示

花韻仙語

花韻仙語

发布时间:2025-12-12 17:34:07

|

957人浏览过

|

来源于php中文网

原创

构建原生JS搜索过滤器:添加“无匹配项”提示

本教程详细指导如何使用原生javascript构建一个高效的搜索过滤器,并集成“无匹配项”提示功能。文章将涵盖html结构、css样式优化(强调`display: none`的优势),以及核心javascript逻辑,包括事件监听、元素过滤和根据搜索结果动态显示/隐藏提示信息。通过具体代码示例和最佳实践,帮助开发者提升用户体验。

在现代网页应用中,搜索过滤功能是提升用户体验的关键一环。当用户输入搜索词却没有找到任何匹配项时,一个清晰的“无匹配项”提示能有效避免用户困惑。本教程将详细介绍如何使用原生JavaScript实现一个带有此类提示的搜索过滤器。

1. HTML结构设计

首先,我们需要定义页面的基本HTML结构,包括搜索输入框、待过滤的卡片列表,以及用于显示“无匹配项”信息的段落。

<section id="seccion-diez" class="section">
  <h2 data-dark>搜索过滤器</h2>
  <!-- 搜索输入框,用于用户输入搜索词 -->
  <input type="search" name="busqueda" placeholder="搜索..." class="card-filter">
  <!-- 无匹配项提示信息,初始状态为隐藏 -->
  <p class="hidden" id="mensaje">未找到匹配结果</p>
  <!-- 待过滤的卡片容器 -->
  <article class="contenedor-cards">
    <!-- 示例卡片项 -->
    <figure class="card">
      <img src="https://placeimg.com/200/200/nature" alt="nature">
      <figcaption>自然</figcaption>
    </figure>
    <figure class="card">
      <img src="https://placeimg.com/200/200/any" alt="any">
      <figcaption>随机</figcaption>
    </figure>
    <figure class="card">
      <img src="https://placeimg.com/200/200/tech" alt="tech">
      <figcaption>科技</figcaption>
    </figure>
    <figure class="card">
      <img src="https://placeimg.com/200/200/people" alt="people">
      <figcaption>人物</figcaption>
    </figure>
    <figure class="card">
      <img src="https://placeimg.com/200/200/animals" alt="animals">
      <figcaption>动物</figcaption>
    </figure>
    <figure class="card">
      <img src="https://placeimg.com/200/200/arch" alt="arch">
      <figcaption>建筑</figcaption>
    </figure>
  </article>
</section>

关键点:

  • input 元素:带有 card-filter 类,作为搜索事件的触发器。
  • p 元素:带有 id="mensaje" 和 class="hidden",用于显示或隐藏“无匹配项”提示。
  • figure.card 元素:代表每个可过滤的项,其 figcaption 文本将用于匹配搜索词。

2. CSS样式定义

为了实现元素的隐藏和显示,我们定义一个 .hidden 类。这里,我们推荐使用 display: none; 而非 visibility: hidden;。

.hidden {
  display: none; /* 元素将从文档流中完全移除,不占据任何空间 */
  opacity: 0;    /* 配合 display: none 使用,虽然不影响布局,但可用于平滑过渡(如果结合JS移除display:none) */
  order: 1;      /* 弹性盒或网格布局中的排序属性,这里作为示例保留 */
}

注意事项:display: none 与 visibility: hidden 的区别

  • display: none;:元素将从文档流中完全移除,不占据任何空间,且不会响应任何事件。这是隐藏元素最彻底的方式,适用于需要完全移除元素及其对布局影响的场景。
  • visibility: hidden;:元素仍然占据其原有的空间,只是在视觉上不可见,但仍然会影响布局。它依然会响应事件。

在本教程的搜索过滤场景中,我们希望隐藏的卡片不占用任何空间,因此 display: none; 是更合适的选择。

小微助手
小微助手

微信推出的一款专注于提升桌面效率的助手型AI工具

下载

3. JavaScript核心逻辑实现

JavaScript代码将负责监听搜索框的输入事件,根据输入内容过滤卡片,并根据过滤结果动态显示或隐藏“无匹配项”提示。

const d = document; // 简化 document 引用

/**
 * 实现搜索过滤功能,并动态显示“无匹配项”提示。
 * @param {string} inputSelector - 搜索输入框的CSS选择器。
 * @param {string} cardSelector - 待过滤卡片的CSS选择器。
 */
function filtroBusqueda(inputSelector, cardSelector) {
  d.addEventListener("keyup", (e) => {
    // 检查事件是否来源于指定的搜索输入框,如果不是则提前返回,避免不必要的处理
    if (!e.target.matches(inputSelector)) return;

    // 如果按下的是Escape键,清空搜索框内容
    if (e.key === "Escape") e.target.value = "";

    // 获取所有待过滤的卡片元素
    const cards = d.querySelectorAll(cardSelector);
    const searchTerm = e.target.value.toLowerCase(); // 获取搜索词并转为小写

    // 遍历所有卡片,根据搜索词进行显示或隐藏
    cards.forEach((elemento) => {
      // 检查卡片文本内容是否包含搜索词
      if (elemento.textContent.toLowerCase().includes(searchTerm)) {
        elemento.classList.remove("hidden"); // 包含则显示
      } else {
        elemento.classList.add("hidden");    // 不包含则隐藏
      }
    });

    // 过滤出当前可见的卡片
    // 使用 Array.from 或扩展运算符将 NodeList 转换为数组,以便使用 filter 方法
    const visibleCards = Array.from(cards).filter(
      (elemento) => !elemento.classList.contains("hidden")
    );

    // 根据可见卡片的数量来显示或隐藏“无匹配项”提示
    const messageElement = d.querySelector("#mensaje");
    if (visibleCards.length > 0) {
      messageElement.classList.add("hidden");    // 有可见卡片,隐藏提示
    } else {
      messageElement.classList.remove("hidden"); // 没有可见卡片,显示提示
    }
  });
}

// 当DOM内容完全加载后,初始化搜索过滤器
d.addEventListener("DOMContentLoaded", () => {
  filtroBusqueda(".card-filter", ".card");
});

代码解析:

  1. 事件监听 (keyup):当用户在文档中释放键盘按键时触发。我们只关心在搜索输入框中的按键。
  2. 早期返回 (if (!e.target.matches(inputSelector)) return;):这是一个良好的实践,可以减少不必要的代码执行和嵌套深度,提高代码可读性。
  3. 清空搜索框 (e.key === "Escape"):用户按下 Escape 键时,清空搜索框内容,方便快速重置搜索。
  4. 过滤逻辑
    • 获取所有带有 .card 类的元素。
    • 将搜索框的值转换为小写 (toLowerCase()),以便进行不区分大小写的匹配。
    • 遍历每个卡片,检查其 textContent 是否包含搜索词。
    • 如果包含,则移除 .hidden 类(显示卡片);否则,添加 .hidden 类(隐藏卡片)。
  5. “无匹配项”提示逻辑
    • 在所有卡片处理完毕后,我们通过 Array.from(cards).filter(...) 筛选出所有当前可见的卡片。
    • 如果 visibleCards.length 大于 0,说明至少有一个卡片匹配,此时应隐藏“无匹配项”提示。
    • 如果 visibleCards.length 为 0,说明没有卡片匹配,此时应显示“无匹配项”提示。

4. 完整代码示例

将上述HTML、CSS和JavaScript整合,即可实现一个功能完整的搜索过滤器。

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>带无匹配提示的搜索过滤器</title>
    <style>
        /* 基础样式,可根据需要调整 */
        body { font-family: sans-serif; margin: 20px; }
        .contenedor-cards {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin-top: 20px;
        }
        .card {
            border: 1px solid #eee;
            border-radius: 8px;
            overflow: hidden;
            text-align: center;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        .card img {
            width: 100%;
            height: 150px;
            object-fit: cover;
        }
        .card figcaption {
            padding: 10px;
            font-weight: bold;
        }
        input[type="search"] {
            width: 100%;
            padding: 10px;
            margin-bottom: 15px;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-sizing: border-box;
        }
        #mensaje {
            padding: 10px;
            background-color: #ffe0b2;
            color: #e65100;
            border: 1px solid #ff9800;
            border-radius: 4px;
            text-align: center;
            margin-bottom: 15px;
        }

        /* 隐藏元素的样式 */
        .hidden {
            display: none;
            opacity: 0;
            /* order: 1; 仅在flex或grid布局中生效,这里作为示例保留 */
        }
    </style>
</head>
<body>

    <section id="seccion-diez" class="section">
        <h2 data-dark>搜索过滤器</h2>
        <input type="search" name="busqueda" placeholder="搜索..." class="card-filter">
        <p class="hidden" id="mensaje">未找到匹配结果</p>
        <article class="contenedor-cards">
            <figure class="card">
                <img src="https://placeimg.com/200/200/nature" alt="nature">
                <figcaption>自然</figcaption>
            </figure>
            <figure class="card">
                <img src="https://placeimg.com/200/200/any" alt="any">
                <figcaption>随机</figcaption>
            </figure>
            <figure class="card">
                <img src="https://placeimg.com/200/200/tech" alt="tech">
                <figcaption>科技</figcaption>
            </figure>
            <figure class="card">
                <img src="https://placeimg.com/200/200/people" alt="people">
                <figcaption>人物</figcaption>
            </figure>
            <figure class="card">
                <img src="https://placeimg.com/200/200/animals" alt="animals">
                <figcaption>动物</figcaption>
            </figure>
            <figure class="card">
                <img src="https://placeimg.com/200/200/arch" alt="arch">
                <figcaption>建筑</figcaption>
            </figure>
        </article>
    </section>

    <script>
        const d = document;

        function filtroBusqueda(inputSelector, cardSelector) {
            d.addEventListener("keyup", (e) => {
                if (!e.target.matches(inputSelector)) return;
                if (e.key === "Escape") e.target.value = "";

                const cards = d.querySelectorAll(cardSelector);
                const searchTerm = e.target.value.toLowerCase();

                cards.forEach((elemento) => {
                    if (elemento.textContent.toLowerCase().includes(searchTerm)) {
                        elemento.classList.remove("hidden");
                    } else {
                        elemento.classList.add("hidden");
                    }
                });

                const visibleCards = Array.from(cards).filter(
                    (elemento) => !elemento.classList.contains("hidden")
                );

                const messageElement = d.querySelector("#mensaje");
                if (visibleCards.length > 0) {
                    messageElement.classList.add("hidden");
                } else {
                    messageElement.classList.remove("hidden");
                }
            });
        }

        d.addEventListener("DOMContentLoaded", () => {
            filtroBusqueda(".card-filter", ".card");
        });
    </script>

</body>
</html>

5. 注意事项与最佳实践

  1. 语义化HTML:使用 figure 和 figcaption 标签来表示带有标题的图片内容,增强了HTML的语义性。
  2. CSS类命名:使用清晰的类名如 hidden 能够准确表达其用途。
  3. 性能优化
    • 对于大型数据集,频繁的DOM操作可能会影响性能。可以考虑使用防抖 (debounce) 技术,限制 keyup 事件的触发频率,例如,在用户停止输入一段时间后才执行过滤。
    • 在过滤时,避免在循环内部频繁查询DOM(例如 d.querySelector),应在循环外部一次性获取所有相关元素。
  4. 可访问性 (Accessibility)
    • 对于搜索输入框,可以添加 aria-label 或关联 label 标签,以提高屏幕阅读器用户的体验。
    • 当“无匹配项”提示显示时,可以考虑使用 aria-live 区域,以便屏幕阅读器能够自动播报此信息。
  5. 模块化:在实际项目中,可以将 filtroBusqueda 函数放在单独的JavaScript文件中,并通过 import / export 进行模块化管理,如原始问题中的做法,这有助于代码的组织和维护。

6. 总结

通过本教程,我们学习了如何使用原生JavaScript构建一个功能完善的搜索过滤器,并成功集成了“无匹配项”提示功能。这不仅提升了用户体验,还通过最佳实践(如 display: none 的使用、早期返回语句)优化了代码结构和性能。掌握这些技术将有助于您在前端开发中创建更具交互性和用户友好的界面。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
html5动画制作有哪些制作方法
html5动画制作有哪些制作方法

html5动画制作方法有使用CSS3动画、使用JavaScript动画库、使用HTML5 Canvas等。想了解更多html5动画制作方法相关内容,可以阅读本专题下面的文章。

550

2023.10.23

HTML与HTML5的区别
HTML与HTML5的区别

HTML与HTML5的区别:1、html5支持矢量图形,html本身不支持;2、html5中可临时存储数据,html不行;3、html5新增了许多控件;4、html本身不支持音频和视频,html5支持;5、html无法处理不准确的语法,html5能够处理等等。想了解更多HTML与HTML5的相关内容,可以阅读本专题下面的文章。

473

2024.03.06

html5从入门到精通汇总
html5从入门到精通汇总

想系统掌握HTML5开发?本合集精选全网优质学习资源,涵盖免费教程、实战项目、视频课程与权威电子书,从基础语法到高级特性(Canvas、本地存储、响应式布局等)一应俱全,适合零基础小白到进阶开发者,助你高效入门并精通HTML5前端开发。

300

2025.12.30

html5新老标签汇总
html5新老标签汇总

HTML5在2026年持续优化网页语义化与交互体验,不仅引入了如<header>、<nav>、<article>、<section>、<aside>、<footer>等结构化标签,还新增了<video>、<audio>、<canvas>、<figure>、<time>、<mark>等增强多媒体与

230

2025.12.30

html5空格代码怎么写
html5空格代码怎么写

在HTML5中,空格不能直接通过键盘空格键实现,需使用特定代码。本合集详解常用空格写法:&nbsp;(不间断空格)、&ensp;(半个中文空格)、&emsp;(一个中文空格)及CSS的white-space属性等方法,帮助开发者精准控制页面排版,避免因空格失效导致布局错乱,适用于新手入门与实战参考。

107

2025.12.30

html5怎么做网站教程
html5怎么做网站教程

想从零开始学做网站?这份《HTML5怎么做网站教程》合集专为新手打造!涵盖HTML5基础语法、页面结构搭建、表单与多媒体嵌入、响应式布局及与CSS3/JavaScript协同开发等核心内容。无需编程基础,手把手教你用纯HTML5创建美观、兼容、移动端友好的现代网页。附实战案例+代码模板,快速上手,轻松迈出Web开发第一步!

165

2025.12.31

HTML5建模教程
HTML5建模教程

想快速掌握HTML5模板搭建?本合集汇集实用HTML5建模教程,从零基础入门到实战开发全覆盖!内容涵盖响应式布局、语义化标签、Canvas绘图、表单验证及移动端适配等核心技能,提供可直接复用的模板结构与代码示例。无需复杂配置,助你高效构建现代网页,轻松上手前端开发!

53

2025.12.31

html5怎么使用
html5怎么使用

想快速上手HTML5开发?本合集为你整理最实用的HTML5使用指南!涵盖HTML5基础语法、主流框架(如Bootstrap、Vue、React)集成方法,以及无需安装、直接在线编辑运行的平台推荐(如CodePen、JSFiddle)。无论你是新手还是进阶开发者,都能轻松掌握HTML5网页制作、响应式布局与交互功能开发,零配置开启高效前端编程之旅!

73

2025.12.31

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

49

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.9万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.6万人学习

CSS教程
CSS教程

共754课时 | 43.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号