一聚教程网:一个值得你收藏的教程网站

热门教程

怎样用JavaScript实现城市共享单车搜索功能(含加载状态与动态渲染)

时间:2026-07-02 12:07:46 编辑:袖梨 来源:一聚教程网

本文详解如何使用原生 javascript、html 和 css 构建一个基于 ccbp api 的单车搜索功能,支持输入关键词触发 fetch 请求、显示 bootstrap 加载 spinner,并动态渲染包含城市、id 和名称的单车卡片。

本文详解如何使用原生 javascript、html 和 css 构建一个基于 ccbp api 的单车搜索功能,支持输入关键词触发 fetch 请求、显示 bootstrap 加载 spinner,并动态渲染包含城市、id 和名称的单车卡片。

要实现一个轻量、可复用的城市单车搜索功能,核心在于三部分协同:用户输入控制、异步数据获取与 DOM 动态更新。以下是一个完整、开箱即用的实现方案。

✅ 基础 HTML 结构(含语义化与 Bootstrap 支持)

确保引入 Bootstrap 5 CSS(用于 form-control、btn、spinner-border 等样式),并构建清晰的 UI 层级:

<div class="container mt-4">  <h1 class="mb-4">? 城市单车搜索</h1>  <div class="mb-3">    <label for="searchInput" class="form-label">请输入单车名称</label>    <input       type="text"       class="form-control"       id="searchInput"       placeholder="例如:BikeShare, MetroBike..."       aria-describedby="searchHelp"    >    <div id="searchHelp" class="form-text">支持模糊匹配,留空可获取全部单车列表</div>  </div>  <button type="button" class="btn btn-primary mb-3" onclick="searchBikes()">    ? 开始搜索  </button>  <!-- 加载指示器(默认隐藏) -->  <div class="spinner-container text-center mb-4">    <div class="spinner-border text-primary" role="status">      <span class="visually-hidden">加载中...</span>    </div>  </div>  <!-- 搜索结果容器 -->  <div id="search-results"></div></div>

? 提示:aria-describedby 和 visually-hidden 提升了无障碍访问体验;mb-* 类确保间距合理。

? 核心 JavaScript 逻辑(健壮 & 可维护)

searchBikes() 函数封装了完整的搜索流程:清空旧结果 → 显示 Spinner → 发起 Fetch → 解析 JSON → 创建并追加卡片 → 错误处理。

立即学习“Java免费学习笔记(深入)”;

function searchBikes() {  const input = document.getElementById('searchInput');  const query = input.value.trim();  const resultsContainer = document.getElementById('search-results');  const spinner = document.querySelector('.spinner-container');  // 清空结果并显示加载状态  resultsContainer.innerHTML = '';  spinner.style.display = 'block';  // 构造请求 URL(支持空查询,即获取全部数据)  const url = query     ? `https://apis.ccbp.in/city-bikes?bike-name=${encodeURIComponent(query)}`    : 'https://apis.ccbp.in/city-bikes';  fetch(url)    .then(res => {      if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);      return res.json();    })    .then(data => {      spinner.style.display = 'none';      if (!Array.isArray(data) || data.length === 0) {        resultsContainer.innerHTML = '<div class="alert alert-info">未找到匹配的单车信息。</div>';        return;      }      data.forEach(bike => {        const card = document.createElement('div');        card.className = 'card shadow-sm mb-2';        card.innerHTML = `          <div class="card-body p-3">            <h6 class="card-title mb-1 text-primary">${bike.city || '未知城市'}</h6>            <p class="card-text mb-1"><small><strong>ID:</strong>${bike.id || '-'}</small></p>            <p class="card-text mb-0"><strong>名称:</strong>${bike.name || 'N/A'}</p>          </div>        `;        resultsContainer.appendChild(card);      });    })    .catch(err => {      spinner.style.display = 'none';      console.error('[Bike Search Error]', err);      resultsContainer.innerHTML = `        <div class="alert alert-danger">          <strong>⚠️ 请求失败</strong>:${err.message}。请检查网络或稍后重试。        </div>      `;    });}// 页面加载完成后自动搜索一次(可选:展示示例数据)document.addEventListener('DOMContentLoaded', () => {  // 可选:首次加载时自动搜索 "bike" 获取示例  // searchBikes();});

? 补充 CSS 增强体验(无框架依赖)

即使不使用 Bootstrap,也可通过轻量 CSS 保证基础样式一致性:

#search-results {  margin-top: 1.5rem;}.spinner-container {  display: none;}.card {  border-radius: 8px;  border-left: 4px solid #0d6efd;}.card-body h6 {  font-weight: 600;  font-size: 1.05rem;}.alert {  border-radius: 6px;  margin-top: 1rem;}

⚠️ 注意事项与最佳实践

  • 安全性:使用 encodeURIComponent(query) 防止 URL 注入,避免特殊字符破坏请求;
  • 空值容错:API 返回字段可能缺失(如 city 或 name),务必添加 || 'N/A' 或默认值;
  • 用户体验:建议为输入框添加 Enter 键提交支持(监听 keydown 事件);
  • 性能优化:如需防抖(debounce),可在 searchBikes 调用前封装节流逻辑,避免高频请求;
  • API 限制:该 CCBP 接口为教学用途,请勿用于生产环境;实际项目应对接自有后端或带鉴权的开放 API。

通过以上结构化实现,你将获得一个响应迅速、视觉清晰、错误友好且符合现代 Web 标准的单车搜索模块——既可用于学习 Fetch 与 DOM 操作,也具备直接集成到真实项目的潜力。

热门栏目