鸿蒙开发-车轮家的地图服务:驻车地标记与设施查询

4 阅读3分钟

车轮家的地图服务:驻车地标记与设施查询

如果你是房车旅行爱好者,推荐去鸿蒙应用市场搜一下**「车轮家」**,下载体验体验。标记驻车点、查询设施配套、记录行程,一套走下来对房车旅行的规划会更完善。体验完再回来看这篇文章,你会更清楚驻车地标记和设施查询背后是怎么实现的。


写在前面

大家好,我是一名写了十多年Web前端的老兵。从jQuery时代一路走到React/Vue,CSS3动画、requestAnimationFrame、Web Animation API这些都算是看家本领。去年开始转战鸿蒙生态,用ArkTS开发App,这一路踩了不少坑,也积累了不少心得。

很多人觉得"前端转鸿蒙"应该很容易——都是写UI嘛,组件化、状态管理、生命周期,概念都差不多。但真正上手之后你会发现,相似的地方让你觉得亲切,不同的地方让你抓狂

比如:

  • 地图服务:Web用高德/百度地图JS API,鸿蒙用@ohos.geoLocationManager和地图组件。
  • 定位服务:Web用navigator.geolocation,鸿蒙用@ohos.geoLocationManager
  • 数据存储:Web的localStorage到了ArkTS变成了@ohos.data.preferences

接下来这篇文章,我会用"车轮家"的实际开发经历,带你看看驻车地标记、设施查询、行程记录的实现。


这篇文章聊什么

车轮家的地图服务功能,核心要解决三个问题:

  1. 驻车地标记:标记和收藏驻车点
  2. 设施查询:查询驻车点的设施配套
  3. 行程记录:记录房车旅行的行程

第一步:驻车点数据结构

interface ParkingSpot {
  id: string;
  name: string;
  latitude: number;
  longitude: number;
  address: string;
  facilities: string[];  // 设施列表
  rating: number;        // 评分
  notes: string;
  isFavorite: boolean;
  createdAt: number;
}

const FACILITY_TYPES = [
  { id: 'water', name: '水源', icon: '💧' },
  { id: 'electricity', name: '电源', icon: '🔌' },
  { id: 'toilet', name: '厕所', icon: '🚽' },
  { id: 'shower', name: '淋浴', icon: '🚿' },
  { id: 'laundry', name: '洗衣', icon: '👕' },
  { id: 'dump', name: '排污', icon: '♻️' },
  { id: 'wifi', name: 'WiFi', icon: '📶' },
  { id: 'grocery', name: '超市', icon: '🛒' },
  { id: 'restaurant', name: '餐厅', icon: '🍽️' },
  { id: 'gas', name: '加油站', icon: '⛽' }
];

第二步:驻车点列表

@Entry
@Component
struct ParkingListPage {
  @State spots: ParkingSpot[] = []
  @State filterFacility: string = 'all'
  @State showFavoritesOnly: boolean = false

  get filteredSpots(): ParkingSpot[] {
    let filtered = this.spots;

    if (this.showFavoritesOnly) {
      filtered = filtered.filter(s => s.isFavorite);
    }

    if (this.filterFacility !== 'all') {
      filtered = filtered.filter(s => s.facilities.includes(this.filterFacility));
    }

    return filtered;
  }

  build() {
    Column() {
      // 筛选条件
      Row() {
        Toggle({ type: ToggleType.Checkbox, isOn: this.showFavoritesOnly })
          .onChange((isOn: boolean) => { this.showFavoritesOnly = isOn })
        Text('只看收藏')
          .fontSize(14)
          .margin({ left: 8 })
      }
      .width('100%')
        .margin({ bottom: 12 })

      // 设施筛选
      Flex({ wrap: FlexWrap.Wrap }) {
        ForEach(FACILITY_TYPES, (facility) => {
          Text(`${facility.icon} ${facility.name}`)
            .fontSize(12)
            .padding(6)
            .margin(4)
            .borderRadius(6)
            .backgroundColor(this.filterFacility === facility.id ? '#3B82F6' : '#374151')
            .onClick(() => { this.filterFacility = facility.id })
        })
      }
      .margin({ bottom: 12 })

      // 驻车点列表
      List({ space: 12 }) {
        ForEach(this.filteredSpots, (spot: ParkingSpot) => {
          ListItem() {
            Column() {
              Row() {
                Text(spot.name)
                  .fontSize(16)
                  .fontWeight(FontWeight.Bold)
                  .layoutWeight(1)
                Text(spot.isFavorite ? '⭐' : '☆')
                  .fontSize(20)
                  .onClick(() => this.toggleFavorite(spot.id))
              }
              .width('100%')

              Text(spot.address)
                .fontSize(13)
                .fontColor('#9CA3AF')
                .margin({ top: 4 })

              // 设施标签
              Flex({ wrap: FlexWrap.Wrap }) {
                ForEach(spot.facilities, (facilityId: string) => {
                  const facility = FACILITY_TYPES.find(f => f.id === facilityId);
                  if (facility) {
                    Text(`${facility.icon}`)
                      .fontSize(16)
                      .margin(4)
                  }
                })
              }
              .margin({ top: 8 })
            }
            .width('100%')
            .padding(12)
            .backgroundColor('#1F2937')
            .borderRadius(12)
          }
        })
      }
      .layoutWeight(1)

      Button('添加驻车点')
        .onClick(() => {
          router.pushUrl({ url: 'pages/AddParking' });
        })
        .width('100%')
        .backgroundColor('#3B82F6')
    }
    .width('100%')
    .height('100%')
    .padding(16)
    .backgroundColor('#111827')
  }

  async toggleFavorite(id: string) {
    const spot = this.spots.find(s => s.id === id);
    if (spot) {
      spot.isFavorite = !spot.isFavorite;
      const store = await preferences.getPreferences(getContext(), 'chelunjia_data');
      await store.set('spots', JSON.stringify(this.spots));
      await store.flush();
    }
  }
}

第三步:行程记录

interface TripRecord {
  id: string;
  startDate: string;
  endDate: string;
  startLocation: string;
  endLocation: string;
  distance: number;      // 公里
  fuelUsed: number;      // 升
  fuelCost: number;      // 元
  parkingSpots: string[]; // 驻车点ID列表
  notes: string;
}

总结

这篇文章围绕"车轮家"的地图服务功能,讲解了三个核心主题:

  1. 驻车地标记:驻车点的CRUD操作和收藏管理
  2. 设施查询:按设施类型筛选驻车点
  3. 行程记录:房车旅行的行程管理

驻车点管理的核心是数据过滤——根据收藏状态和设施类型筛选。


如果你是房车旅行爱好者,希望这篇文章能帮你理解车轮家背后的管理逻辑。去鸿蒙应用市场下载体验一下吧,有问题欢迎交流。