最简单的静态页面实现 (适合演示)
这个方案不涉及网络请求,数据直接写在 HTML 中,适合快速理解如何将数据渲染到页面上。
HTML 结构
我们创建一个容器来包裹所有的物流信息,并为每一条信息创建一个列表项。

(图片来源网络,侵删)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">快递信息查询</title>
<style>
/* 一些简单的样式 */
body { font-family: Arial, sans-serif; padding: 20px; }
.logistics-container { border: 1px solid #ccc; padding: 15px; border-radius: 8px; }
.logistics-item { padding: 10px; border-bottom: 1px solid #eee; position: relative; }
.logistics-item:last-child { border-bottom: none; }
.time { color: #888; font-size: 0.9em; }
.content { margin-top: 5px; }
/* 左侧时间轴样式 */
.logistics-item::before {
content: '';
position: absolute;
left: -10px;
top: 20px;
width: 12px;
height: 12px;
background-color: #007bff;
border-radius: 50%;
}
.logistics-item::after {
content: '';
position: absolute;
left: -4px;
top: 32px;
width: 1px;
height: calc(100% + 12px);
background-color: #ccc;
}
.logistics-item:last-child::after {
display: none;
}
</style>
</head>
<body>
<h1>快递单号: SF1234567890</h1>
<div id="logistics-list" class="logistics-container">
<!-- 物流信息将通过 JavaScript 动态插入这里 -->
<!-- 示例数据,稍后会被 JS 覆盖 -->
<div class="logistics-item">
<div class="time">2025-10-27 10:30:00</div>
<div class="content">【深圳市】 快件已由 [快递员姓名] 送达,感谢使用顺丰速运,期待再次为您服务。</div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
JavaScript 逻辑 (app.js)
我们定义一个包含物流信息的数组,然后遍历这个数组,为每个信息创建一个 HTML 元素,并添加到页面上。
// 1. 模拟从服务器获取的物流数据
// 在真实应用中,这些数据通常来自 API 请求
const logisticsData = [
{
time: '2025-10-27 15:22:00',
content: '【深圳市】 快件已由 [快递员姓名] 送达,感谢使用顺丰速运,期待再次为您服务。'
},
{
time: '2025-10-27 10:30:00',
content: '【深圳市】 快件已派送完毕,快件已由 [快递员姓名] 派送。'
},
{
time: '2025-10-27 08:15:00',
content: '【深圳市】 快件到达 【深圳南山营业点】,快件将由快递员 [快递员姓名] 进行下一步派送。'
},
{
time: '2025-10-26 22:45:00',
content: '【深圳市】 快件已到达 【深圳转运中心】,下一站 【深圳南山营业点】'
},
{
time: '2025-10-26 20:10:00',
content: '【广州市】 快件已离开 【广州转运中心】,下一站 【深圳转运中心】'
}
];
// 2. 获取页面上的容器元素
const logisticsListContainer = document.getElementById('logistics-list');
// 3. 清空容器(如果里面有默认的示例内容)
// logisticsListContainer.innerHTML = '';
// 4. 遍历数据,动态生成 HTML 并插入到容器中
logisticsData.forEach(item => {
// 创建一个列表项 div
const listItem = document.createElement('div');
listItem.className = 'logistics-item';
// 创建时间 div
const timeDiv = document.createElement('div');
timeDiv.className = 'time';
timeDiv.textContent = item.time;
// 创建内容 div
const contentDiv = document.createElement('div');
contentDiv.className = 'content';
contentDiv.textContent = item.content;
// 将时间和内容添加到列表项中
listItem.appendChild(timeDiv);
listItem.appendChild(contentDiv);
// 将列表项添加到容器中
// 使用 prepend 可以让最新的物流信息显示在最上面
logisticsListContainer.prepend(listItem);
});
原理总结:
- 数据准备:定义一个数据结构(通常是数组),每个元素代表一条物流信息。
- 获取容器:用
document.getElementById找到 HTML 中用于显示信息的“空盒子”。 - 遍历与创建:用
forEach循环遍历数据数组,在循环内部,用document.createElement为每条信息创建对应的 HTML 元素(<div>)。 - :用
element.textContent或element.innerHTML将数据填充到新创建的元素中。 - 添加到页面:用
container.appendChild()或container.prepend()将创建好的元素添加到容器中,从而显示在页面上。
使用 Fetch API 从服务器获取真实数据 (实际应用)
在实际项目中,物流信息存储在服务器上,我们需要通过 API (应用程序接口) 来获取。
修改 HTML (index.html)
HTML 结构基本不变,但我们会增加一个“查询”按钮,让用户主动触发数据获取。

(图片来源网络,侵删)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<!-- 样式与方案一相同 -->
<style>
/* ... (方案一的 CSS) ... */
</style>
</head>
<body>
<h1>快递信息查询</h1>
<div>
<input type="text" id="tracking-number" placeholder="请输入快递单号" value="SF1234567890">
<button id="query-btn">查询</button>
</div>
<div id="logistics-list" class="logistics-container">
<!-- 物流信息将通过 JavaScript 动态插入这里 -->
<p style="color: #888;">等待查询...</p>
</div>
<script src="app.js"></script>
</body>
</html>
JavaScript 逻辑 (app.js)
核心变化是使用 fetch 函数来发起网络请求。
// 获取页面元素
const trackingNumberInput = document.getElementById('tracking-number');
const queryBtn = document.getElementById('query-btn');
const logisticsListContainer = document.getElementById('logistics-list');
// 模拟一个 API 接口地址
// 在真实项目中,这里是一个真实的 URL, 'https://api.example.com/logistics'
const API_URL = 'https://mockapi.example.com/logistics';
// 封装一个获取物流信息的函数
async function fetchLogisticsInfo(trackingNumber) {
try {
// 在真实请求中,你可能需要将单号作为参数或请求体发送
// const response = await fetch(`${API_URL}?trackingNumber=${trackingNumber}`);
// 为了演示,我们使用一个假的 API,它会延迟 1 秒后返回我们的模拟数据
// 注意:这是一个模拟,真实 API 的行为取决于后端服务
const mockApiResponse = new Promise((resolve) => {
setTimeout(() => {
resolve({
code: 200,
message: 'success',
data: [
{ time: '2025-10-27 15:22:00', content: '【深圳市】 快件已由 [快递员姓名] 送达,感谢使用顺丰速运,期待再次为您服务。' },
{ time: '2025-10-27 10:30:00', content: '【深圳市】 快件已派送完毕,快件已由 [快递员姓名] 派送。' },
{ time: '2025-10-27 08:15:00', content: '【深圳市】 快件到达 【深圳南山营业点】,快件将由快递员 [快递员姓名] 进行下一步派送。' },
{ time: '2025-10-26 22:45:00', content: '【深圳市】 快件已到达 【深圳转运中心】,下一站 【深圳南山营业点】' },
{ time: '2025-10-26 20:10:00', content: '【广州市】 快件已离开 【广州转运中心】,下一站 【深圳转运中心】' }
]
});
}, 1000);
});
const result = await mockApiResponse;
if (result.code === 200) {
return result.data;
} else {
throw new Error(result.message || '获取物流信息失败');
}
} catch (error) {
console.error('请求出错:', error);
// 可以在这里显示一个错误提示给用户
alert('查询失败: ' + error.message);
return null;
}
}
// 渲染物流信息的函数 (与方案一中的逻辑类似)
function renderLogisticsList(data) {
// 清空容器
logisticsListContainer.innerHTML = '';
if (!data || data.length === 0) {
logisticsListContainer.innerHTML = '<p style="color: #888;">暂无物流信息。</p>';
return;
}
data.forEach(item => {
const listItem = document.createElement('div');
listItem.className = 'logistics-item';
listItem.innerHTML = `
<div class="time">${item.time}</div>
<div class="content">${item.content}</div>
`;
logisticsListContainer.prepend(listItem);
});
}
// 为查询按钮添加点击事件监听器
queryBtn.addEventListener('click', async () => {
const trackingNumber = trackingNumberInput.value.trim();
if (!trackingNumber) {
alert('请输入快递单号');
return;
}
// 在查询开始时,可以显示一个加载动画
logisticsListContainer.innerHTML = '<p style="color: #888;">正在查询中...</p>';
// 调用函数获取数据
const logisticsData = await fetchLogisticsInfo(trackingNumber);
// 获取到数据后,渲染到页面上
if (logisticsData) {
renderLogisticsList(logisticsData);
}
});
// 页面加载时,可以默认查询一次
window.addEventListener('DOMContentLoaded', () => {
queryBtn.click();
});
原理解释:
async/await和fetch:fetch是现代浏览器提供的用于发起网络请求的 API,它返回一个 Promise。async/await语法让异步代码看起来像同步代码,更容易理解和维护。- 错误处理 (
try...catch):网络请求可能会失败(比如服务器宕机、网络断开)。try...catch块可以捕获这些错误,并执行相应的错误处理逻辑(提示用户“查询失败”)。 - 事件监听 (
addEventListener):我们将查询逻辑绑定在按钮的click事件上,只有当用户点击按钮时,才会触发数据获取和渲染。 - 用户体验:在请求开始时,我们显示“正在查询中...”,在请求结束后,根据结果显示成功信息或错误信息,这提供了更好的用户体验。
使用现代前端框架 (如 Vue 或 React)
对于大型或复杂的应用,手动操作 DOM (如方案一和二) 会变得繁琐且难以维护,现代前端框架通过“声明式”的编程方式,让你只需关心数据的状态,框架会自动帮你更新视图。
这里以 Vue.js 为例,因为它更轻量且易于上手。
安装 Vue
你可以通过 CDN 引入 Vue,无需复杂的环境搭建。
<!-- 在你的 HTML 文件头部添加 --> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
HTML 和 Vue 模板 (index.html)
Vue 使用特殊的模板语法,如 来插值,v-for 来循环。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">Vue 快递信息查询</title>
<style>
/* 样式与方案一相同 */
body { font-family: Arial, sans-serif; padding: 20px; }
.logistics-container { border: 1px solid #ccc; padding: 15px; border-radius: 8px; }
.logistics-item { padding: 10px; border-bottom: 1px solid #eee; position: relative; }
.logistics-item:last-child { border-bottom: none; }
.time { color: #888; font-size: 0.9em; }
.content { margin-top: 5px; }
.logistics-item::before, .logistics-item::after { /* 与方案一相同 */ }
</style>
</head>
<body>
<div id="app">
<h1>快递单号: {{ trackingNumber }}</h1>
<div>
<input type="text" v-model="trackingNumberInput" placeholder="请输入快递单号">
<button @click="queryLogistics">查询</button>
</div>
<!-- 使用 v-if 和 v-else 进行条件渲染 -->
<div v-ifisLoading" class="logistics-container">
<p style="color: #888;">正在查询中...</p>
</div>
<div v-else class="logistics-container">
<!-- 使用 v-for 指令循环渲染物流列表 -->
<!-- :key 是必须的,帮助 Vue 高效地更新列表 -->
<div v-for="(item, index) in logisticsList" :key="index" class="logistics-item">
<div class="time">{{ item.time }}</div>
<div class="content">{{ item.content }}</div>
</div>
<p v-if="logisticsList.length === 0" style="color: #888;">暂无物流信息。</p>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
Vue 应用逻辑 (app.js)
Vue 的核心是创建一个“应用实例”,并管理其数据和方法。
// 从全局 Vue 对象中获取 createApp
const { createApp } = Vue;
// 创建 Vue 应用实例
const app = createApp({
// data() 函数返回所有需要在模板中使用的数据
data() {
return {
trackingNumberInput: 'SF1234567890', // 输入框绑定的数据
trackingNumber: 'SF1234567890', // 页面标题显示的数据
logisticsList: [], // 存储物流信息的数组
isLoading: false // 控制加载状态的标志
}
},
// methods 对象中定义所有方法(事件处理函数等)
methods: {
async queryLogistics() {
// 更新页面显示的单号
this.trackingNumber = this.trackingNumberInput;
// 显示加载状态
this.isLoading = true;
// 清空旧列表
this.logisticsList = [];
try {
// 模拟 API 请求
const mockApiResponse = new Promise((resolve) => {
setTimeout(() => {
resolve([
{ time: '2025-10-27 15:22:00', content: '【深圳市】 快件已由 [快递员姓名] 送达,感谢使用顺丰速运,期待再次为您服务。' },
{ time: '2025-10-27 10:30:00', content: '【深圳市】 快件已派送完毕,快件已由 [快递员姓名] 派送。' },
{ time: '2025-10-27 08:15:00', content: '【深圳市】 快件到达 【深圳南山营业点】,快件将由快递员 [快递员姓名] 进行下一步派送。' },
{ time: '2025-10-26 22:45:00', content: '【深圳市】 快件已到达 【深圳转运中心】,下一站 【深圳南山营业点】' },
{ time: '2025-10-26 20:10:00', content: '【广州市】 快件已离开 【广州转运中心】,下一站 【深圳转运中心】' }
]);
}, 1000);
});
const data = await mockApiResponse;
// 请求成功,将数据赋值给 logisticsList
// Vue 会检测到数据变化,并自动重新渲染视图
this.logisticsList = data;
} catch (error) {
console.error('查询失败:', error);
alert('查询失败,请稍后重试。');
} finally {
// 无论成功或失败,最后都关闭加载状态
this.isLoading = false;
}
}
},
// 生命周期钩子,在实例创建完成后调用
mounted() {
// 页面加载时,自动执行一次查询
this.queryLogistics();
}
});
// 挂载应用,将 Vue 实例关联到 id 为 'app' 的 DOM 元素上
app.mount('#app');
Vue 的优势:
- 数据驱动视图:你只需要修改
data中的数据(如this.logisticsList = newData),Vue 会自动、高效地更新对应的 DOM,无需手动createElement和appendChild。 - 声明式渲染:模板 (
<template>) 清晰地描述了视图应该是什么样子,而不是如何操作 DOM 来变成那个样子。 - 组件化:可以将快递信息列表、查询框等拆分成可复用的组件,使代码结构更清晰。
- 响应式系统:Vue 的响应式系统能精确追踪数据变化,只更新变化的部分,性能优异。
总结与选择
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 静态页面 | 简单直观,无依赖 | 无法获取实时数据,硬编码 | 学习入门、静态演示、数据固定不变的页面 |
| 原生 JS + Fetch | 轻量,无需框架,掌握核心概念 | 手动操作 DOM,复杂应用中代码冗余 | 小型项目、快速原型、对性能要求极高的场景 |
| 现代框架 (Vue/React) | 开发效率高,代码可维护性强,组件化 | 需要学习框架概念,有打包/构建步骤(Vue CLI, Vite) | 中大型单页应用(SPA)、需要长期维护和迭代的复杂项目 |
对于初学者,建议从 方案一 开始理解 DOM 操作,然后学习 方案二 掌握异步请求和事件处理,当你需要开发更复杂的应用时,再学习 方案三 这样的现代框架。
