使用 HTML + JavaScript 在高德地图上实现物流轨迹跟踪系统

在电商行业蓬勃发展的今天,物流信息查询已成为人们日常生活中的重要需求。本文将详细介绍如何基于高德地图 API 利用 HTML + JavaScript 实现物流轨迹跟踪系统的开发。

效果演示

项目概述

本项目主要包含以下核心功能:

  • 地图初始化与展示
  • 运单号查询功能
  • 物流轨迹可视化显示

准备工作

  1. 注册高德开放平台账号,创建应用并获取API Key。

  2. 引入高德地图 API (将 API_Key 替换为自己的)和德地图 UI 组件库

html 复制代码
<script src="https://webapi.amap.com/maps?v=2.0&key=API_Key"></script>
<script src="https://webapi.amap.com/ui/1.1/main.js"></script>

页面结构与样式设计

创建 HTML 结构

页面主要包含两个核心区域:

  • container:用于承载地图展示的核心区域
  • panel:右上角的操作面板,包含输入框、查询按钮和物流信息展示区
html 复制代码
<div id="container"></div>
<div id="panel">
    <h3>物流轨迹查询</h3>
    <div class="input-group">
        <input type="text" id="orderNumber" placeholder="请输入运单号">
    </div>
    <button id="queryBtn">查询轨迹</button>
    <div id="logistics-info"></div>
</div>
设计 CSS 样式

地图容器样式

css 复制代码
#container {
    width: 100%;
    height: 100vh;
    position: relative;
}

操作面板样式

css 复制代码
#panel {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 300px;
    background: white;
    padding: 10px;
    box-shadow: 0 0 10px rgba(0,0,0,0.2);
    z-index: 999;
    border-radius: 5px;
}
.input-group {
    margin-bottom: 10px;
}
input, button {
    padding: 8px;
    width: 100%;
    box-sizing: border-box;
}
button {
    background: #1E90FF;
    color: white;
    border: none;
    cursor: pointer;
}
button:hover {
    background: #1874CD;
}
#logistics-info {
    margin-top: 10px;
    font-size: 14px;
    max-height: 300px;
    overflow-y: auto;
}
.info-item {
    margin-bottom: 5px;
    padding-bottom: 5px;
    border-bottom: 1px solid #eee;
}
.info-time {
    color: #888;
    font-size: 12px;
}
.info-content {
    color: #333;
}

核心功能实现

初始化地图
js 复制代码
var map = new AMap.Map('container', {
    zoom: 10,  // 缩放级别
    center: [116.397428, 39.90923],  // 中心点坐标(北京)
    viewMode: '2D'  // 使用2D视图
});
获取物流数据

这里只是示例,模拟了不同运单号返回不同数据,实际应用中可以通过请求后端 API 获取真实数据。

js 复制代码
function getLogisticsData(orderNumber) {
    if (orderNumber === "123456") {
        return {
            status: "success",
            company: "顺丰速运",
            number: orderNumber,
            steps: [
                {
                    time: "2023-05-01 08:00:00",
                    location: [116.404, 39.915],
                    content: "快件已到达【北京朝阳集散中心】"
                },
                // ...
            ]
        };
    } else if (orderNumber === "654321") {
        return {
            status: "success",
            company: "中通快递",
            number: orderNumber,
            steps: [
                // ...
            ]
        };
    } else {
        return {
            status: "error",
            message: "未找到该运单号的物流信息"
        };
    }
}
清除地图上的轨迹和标记
js 复制代码
function clearMap() {
    if (polyline) {
        map.remove(polyline);
        polyline = null;
    }

    if (markers.length > 0) {
        map.remove(markers);
        markers = [];
    }
}
显示物流轨迹
js 复制代码
function showLogisticsTrack(data) {
    // 清除之前的轨迹
    clearMap();
    // 更新物流信息显示
    var infoDiv = document.getElementById('logistics-info');
    infoDiv.innerHTML = '';
    if (data.status === "error") {
        infoDiv.innerHTML = '<div class="info-item">' + data.message + '</div>';
        return;
    }
    // 显示物流公司信息
    infoDiv.innerHTML += '<div class="info-item"><strong>' + data.company + '</strong> 运单号: ' + data.number + '</div>';
    // 提取轨迹点坐标
    var lineArr = [];
    // 按时间顺序排序(确保最早的步骤在最前面)
    data.steps.sort(function(a, b) {
        return new Date(a.time) - new Date(b.time);
    });
    // 添加标记和轨迹线
    data.steps.forEach(function(step, index) {
        // 添加到轨迹线
        lineArr.push(step.location);
        // 创建标记
        var marker = new AMap.Marker({
            position: step.location,
            map: map,
            content: '<div style="background: #1E90FF; color: white; border-radius: 50%; width: 20px; height: 20px; text-align: center; line-height: 20px;">' + (index + 1) + '</div>',
            offset: new AMap.Pixel(-10, -10)
        });
        // 信息窗口内容
        var infoContent = '<div style="padding: 5px;">' +
            '<div style="font-weight: bold;">步骤 ' + (index + 1) + '</div>' +
            '<div>' + step.content + '</div>' +
            '<div style="color: #888; font-size: 12px;">' + step.time + '</div>' +
            '</div>';
        // 点击标记显示信息窗口
        marker.on('click', function() {
            new AMap.InfoWindow({
                content: infoContent,
                offset: new AMap.Pixel(0, -30)
            }).open(map, step.location);
        });
        markers.push(marker);
        // 添加物流信息到面板
        infoDiv.innerHTML += '<div class="info-item">' +
            '<div class="info-time">' + step.time + '</div>' +
            '<div class="info-content">' + step.content + '</div>' +
            '</div>';
    });
    // 绘制轨迹线
    polyline = new AMap.Polyline({
        path: lineArr,
        isOutline: true,
        outlineColor: '#ffeeff',
        borderWeight: 1,
        strokeColor: "#3366FF",
        strokeOpacity: 1,
        strokeWeight: 5,
        strokeStyle: "solid",
        lineJoin: 'round',
        lineCap: 'round',
        zIndex: 50
    });
    map.add(polyline);
    // 调整视图以适应轨迹
    map.setFitView(polyline);
}
查询功能实现

输入运单号,点击【查询轨迹】按钮获取输入框中的运单号,根据运单号获取物流数据,显示物流轨迹。

js 复制代码
document.getElementById('queryBtn').addEventListener('click', function() {
    var orderNumber = document.getElementById('orderNumber').value.trim();
    if (!orderNumber) return;
    var logisticsData = getLogisticsData(orderNumber);
    showLogisticsTrack(logisticsData);
});

完整代码

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <title>物流轨迹跟踪系统</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
        }
        #container {
            width: 100%;
            height: 100vh;
            position: relative;
        }
        #panel {
            position: absolute;
            top: 10px;
            right: 10px;
            width: 300px;
            background: white;
            padding: 10px;
            box-shadow: 0 0 10px rgba(0,0,0,0.2);
            z-index: 999;
            border-radius: 5px;
        }
        .input-group {
            margin-bottom: 10px;
        }
        input, button {
            padding: 8px;
            width: 100%;
            box-sizing: border-box;
        }
        button {
            background: #1E90FF;
            color: white;
            border: none;
            cursor: pointer;
        }
        button:hover {
            background: #1874CD;
        }
        #logistics-info {
            margin-top: 10px;
            font-size: 14px;
            max-height: 300px;
            overflow-y: auto;
        }
        .info-item {
            margin-bottom: 5px;
            padding-bottom: 5px;
            border-bottom: 1px solid #eee;
        }
        .info-time {
            color: #888;
            font-size: 12px;
        }
        .info-content {
            color: #333;
        }
    </style>
</head>
<body>
<div id="container"></div>
<div id="panel">
    <h3>物流轨迹查询</h3>
    <div class="input-group">
        <input type="text" id="orderNumber" placeholder="请输入运单号">
    </div>
    <button id="queryBtn">查询轨迹</button>
    <div id="logistics-info"></div>
</div>

<!-- 引入高德地图API -->
<script src="https://webapi.amap.com/maps?v=2.0&key=API_Key"></script>
<!-- 引入高德地图UI组件库 -->
<script src="https://webapi.amap.com/ui/1.1/main.js"></script>

<script>
    // 初始化地图
    var map = new AMap.Map('container', {
        zoom: 10,  // 缩放级别
        center: [116.397428, 39.90923],  // 中心点坐标(北京)
        viewMode: '2D'  // 使用2D视图
    });


    // 轨迹线
    var polyline = null;
    // 轨迹点标记
    var markers = [];
    // 模拟物流数据(实际应用中应从后端API获取)
    function getLogisticsData(orderNumber) {
        if (orderNumber === "123456") {
            return {
                status: "success",
                company: "顺丰速运",
                number: orderNumber,
                steps: [
                    {
                        time: "2023-05-01 08:00:00",
                        location: [116.404, 39.915],
                        content: "快件已到达【北京朝阳集散中心】"
                    },
                    {
                        time: "2023-05-01 10:30:00",
                        location: [116.408, 39.925],
                        content: "快件已从【北京朝阳集散中心】发出,下一站【北京海淀集散中心】"
                    },
                    {
                        time: "2023-05-01 14:15:00",
                        location: [116.300, 39.960],
                        content: "快件已到达【北京海淀集散中心】"
                    },
                    {
                        time: "2023-05-02 09:00:00",
                        location: [116.310, 39.980],
                        content: "快件正在派送中,派件员:张三,电话:138****1234"
                    },
                    {
                        time: "2023-05-02 11:30:00",
                        location: [116.315, 39.985],
                        content: "快件已签收,签收人:李四"
                    }
                ]
            };
        } else if (orderNumber === "654321") {
            return {
                status: "success",
                company: "中通快递",
                number: orderNumber,
                steps: [
                    {
                        time: "2023-05-10 13:20:00",
                        location: [121.4737, 31.2304],
                        content: "快件已从【上海虹口集散中心】发出"
                    },
                    {
                        time: "2023-05-11 08:45:00",
                        location: [120.1551, 30.2741],
                        content: "快件已到达【杭州集散中心】"
                    },
                    {
                        time: "2023-05-11 16:30:00",
                        location: [120.2108, 30.2468],
                        content: "快件已从【杭州集散中心】发出,下一站【杭州西湖分部】"
                    }
                ]
            };
        } else {
            return {
                status: "error",
                message: "未找到该运单号的物流信息"
            };
        }
    }

    // 清除地图上的轨迹和标记
    function clearMap() {
        if (polyline) {
            map.remove(polyline);
            polyline = null;
        }

        if (markers.length > 0) {
            map.remove(markers);
            markers = [];
        }
    }

    // 显示物流轨迹
    function showLogisticsTrack(data) {
        // 清除之前的轨迹
        clearMap();

        // 更新物流信息显示
        var infoDiv = document.getElementById('logistics-info');
        infoDiv.innerHTML = '';

        if (data.status === "error") {
            infoDiv.innerHTML = '<div class="info-item">' + data.message + '</div>';
            return;
        }

        // 显示物流公司信息
        infoDiv.innerHTML += '<div class="info-item"><strong>' + data.company + '</strong> 运单号: ' + data.number + '</div>';

        // 提取轨迹点坐标
        var lineArr = [];

        // 按时间顺序排序(确保最早的步骤在最前面)
        data.steps.sort(function(a, b) {
            return new Date(a.time) - new Date(b.time);
        });

        // 添加标记和轨迹线
        data.steps.forEach(function(step, index) {
            // 添加到轨迹线
            lineArr.push(step.location);

            // 创建标记
            var marker = new AMap.Marker({
                position: step.location,
                map: map,
                content: '<div style="background: #1E90FF; color: white; border-radius: 50%; width: 20px; height: 20px; text-align: center; line-height: 20px;">' + (index + 1) + '</div>',
                offset: new AMap.Pixel(-10, -10)
            });

            // 信息窗口内容
            var infoContent = '<div style="padding: 5px;">' +
                '<div style="font-weight: bold;">步骤 ' + (index + 1) + '</div>' +
                '<div>' + step.content + '</div>' +
                '<div style="color: #888; font-size: 12px;">' + step.time + '</div>' +
                '</div>';

            // 点击标记显示信息窗口
            marker.on('click', function() {
                new AMap.InfoWindow({
                    content: infoContent,
                    offset: new AMap.Pixel(0, -30)
                }).open(map, step.location);
            });

            markers.push(marker);

            // 添加物流信息到面板
            infoDiv.innerHTML += '<div class="info-item">' +
                '<div class="info-time">' + step.time + '</div>' +
                '<div class="info-content">' + step.content + '</div>' +
                '</div>';
        });

        // 绘制轨迹线
        polyline = new AMap.Polyline({
            path: lineArr,
            isOutline: true,
            outlineColor: '#ffeeff',
            borderWeight: 1,
            strokeColor: "#3366FF",
            strokeOpacity: 1,
            strokeWeight: 5,
            strokeStyle: "solid",
            lineJoin: 'round',
            lineCap: 'round',
            zIndex: 50
        });

        map.add(polyline);

        // 调整视图以适应轨迹
        map.setFitView(polyline);
    }

    // 查询按钮点击事件
    document.getElementById('queryBtn').addEventListener('click', function() {
        var orderNumber = document.getElementById('orderNumber').value.trim();
        if (!orderNumber) return;
        var logisticsData = getLogisticsData(orderNumber);
        showLogisticsTrack(logisticsData);
    });
</script>
</body>
</html>
相关推荐
摆烂工程师1 分钟前
快上车!教你白嫖ChatGPT Team的教程以及怎么取消和支付ChatGPT Team订阅的教程
前端·人工智能·后端
有梦想的攻城狮2 分钟前
从0开始学vue:vue3和vue2的关系
前端·javascript·vue.js·vue3·vue2
我家猫叫佩奇4 分钟前
🔥 React 模版版本升级 React19.0.0 ->19.1.0
前端·javascript·开源
CAD老兵4 分钟前
TypeScript 类型判断方法详解与比较
前端
LIUSAi1115 分钟前
使用gsap实现加载进度条功能
前端
yinke小琪5 分钟前
t06_vue在mac操作系统中热更新失效问题包括cli与vite
前端
不一样的少年_8 分钟前
🚨 别再乱用will-change了!前端翻车的"性能优化"陷阱
前端·浏览器
北京_宏哥10 分钟前
🔥《刚刚问世》系列初窥篇-Java+Playwright自动化测试-16- iframe操作-监听事件和执行js脚本 (详细教程)
java·前端·自动化运维
wordbaby10 分钟前
React 中 useDeferredValue 和 startTransition 的核心区别与使用场景
前端·react.js
zhfy啊12 分钟前
数组转哈希映射工具函数封装(toMap方法)
前端·typescript