vue3+pinia+ts+vite+腾讯地图实现一个输入两地名称获取路线图的功能

1,097 阅读4分钟

今天接到个需要需要计算两地之间的距离,算出要消耗多少东西,这个功能在微信小程序很好实现但是在web端没有现成的组件,只能自己一个个的去调,苦不堪言简直....,起初我是用的是axios来请求的腾讯api,axios弄好了我发布上线,发现有跨域,又跑到ng修改我们的跨域设置,设置完了好了之后想着松口气,没想到我们的服务没定位地址,服务器没有定位默认给的是北京,这显然不行,最后我是用的是jsonp请求,使用jsonp就没有跨域和当前用户定位的烦恼了,美滋滋。在写路况的时候发现他的路况图不会自己缩放自己的地图比例,让我好一顿找,最终发现了两点之间,显示在合适的层级的方法,相比较这一点高德确实不错啊,一步到位,可惜的就是有100km的限制。兄弟们看思路吧,先赞后看,江湖规矩哈

1.我们首先去腾讯控制台申请api的key,建立自己的应用 lbs.qq.com/dev/console…

2.我这个使用的webServiceApi,设置为授权IP,下面的输入框不要输入默认全部,或者输入自己本机的Ip

image.png

3.vue项目中index.html文件中引入自己的申请到的key,可参考官网api:lbs.qq.com/service/web…

<script charset="utf-8" src="https://map.qq.com/api/gljs?v=1.exp&key=自己申请的key"></script>

4.因为在ts项目中不识别引入的腾讯js我们要建立一个文件声明一下在文件外部建立一个TMap.d.ts文件

// 声明一下腾讯地图
declare global {
  const TMap: any;
}

//自己封装的腾讯地图api

// MapService.ts
// import axiosInstance from "./requset";
import { jsonp } from "vue-jsonp";
const baseUrl = "https://apis.map.qq.com/ws";
export interface MapData {
  // 定义腾讯地图接口返回的数据结构
  // 根据实际情况进行定义
  result: any;
  data: any;
  status: number;
}

export async function fetchMapData(params: {
  address: string;
  key: string;
}): Promise<MapData> {
  try {
    const response = await jsonp(baseUrl + "/location/v1/ip", {
      key: params.key,
      address: params.address,
      output: "jsonp",
    });
    // 处理接口响应数据
    return response;
  } catch (error: any) {
    // 处理请求错误
    throw new Error(error);
  }
}
export async function getLocation(params: {
  location: string;
  key: string;
  get_poi: number;
  poi_options: string;
}): Promise<MapData> {
  try {
    const response = await jsonp(baseUrl + "/geocoder/v1", {
      key: params.key,
      location: params.location,
      get_poi: 1,
      poi_options: params.poi_options,
      output: "jsonp",
    });
    // 处理接口响应数据
    return response;
  } catch (error: any) {
    // 处理请求错误
    throw new Error(error);
  }
}
export async function getSuggestion(params: {
  keyword: string;
  key: string;
}): Promise<MapData> {
  try {
    const response = await jsonp(baseUrl + "/place/v1/suggestion", {
      key: params.key,
      keyword: params.keyword,
      output: "jsonp",
    });
    // 处理接口响应数据
    return response;
  } catch (error: any) {
    // 处理请求错误
    throw new Error(error);
  }
}

export async function getGencoder(params: {
  address: string;
  key: string;
}): Promise<MapData> {
  try {
    const response = await jsonp(baseUrl + "/geocoder/v1", {
      key: params.key,
      address: params.address,
      output: "jsonp",
    });
    // 处理接口响应数据
    return response;
  } catch (error: any) {
    // 处理请求错误
    throw new Error(error);
  }
}

export async function getDriving(params: {
  from: string;
  key: string;
  to: string;
}): Promise<MapData> {
  try {
    const response = await jsonp(baseUrl + "/direction/v1/driving", {
      key: params.key,
      from: params.from,
      to: params.to,
      output: "jsonp",
    });
    // 处理接口响应数据
    return response;
  } catch (error: any) {
    // 处理请求错误
    throw new Error(error);
  }
}

5.创建一个地图

const dataMap: any = reactive({
      map: "",
      markerLayer: "",
      zoom: "10",
      latitude: "31.336843", //默认纬度
      lngitude: "121.493889", //默认经度
  });
const TMap = (window as any).TMap; // 声明TMap
// 生成地图
const init = () => {
      let center = new TMap.LatLng(dataMap.latitude, dataMap.lngitude);
      dataMap.map = new TMap.Map(document.getElementById("amp-container"), {
        center: center, //设置地图中心点坐标
        zoom: dataMap.zoom, //设置地图缩放级别
        viewMode: "2D",
        rotation: 20,
        pitch: 30,
      });
 };

6.获取当前地址

const currentLotion = async () => {
 try {
    let params = {
      key: "FMLBZ-IM2KH-ZL6D3-W6IND-RSK36-TPF3M", // 填申请到的腾讯key
      address: "上海",
    };
    let { result } = await fetchMapData(params);
    if (result) {
      console.log(result);
      // const loction = result.location.lat + "," + result.location.lng;

    }
  } catch (e) {
    console.log(e);
  }
}

7.获取附近的地址名称

const getLocationAddress = async (value: string) => {
  let params = {
    key: "FMLBZ-IM2KH-ZL6D3-W6IND-RSK36-TPF3M", // 填申请到的腾讯key
    location: value,
    get_poi: 1,
    poi_options: "policy=5",
  };
  let { result } = await getLocation(params);
  addressList.value = result.pois;
};

8.获取两地的距离以及路线图

const toDriving = async () => {
//这里面的值为pinia中存储的值,将你的重点坐标起点坐标放入
      let params = {
        from:
          storeData.startLoction.location.lat + 
          "," +
          storeData.startLoction.location.lng,
        to:
          storeData.endLocation.location.lat +
          "," +
          storeData.endLocation.location.lng,
        key: "FMLBZ-IM2KH-ZL6D3-W6IND-RSK36-TPF3M", // 填申请到的腾讯key
        get_speed: 1,
      };
      let { status, result } = await getDriving(params);

      if (status == 0) {
        distanceLine.value = result.routes[0].distance;
        // dataMap.zoom = calculateZoomLevel(result.routes[0].distance).toString();
        // reloadMap();
        var coors = result.routes[0].polyline,
          pl = [];
        //坐标解压(返回的点串坐标,通过前向差分进行压缩,因此需要解压)
        var kr = 1000000;
        for (var i = 2; i < coors.length; i++) {
          coors[i] = Number(coors[i - 2]) + Number(coors[i]) / kr;
        }
        //将解压后的坐标生成LatLng数组
        for (var i = 0; i < coors.length; i += 2) {
          pl.push(new TMap.LatLng(coors[i], coors[i + 1]));
        }
        new TMap.MultiPolyline({
          id: "polyline-layer", //图层唯一标识
          map: dataMap.map, //绘制到目标地图
          //折线样式定义
          styles: {
            style_blue: new TMap.PolylineStyle({
              color: "#3777FF", //线填充色
              width: 8, //折线宽度
              borderWidth: 5, //边线宽度
              borderColor: "#FFF", //边线颜色
              lineCap: "round", //线端头方式
            }),
          },
          //折线数据定义
          geometries: [
            {
              id: "pl_1", //折线唯一标识,删除时使用
              styleId: "style_blue", //绑定样式名
              paths: pl,
            },
          ],
        });
        showMarker();
      }
    };
    
    var bounds = new TMap.LatLngBounds();
    const showMarker = () => {
      markerLayer();
      markerArr.forEach(function (item) {
        //若坐标点不在范围内,扩大bounds范围
        if (bounds.isEmpty() || !bounds.contains(item.position)) {
          bounds.extend(item.position);
        }
      });

      //自适应设置地图可视范围
      dataMap.map?.fitBounds(bounds, {
        padding: 100, // 自适应边距
      });
    };

9.两地坐标位置展示

const markerArr = [
      {
        id: "marker1", //标记1
        styleId: "marker", //指定样式id
        position: new TMap.LatLng(
          storeData?.startLoction?.location?.lat || 39.984104,
          storeData?.startLoction?.location?.lng || 116.307503
        ), //点标记坐标位置
        src: "http://oss.cn-north-3.inspurcloudoss.com/eccloud/ce4d79a7cce849b3a512d9b51c2da9c0?",
      },
      {
        id: "marker2", //标记1
        styleId: "marker", //指定样式id
        src: "http://oss.cn-north-3.inspurcloudoss.com/eccloud/ce4d79a7cce849b3a512d9b51c2da9c0?",
        position: new TMap.LatLng(
          storeData?.endLocation?.location?.lat || 39.794104,
          storeData?.endLocation?.location?.lng || 116.287503
        ), //点标记坐标位置
      },
    ];
    // 标记地图
    const markerLayer = () => {
      dataMap.markerLayer = new TMap.MultiMarker({
        map: dataMap.map, //指定地图容器
        //样式定义
        styles: {
          myStyle: new TMap.MarkerStyle({
            width: 25,
            height: 35,
            anchor: { x: 16, y: 32 },
            src: "http://oss.cn-north-3.inspurcloudoss.com/eccloud/ce4d79a7cce849b3a512d9b51c2da9c0?",
          }),
        },
        //点标记数据数组

        geometries: markerArr,
      });
    };
    //监听两地位置变化重新生成路线图
     watchEffect(() => {
      if (storeData.startLoction.address && storeData.endLocation.address) {
        dataMap.map = null;
        toDriving();
      }
    });

效果展示:

db07b5520ed197f3bc180658e5897ec.jpg

9017b20e6f71f9f8f9c561510e869ed.jpg