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

news/2025/3/10 17:42:15/

目录

  • 引言
  • 1 搭建布局
  • 2 创建变量
  • 3 初始化站点
  • 4 点选站点时联动
  • 5 数据绑定
  • 最终效果
  • 完整代码
  • 总结

引言

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

1 搭建布局

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

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

每一行都可以用一个普通容器进行占位,具体结构如下
在这里插入图片描述
第一个普通容器里边放置三个文本组件,用来显示站点名称、营业状态和更多网点
在这里插入图片描述
组件默认是垂直排列的,为了让他在一行显示,可以设置普通容器的样式,设置为横向排列
在这里插入图片描述
第一个文本我们用来显示站点名称,设置文本的样式为加粗
在这里插入图片描述
第二个文本显示营业状态,设置一个淡绿色的背景色
在这里插入图片描述
将文本颜色设置为绿色
在这里插入图片描述
设置字号和内边距
在这里插入图片描述
再设置一点圆角
在这里插入图片描述
设置第三个文本的边框,设置为红色
在这里插入图片描述
文本颜色也设置为红色

第二个普通容器,放置文本和两个图标组件
在这里插入图片描述
将两个图标组件又放到普通容器里边是为了实现两端对齐的效果,外层普通容器设置对齐方式为端对齐
在这里插入图片描述

2 创建变量

布局搭建好了之后,就需要定义变量用来绑定数据。先创建一个文本变量,定义为stationName,用来获取地图点选的站点名称
在这里插入图片描述
然后创建一个内置表查询变量,用来根据站点名称查询站点信息
在这里插入图片描述
查询条件设置为站点名称等于我们的stationName
在这里插入图片描述

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.nameawait $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 数据绑定

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

先绑定站点名称
在这里插入图片描述
接着绑定营业状态
在这里插入图片描述
接着绑定营业地址
在这里插入图片描述
电话的图标,我们可以设置点击事件,方法选择拨打电话
在这里插入图片描述
在这里插入图片描述
绑定为站点的电话字段
在这里插入图片描述
导航图标绑定地图导航方法
在这里插入图片描述
绑定站点的经纬度
在这里插入图片描述

最终效果

地图加载完毕后会显示最近的站点,当点击站点的时候信息会重新切换
在这里插入图片描述

完整代码

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.nameawait $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 }}><selectvalue={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><divref={mapContainerRef}style={{position: "relative",width: "100%",height: "500px",marginTop: "0px",...style,}}/></div>);
}

总结

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


http://www.ppmy.cn/news/1578138.html

相关文章

FusionInsight MRS云原生数据湖

FusionInsight MRS云原生数据湖 1、FusionInsight MRS概述2、FusionInsight MRS解决方案3、FusionInsight MRS优势4、FusionInsight MRS功能 1、FusionInsight MRS概述 1.1、数据湖概述 数据湖是一个集中式存储库&#xff0c;允许以任意规模存储所有结构化和非结构化数据。可以…

elk的相关的基础

以下是关于ELK&#xff08;Elasticsearch, Logstash, Kibana&#xff09;的200个基础问题及其答案&#xff0c;涵盖了ELK的核心概念、组件、配置、使用场景、优化等方面。 ​Elasticsearch 基础 ​**什么是Elasticsearch&#xff1f;**​ 答&#xff1a;Elasticsearch是一个分…

25.3.7#Git命令#merge和rebase的区别

1 Git命令大全 git init # 初始化本地git仓库&#xff08;创建新仓库&#xff09; git config --global user.name "xxx" # 配置全局用户名 git config --global user.email "xxxxxx.…

手机屏幕摔不显示了,如何用其他屏幕临时显示,用来导出资料或者清理手机

首先准备一个拓展坞 然后 插入一个外接的U盘 插入鼠标 插入有数字小键盘区的键盘 然后准备一根高清线&#xff0c;一端链接电脑显示器,一端插入拓展坞 把拓展坞的连接线&#xff0c;插入手机充电口&#xff08;可能会需要转接头&#xff09; 然后确保手机开机 按下键盘…

WebSocket(WS)协议系列(三)加密

平时看到两种形式&#xff1a;ws 和 wss。他们有什么联系吗&#xff1f; ws 和 wss 都是 WebSocket 协议的两种形式&#xff0c;它们分别代表了不同的传输层协议。它们之间的主要区别在于加密和安全性。 ws: WebSocket 协议 ws 代表 WebSocket 协议&#xff08;不加密的&…

小迪安全-27-php开发,tp框架,路由访问,对象操作,内置过滤,核心漏洞

下载一个thinkphp的框架 thinkphp就是一个mvc架构 5.0.2即可 绑定一下域名到 就可以访问了 而输出的地方在这里 而这种框架有使用手册和规范操作&#xff0c;代码写法也跟原生不一样&#xff0c;例如数据库配置 只需要在这里输入好即可&#xff0c;都不用自己再去写链接 这是…

Vue项目通过内嵌iframe访问另一个vue页面,获取token适配后端鉴权(以内嵌若依项目举例)

1. 改造子Vue项目进行适配(ruoyi举例) (1) 在路由文件添加需要被外链的vue页面配置 // 若依项目的话是 router/index.js文件 {path: /contrast,component: () > import(/views/contrast/index),hidden: true },(2) 开放白名单 // 若依项目的话是 permission.js 文件 cons…

deepseek在pycharm中的配置和简单应用

对于最常用的调试python脚本开发环境pycharm&#xff0c;如何接入deepseek是我们窥探ai代码编写的第一步&#xff0c;熟悉起来总没坏处。 1、官网安装pycharm社区版&#xff08;免费&#xff09;&#xff0c;如果需要安装专业版&#xff0c;需要另外找破解码。 2、安装Ollama…