当前位置: 首页 > 工具软件 > RenderJS > 使用案例 >

uniapp vue renderjs 高德地图

甄正信
2023-12-01

前情提要:uniapp自带的 map 标签实在是不好用(也可能是笔者不懂…-_-||),因此最终选择的方案,还是H5方式的高德地图。但是呢,在app端又识别不了跟dom相关的对象的,后根据文档说明,使用renderjs解决H5渲染地图的问题。

代码

<!--
 * @Description: js方式的高德基础地图底图
 * @Author: 
 * @Date: 
 * @LastEditors: 
 * @LastEditTime: 
-->
<template>
  <view
    id="mapContainer"
    class="relative w-full h-full"
    :init-map="initMap"
    :change:init-map="AMapInstance.initAmap"
    :markers-prop="markers"
    :change:markers-prop="AMapInstance.drawPoint"
    :center="center"
    :change:center="AMapInstance.setCenter"
    :location-prop="location"
    :change:location-prop="AMapInstance.setLocation"
    :zoom-prop="zoom"
    :change:zoom-prop="AMapInstance.setZoom"
  />
</template>
<script>
export default {
  props: {
    markers: {
      type: Object,
      default: () => ({}),
    },
    center: { // 中心点坐标
      type: Array,
      default: () => [],
    },
    location: { // 定位坐标
      type: Array,
      default: () => [],
    },
    mapCover: {
      type: Array,
      default: () => [],
    },
    zoom: {
      type: Number,
      default: 10,
    },
  },
  data() {
    return {
      initMap: true,
      direction: 0,
    };
  },
  watch: { },
  mounted() {
    // 罗盘
    uni.onCompassChange(function (res) {
      // console.log(`罗盘${res.direction}`);
      this.direction = res.direction;
    });
  },
  methods: {
    mapLoaded() {
      this.$emit('mapLoaded', true);
    },
    showMarkerDetail(item) {
      this.$emit('clickMarkDetail', item);
    },
  },
};
</script>

<script module="AMapInstance" lang="renderjs">
// renderjs运行在视图层的js,只支持app-vue和h5(简单来说就是开了另外一条线程)
// 大幅降低逻辑层和视图层的通讯损耗,提供高性能视图交互能力(减少通讯损耗提升性能,例如一些手势或canvas动画的场景
export default {
  data() {
    return {
      amap: null,
      infoWindow: null,
      overlayGroups: null, // 覆盖物群组
      markersAll: [], // 点集合组
      cacheMarkers: {},
      projectLineData: [],
      longitude: 104.07275,
      latitude: 30.57899,
      ImgDiseaseBlue0: 'static/images/map/disease-blue-0.png',
      ImgDiseaseBlue1: 'static/images/map/disease-blue-1.png',
      ImgDiseaseCyan0: 'static/images/map/disease-cyan-0.png',
      ImgDiseaseCyan1: 'static/images/map/disease-cyan-1.png',
      ImgDiseaseOrange0: 'static/images/map/disease-orange-0.png',
      ImgDiseaseOrange1: 'static/images/map/disease-orange-1.png',
      ImgLocation: 'static/images/map/location.png',
    };
  },
  mounted() {
	if (window && window.AMap) {
      this.initAmap();
    } else {
      window._AMapSecurityConfig = {
        securityJsCode: '***',
      };
      const script = document.createElement('script');
      script.src = 'https://webapi.amap.com/maps?v=1.4.8&key=***&plugin=AMap.ControlBar';
      script.onload = () => {
        this.initAmap()
      };
      document.head.appendChild(script);
    }
  },
  methods: {
    initAmap(newValue, oldValue, ownerVm, vm) {    
       this.amap = new AMap.Map('mapContainer', {
         zoom: 10, // 显示的缩放级别
         // zooms: [2, 30], //地图显示的缩放级别范围, 默认为 [2, 20] ,取值范围 [2 ~ 30]
         center: [this.longitude, this.latitude], // todo 中心点坐标
         mapStyle: 'amap://styles/57994c871bb604a4c79184f5f65d8782', // todo 地图样式
         resizeEnable: true, // 是否监控地图容器尺寸变化
       });
       ownerVm.callMethod('mapLoaded', true)
		// 获取点击点
       var markers = [];
       this.amap.on('click', (e) => {
           this.amap.remove(markers);
           this.pointerMaker = new AMap.Marker({
               icon: "https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png",
               position: new AMap.LngLat(e.lnglat.getLng(), e.lnglat.getLat()),
               //anchor:'bottom-center',
               offset: new AMap.Pixel(-9, -31),
           });
           this.amap.add(this.pointerMaker);
           this.pointerLonLat = [e.lnglat.getLng(), e.lnglat.getLat()];
           // 真机中,在renderjs中识别不了常规的this对象,因此相关的api不可用了,只能兼容着写了
           // #ifdef H5
           this.$uniStorage.set('A_MAP_POINTER_LONLAT', { lonLat: this.pointerLonLat });
           //#endif

           // #ifdef APP-PLUS || APP-PLUS-NVUE
           ownerVm.callMethod('setPinter', { lonLat: this.pointerLonLat })
           //#endif

           markers.push(this.pointerMaker);
       });
	  // 动态设置css,去掉高德的logo(奇怪的是,其他组件或页面不需要加这个,只有首页需要...)PS:按需,是否加以下代码
      const style = document.createElement('style');
      style.type = 'text/css';
      style.innerHTML = '.amap-logo {opacity: 0 !important; display: none !important;z-index: -99999999 !important;}';
      document.head.appendChild(style);
   },
    setCenter(newValue, oldValue, ownerVm, vm) {
      if (!this.amap) return;
      if(!newValue || newValue.length === 0) return;
      const position = new AMap.LngLat(newValue[0], newValue[1]);  // 标准写法
      // 简写 var position = [116, 39];
      this.amap&&this.amap.setCenter(position);
    },
    // 定位
    setLocation(newValue, oldValue, ownerVm, vm) {
      if(!newValue || newValue.length === 0) return;
      const position = new AMap.LngLat(newValue[0], newValue[1]);  // 标准写法
      // 简写 var position = [116, 39];
      this.amap.setCenter(position);
      const wh = this.getWH(68, 56, 32);
      const mark = new AMap.Marker({
          position: position,
          icon: new AMap.Icon({ image: this.ImgLocation, size: new AMap.Size(wh[0], wh[1]), imageSize: new AMap.Size(wh[0], wh[1]) }),
          offset: new AMap.Pixel(-wh[0] / 2, -wh[1]),
          autoRotation: true,
          angle: 180
      });

      this.amap.add(mark)
    },
    // 设置缩放等级
    setZoom(level) {
      if (!this.amap) return;
      this.amap.setZoom(level || 12);
    },
    // 清除所有marker点位
    clearMarkerPoints() {
      if (!this.amap) return;
      this.markersAll = [];
      if (this.overlayGroups) {
        this.amap.remove(this.overlayGroups);
        this.overlayGroups = null;
      }
    },
    // 画圆形
    drawCircle(coors){
      if (!this.amap) return;
      this.clearCircle()
      const circle = new AMap.Circle({
        center: coors || [116.433322, 39.900255],
        radius: 1000, // 半径
        borderWeight: 3,
        strokeColor: '#FF33FF',
        strokeWeight: 6,
        strokeOpacity: 0.2,
        fillOpacity: 0.4,
        strokeStyle: 'dashed',
        strokeDasharray: [10, 10],
        // 线样式还支持 'dashed'
        fillColor: '#1791fc',
        zIndex: 50
      });
      this.circleGroups = circle;
      this.amap.add(circle);
    },
    // 画点
    drawPoint(newValue, oldValue, ownerVm, vm) {
      this.clearMarkerPoints()
      if (!newValue || !newValue.data) return;
      if (!this.amap) return;
      this.cacheMarkers = newValue;
      const data = newValue.data;
      const type = newValue.type;
      if (type === '0') {
        if (!data.length) return;
        const markers = data.map((item) => {
          let iconImgD = this.ImgDiseaseOrange1;
          let iconImgA = this.ImgDiseaseOrange0;
          if (item.type === 1) {
            iconImgD = this.ImgDiseaseBlue1;
            iconImgA = this.ImgDiseaseBlue0;
          } else if (item.type === 2) {
            iconImgD = this.ImgDiseaseCyan1;
            iconImgA = this.ImgDiseaseCyan0;
          }

          const wh = this.getWH(64, 90, 30);
          const marker = new AMap.Marker({
            position: new AMap.LngLat(item.position[0], item.position[1]),
            icon: new AMap.Icon({ image: iconImgD, size: new AMap.Size(wh[0], wh[1]), imageSize: new AMap.Size(wh[0], wh[1]) }),
            extData: item,
            offset: new AMap.Pixel(-wh[0] / 2, -wh[1]),
          });
          marker.on('click', (e) => {
            for (let i = 0; i < markers.length; i++) {
              const it = markers[i].getExtData();
              let iconImgD = this.ImgDiseaseOrange1;
              if (it.type === 1) {
                iconImgD = this.ImgDiseaseBlue1;
              } else if (it.type === 2) {
                iconImgD = this.ImgDiseaseCyan1;
              }
              const preIcon = new AMap.Icon({
                image: iconImgD,
                size: new AMap.Size(wh[0], wh[1]), // 图标大小
                imageSize: new AMap.Size(wh[0], wh[1]),
              });

              markers[i].setIcon(preIcon);
              markers[i].setOffset(new AMap.Pixel(-wh[0] / 2, -wh[1]));
            }

            const whn = this.getWH(96, 160, 36);
            // eslint-disable-next-line no-undef
            const clickIcon = new AMap.Icon({
              image: iconImgA,
              size: new AMap.Size(whn[0], whn[1]), // 图标大小
              imageSize: new AMap.Size(whn[0], whn[1]),
            });
            e.target.setIcon(clickIcon);
            e.target.setOffset(new AMap.Pixel(-whn[0] / 2, -whn[1]));

            ownerVm.callMethod('showMarkerDetail', item);
          });
          return marker;
        });
        if (this.markersAll.length > 0) {
          this.markersAll = [...this.markersAll, ...markers];
        } else {
          this.markersAll = Object.assign(this.markersAll, markers);
        }

        // eslint-disable-next-line no-undef
        this.overlayGroups = new AMap.OverlayGroup(this.markersAll);
        this.amap.add(this.overlayGroups);
      }
    },
    // 画线
    drawLine(data = []) {
      if (!data.length) return;
      if (!this.amap) return;
      const opts = {
        strokeWeight: 10,
        strokeStyle: 'solid',
        zIndex: 10,
        isOutline: true,
        outlineColor: '#ffeeff',
        borderWeight: 3,
        strokeColor: "#3366FF",
        strokeOpacity: 1,
        // 折线样式还支持 'dashed',strokeStyle是dashed时有效
        strokeDasharray: [10, 5],
        lineJoin: 'round',
        lineCap: 'round',
        zIndex: 50,
        bubble: true, //  将覆盖物的鼠标或touch等事件冒泡到地图上
      };

      if (type === 'loopLine') {
        data.forEach((item) => {
          opts.path = item.position;
          const polyline = new AMap.Polyline(opts);
          this.amap.add(polyline);
          this.projectLineData.push(polyline);
          polyline.on('mouseover', async (e) => {
            console.log('drawLineCustom-polyline-item>>', item);
          });
        });
        this.amap.setFitView(this.projectLineData);
      }
    },
    // 根据需要,通过原始宽高和结果宽度,获取结果图片的大小
    getWH(ow, oh, rw) {
      return [rw, rw * oh / ow];
    },
  },
};
</script>

<style scoped>
  ::v-deep .amap-logo {
    opacity: 0 !important;
    display: none !important;
  }
  ::v-deep .amap-copyright {
    opacity: 0 !important;
    display: none !important;
  }
</style>

特别说明:在 renderjs 中,是不能引入请求api的(真机报错)等普通依赖js方法的,所有跟渲染图层相关的操作,尽量都通过 service 层传参到 renderjs 中处理!

 类似资料: