目录

加油站小程序实战教程09显示站点信息

加油站小程序实战教程09显示站点信息

引言

在《加油站小程序实战教程08动态获取城市和站点信息》中,我们已经介绍了如何动态的读取城市及站点信息显示到地图上。站点信息读取到后,如果在地图点选站点信息的时候,需要在地图的下方显示站点的详细信息,本篇我们介绍一下具体的实现过程。

1 搭建布局

要显示详情信息,需要先用布局组件搭建布局。通常我们是使用普通容器、文本、图标几个布局组件来搭建页面。

在JSX组件下边先添加普通容器,整体内容是分为两行,第一行显示站点的名称、营业状态、更多网点。第二行显示站点的地址,有两个图标,一个可以拨打电话,一个可以导航

每一行都可以用一个普通容器进行占位,具体结构如下

https://i-blog.csdnimg.cn/direct/29d6829998454e3ba8528976d0251873.png

第一个普通容器里边放置三个文本组件,用来显示站点名称、营业状态和更多网点

https://i-blog.csdnimg.cn/direct/73e35e53e93f4c909fae63efce577f21.png

组件默认是垂直排列的,为了让他在一行显示,可以设置普通容器的样式,设置为横向排列

https://i-blog.csdnimg.cn/direct/312a65afe6bb433aa7718943ffcd8ce3.png

第一个文本我们用来显示站点名称,设置文本的样式为加粗

https://i-blog.csdnimg.cn/direct/2a3fc3b083df4c039335813562df8ca0.png

第二个文本显示营业状态,设置一个淡绿色的背景色

https://i-blog.csdnimg.cn/direct/f511c670c2e844c8ad0482ce0ee1ea42.png

将文本颜色设置为绿色

https://i-blog.csdnimg.cn/direct/bec7663ad9c243499e956ef3d6df1195.png

设置字号和内边距

https://i-blog.csdnimg.cn/direct/701d3e9753d14ad3a88860fd6d38856c.png

再设置一点圆角

https://i-blog.csdnimg.cn/direct/115b2617a34a4ad987eb79beb55f8f71.png

第二个普通容器,放置文本和两个图标组件

https://i-blog.csdnimg.cn/direct/7d72050e9f8442298accf5d9788c88ce.png

将两个图标组件又放到普通容器里边是为了实现两端对齐的效果,外层普通容器设置对齐方式为端对齐

https://i-blog.csdnimg.cn/direct/7265235164754446a8b744827d8d5b13.png

2 创建变量

布局搭建好了之后,就需要定义变量用来绑定数据。先创建一个文本变量,定义为stationName,用来获取地图点选的站点名称

https://i-blog.csdnimg.cn/direct/5ee8d54dc74f4195a3227381ca0d215c.png

然后创建一个内置表查询变量,用来根据站点名称查询站点信息

https://i-blog.csdnimg.cn/direct/61aedebfce054e6483f234a1c6baf879.png

查询条件设置为站点名称等于我们的stationName

https://i-blog.csdnimg.cn/direct/7aa81343c8be4940a21c78076fe48a25.png

3 初始化站点

当地图加载完毕后,我们会进行距离计算,将最近的站点的名称赋值给我们的stationName

const calculateNearestStation =async (stations) => {
        let nearest = null;
        let minDistance = Infinity;

        stations.forEach((station) => {
            const distance = calculateDistance(userLocation, station.location);
            if (distance < minDistance) {
                minDistance = distance;
                nearest = station;
            }
        });
        $w.page.dataset.state.stationName = nearest.name
        await $w.staion.trigger()
        setNearestStation(nearest);
    };

在计算最近距离站点的方法里我们添加了赋值语句,这样就得到了站点信息,内置表查询需要调用trigger方法才可以获取到值

4 点选站点时联动

除了初始化需要显示站点详情外,当在地图点选站点的时候也要进行联动,找到点选的方法,给站点名称进行赋值

marker.on("click", async () => {
                infoWindow.open(mapInstance, marker.getPosition());
                // 更新站点名称并触发事件
            $w.page.dataset.state.stationName = station.name;
            await $w.staion.trigger();
            });

5 数据绑定

完成了点选和初始化工作后,我们现在就已经得到了站点的数据,就需要给文本组件绑定一下文本内容,从变量里依次绑定

先绑定站点名称

https://i-blog.csdnimg.cn/direct/a06bd5b88d654927ae8d5c6e571bd0e6.png

接着绑定营业状态

https://i-blog.csdnimg.cn/direct/0bd7792831904a99987ad29837decf22.png

接着绑定营业地址

https://i-blog.csdnimg.cn/direct/460140b173b04bdf949f0a43e8e280d4.png

电话的图标,我们可以设置点击事件,方法选择拨打电话

https://i-blog.csdnimg.cn/direct/a01639036b9c42099a573630be3b491d.png

https://i-blog.csdnimg.cn/direct/3212b738cb1047cfad57e538bc1325e5.png

绑定为站点的电话字段

https://i-blog.csdnimg.cn/direct/da0c5edd4d344486b23b21da1ef48910.png

导航图标绑定地图导航方法

https://i-blog.csdnimg.cn/direct/b4e95787effa4783930264f367a4708e.png

绑定站点的经纬度

https://i-blog.csdnimg.cn/direct/5e75d90e9546449b9be7ec6e478be2f6.png

最终效果

地图加载完毕后会显示最近的站点,当点击站点的时候信息会重新切换

https://i-blog.csdnimg.cn/direct/178fbde5f4394e8992789e0d0c38a19d.png

完整代码

import React, { useRef, useEffect, useState } from "react";

export default function CitySwitcherMap(props) {
    const { style } = props;
    const mapContainerRef = useRef(null);
    const [selectedCity, setSelectedCity] = useState("");
    const [defaultCityLocation, setDefaultCityLocation] = useState([116.397428, 39.90923]); // 默认北京
    const [mapInstance, setMapInstance] = useState(null);
    const [userLocation, setUserLocation] = useState([116.397428, 39.90923]); // 默认用户位置为北京
    const [nearestStation, setNearestStation] = useState(null);
    const [cities, setCities] = useState([]); // 存储城市数据

    useEffect(() => {
        // 模拟触发 API 并获取数据
        const fetchCityStations = async () => {
            try {
                // 调用你的 API 获取城市数据
                const result = await $w.getCityStation.trigger();
                console.log("城市数据",result)
                if (result) {
                    setCities(result); // 更新城市数据
                } else {
                    console.error("获取城市数据失败");
                }
            } catch (error) {
                console.error("API 调用失败", error);
            }
        };

        fetchCityStations();
    }, []); // 只在组件加载时触发一次

    useEffect(() => {
        const loadAMap = async () => {
            if (!window.AMap) {
                const script = document.createElement("script");
                script.src = "https://webapi.amap.com/maps?v=2.0&key=6bd36e95532ee2800d841762601420f5";
                script.async = true;
                script.onload = () => {
                    initMap();
                };
                document.body.appendChild(script);
            } else {
                initMap();
            }
        };

        const initMap = () => {
            if (window.AMap) {
                const map = new window.AMap.Map(mapContainerRef.current, {
                    center: defaultCityLocation,
                    zoom: 12,
                    mapStyle: "amap://styles/normal",
                });
                setMapInstance(map);
            }
        };

        loadAMap();
    }, []);

    useEffect(() => {
        if (mapInstance) {
            const selectedCityData = cities.find((city) => city.name === selectedCity);
            if (selectedCityData) {
                mapInstance.setCenter(selectedCityData.location);
                addMarkers(selectedCityData.stations);
                calculateNearestStation(selectedCityData.stations);
            }
        }
    }, [selectedCity, mapInstance, cities]);

    const addMarkers = (stations) => {
        mapInstance.clearMap();

        stations.forEach((station) => {
            const marker = new window.AMap.Marker({
                position: station.location,
                map: mapInstance,
            });

            const distance = calculateDistance(userLocation, station.location);

            const infoWindow = new window.AMap.InfoWindow({
                content: `<div style="padding: 10px; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
                             <div><strong>${station.name}</strong></div>
                             <div style="color: #666;">距当前站点 ${distance.toFixed(1)} km</div>
                          </div>`,
                offset: new window.AMap.Pixel(0, -40), // 调整偏移,避免遮挡标记
            });

            marker.on("click", async () => {
                infoWindow.open(mapInstance, marker.getPosition());
                // 更新站点名称并触发事件
            $w.page.dataset.state.stationName = station.name;
            await $w.staion.trigger();
            });

            if (nearestStation && nearestStation.name === station.name) {
                infoWindow.open(mapInstance, marker.getPosition());
            }
        });
    };

    const calculateNearestStation =async (stations) => {
        let nearest = null;
        let minDistance = Infinity;

        stations.forEach((station) => {
            const distance = calculateDistance(userLocation, station.location);
            if (distance < minDistance) {
                minDistance = distance;
                nearest = station;
            }
        });
        $w.page.dataset.state.stationName = nearest.name
        await $w.staion.trigger()
        setNearestStation(nearest);
    };

    const calculateDistance = (start, end) => {
        const startLngLat = new window.AMap.LngLat(start[0], start[1]);
        const endLngLat = new window.AMap.LngLat(end[0], end[1]);
        return startLngLat.distance(endLngLat) / 1000; // 返回公里数
    };

    const getUserLocation = () => {
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(
                (position) => {
                    const { latitude, longitude } = position.coords;
                    setUserLocation([longitude, latitude]);
                    fetchCityNameFromCoords(longitude, latitude);
                },
                () => {
                    setUserLocation([111.75199, 40.84211]); // 呼和浩特
                    setSelectedCity("呼和浩特市");
                }
            );
        }
    };

    const fetchCityNameFromCoords = async (lng, lat) => {
        try {
            const response = await fetch(
                `https://restapi.amap.com/v3/geocode/regeo?key=154efad008972a03ecac218a844959a9&location=${lng},${lat}`
            );
            const data = await response.json();
            if (data.status === "1" && data.regeocode) {
                const cityName = data.regeocode.addressComponent.city || data.regeocode.addressComponent.province;
                setSelectedCity(cityName);
            }
        } catch {
            console.error("获取城市名称失败");
        }
    };

    useEffect(() => {
        getUserLocation();
    }, []);

    return (
        <div>
            <div style={{ marginBottom: "10px", zIndex: 999 }}>
                <select
                    value={selectedCity}
                    onChange={(e) => setSelectedCity(e.target.value)}
                    style={{
                        padding: "8px",
                        fontSize: "14px",
                        borderRadius: "4px",
                        border: "1px solid #ccc",
                    }}
                >
                    <option value="">请选择城市</option>
                    {cities.map((city) => (
                        <option key={city.name} value={city.name}>
                            {city.name}
                        </option>
                    ))}
                </select>
            </div>

            <div
                ref={mapContainerRef}
                style={{
                    position: "relative",
                    width: "100%",
                    height: "500px",
                    marginTop: "0px",
                    ...style,
                }}
            />
        </div>
    );
}

总结

本篇我们介绍了站点详情的展示,需要理解变量的作用,如何在地图组件中重新更新变量的内容。页面布局的搭建,以及变量绑定的方法。