You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ionic 3中如何利用Google Distance Matrix API计算分店距离与时长

我来帮你搞定这个需求!结合你的Ionic项目结构,我们可以分三步实现:先在Provider里封装Google Distance Matrix API的调用逻辑,然后在Branches页面获取用户当前位置并请求行程数据,最后把计算好的距离和时长渲染到页面上。具体代码和步骤如下:

解决方案:计算并展示分店距离与行程时长

1. 完善TravelDetailsProvider的API调用逻辑

把Google Distance Matrix API的请求逻辑封装在Provider里,方便页面调用和复用:

// travel-details.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { map } from 'rxjs/operators';

@Injectable()
export class TravelDetailsProvider {
  // 替换成你自己的Google Distance Matrix API密钥
  private apiKey = 'YOUR_GOOGLE_API_KEY';
  private apiUrl = 'https://maps.googleapis.com/maps/api/distancematrix/json';

  constructor(public http: HttpClient) {}

  /**
   * 获取当前位置到所有分店的行程详情
   * @param currentLat 当前位置纬度
   * @param currentLng 当前位置经度
   * @param branches 分店列表(每个分店需包含lat、lng属性)
   */
  getTravelDetails(currentLat: number, currentLng: number, branches: any[]) {
    // 拼接所有分店经纬度为API要求的格式:"lat1,lng1|lat2,lng2|..."
    const destinations = branches.map(branch => `${branch.lat},${branch.lng}`).join('|');
    const origins = `${currentLat},${currentLng}`;

    // 构建请求参数,支持driving/walking/bicycling/transit等出行模式
    const params = {
      origins,
      destinations,
      mode: 'driving',
      key: this.apiKey
    };

    return this.http.get(this.apiUrl, { params }).pipe(
      map((response: any) => {
        if (response.status !== 'OK') {
          throw new Error(`API请求失败:${response.status}`);
        }
        // 将行程数据与原分店数据合并
        return branches.map((branch, index) => {
          const element = response.rows[0].elements[index];
          return {
            ...branch,
            distance: element.distance, // 包含text(如"5 km")和value(米数)
            duration: element.duration  // 包含text(如"10 mins")和value(秒数)
          };
        });
      })
    );
  }
}

2. 在Branches页面集成数据获取逻辑

页面里先获取用户当前位置,再调用Provider获取行程数据:

// Branches.ts
import { Component } from '@angular/core';
import { IonicPage, NavController, LoadingController, Platform } from 'ionic-angular';
import { TravelDetailsProvider } from '../../providers/travel-details/travel-details';
import { Geolocation } from '@ionic-native/geolocation';
import { ToastController } from 'ionic-angular';

@IonicPage()
@Component({
  selector: 'page-branches',
  templateUrl: 'branches.html',
})
export class BranchesPage {
  // 替换成你的原始分店列表(需包含lat、lng属性)
  branches: any[] = [
    { name: '分店A', address: 'XX路XX号', lat: 31.2304, lng: 121.4737 },
    { name: '分店B', address: 'YY路YY号', lat: 31.2165, lng: 121.4365 }
  ];
  branchesWithTravelDetails: any[] = [];
  isLoading = false;

  constructor(
    public navCtrl: NavController,
    private travelDetailsProvider: TravelDetailsProvider,
    private geolocation: Geolocation,
    private loadingCtrl: LoadingController,
    private platform: Platform,
    private toastCtrl: ToastController
  ) {}

  ionViewDidEnter() {
    this.loadTravelDetails();
  }

  async loadTravelDetails(refresher?: any) {
    this.isLoading = true;
    const loader = this.loadingCtrl.create({ content: '正在计算距离...' });
    await loader.present();

    try {
      // 等待平台就绪后获取当前位置
      await this.platform.ready();
      const position = await this.geolocation.getCurrentPosition({
        enableHighAccuracy: true,
        timeout: 10000
      });

      // 调用Provider获取行程数据
      this.travelDetailsProvider.getTravelDetails(
        position.coords.latitude,
        position.coords.longitude,
        this.branches
      ).subscribe(
        (data) => {
          this.branchesWithTravelDetails = data;
          loader.dismiss();
          this.isLoading = false;
          refresher?.complete();
        },
        (error) => {
          this.showToast('获取行程信息失败,请稍后重试');
          console.error('API请求错误:', error);
          loader.dismiss();
          this.isLoading = false;
          refresher?.complete();
        }
      );
    } catch (error) {
      this.showToast('无法获取当前位置,请检查权限设置');
      console.error('位置获取错误:', error);
      loader.dismiss();
      this.isLoading = false;
      refresher?.complete();
    }
  }

  private showToast(message: string) {
    const toast = this.toastCtrl.create({
      message,
      duration: 2000,
      position: 'bottom'
    });
    toast.present();
  }
}

3. 模板渲染距离与时长

在Branches页面的HTML模板里,把行程数据渲染出来:

<!-- branches.html -->
<ion-header>
  <ion-navbar>
    <ion-title>分店列表</ion-title>
  </ion-navbar>
</ion-header>

<ion-content>
  <!-- 下拉刷新 -->
  <ion-refresher (ionRefresh)="loadTravelDetails($event)">
    <ion-refresher-content></ion-refresher-content>
  </ion-refresher>

  <!-- 加载状态 -->
  <div *ngIf="isLoading" class="loading-wrap">
    <ion-spinner></ion-spinner>
    <p>正在计算距离...</p>
  </div>

  <!-- 分店列表 -->
  <ion-list *ngIf="!isLoading && branchesWithTravelDetails.length > 0">
    <ion-item *ngFor="let branch of branchesWithTravelDetails">
      <h2>{{branch.name}}</h2>
      <p>{{branch.address}}</p>
      <ion-note item-end>
        <p>距离: {{branch.distance?.text}}</p>
        <p>预计时长: {{branch.duration?.text}}</p>
      </ion-note>
    </ion-item>
  </ion-list>

  <!-- 空状态 -->
  <div *ngIf="!isLoading && branchesWithTravelDetails.length === 0" class="empty-wrap">
    <p>暂无分店数据</p>
  </div>
</ion-content>

关键注意事项

  • API密钥配置:一定要替换代码中的YOUR_GOOGLE_API_KEY为你在Google Cloud平台申请的Distance Matrix API密钥,并确保该API已启用,同时配置好使用限制(如HTTP referrers)保障安全。
  • 位置权限:需在项目config.xml中添加位置权限配置:
    <plugin name="cordova-plugin-geolocation" spec="^4.1.0" />
    
  • 计费说明:Google Distance Matrix API为付费服务,记得在Google Cloud平台监控使用量,避免超出预算。

内容的提问来源于stack exchange,提问作者user538578964

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:57:50