最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
怎样用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 操作,也具备直接集成到真实项目的潜力。
相关文章
- 我能无限精炼装备黑暗中的敌人分布位置一览 07-03
- 寻道大千精怪最强搭配阵容是什么 07-03
- 失落城堡2隐藏关卡解锁方法 07-03
- 原神越之匙双手剑强度详析 07-03
- 《暗区突围》S18原爆点赛季上线:生化PVE模式开放 07-03
- 逆水寒手游幽蛊南疆玩法攻略 07-03