1.首先,登录需选择个人或者企业实名认证进入百度地图开放平台,点击右上角的控制台,进入开发者管理界面:控制台 | 百度地图开放平台

方法一:由于marker标记很多,拖动时造成卡顿,需要优化(适用少量标点)

代码如下:

 注意点:  记得换成自己的key

https://api.map.baidu.com/api?v=3.0&ak=你的key&callback=onBaiduMapLoaded

<template>
  <div class="map-container">
    <div id="container" class="map" tabindex="0"></div>
    <div class="input-card">
      <div class="mt5"><el-avatar :size="20" src="图标地址"/> 一级代理店</div>
      <div class="mt5"><el-avatar :size="20" src="图标地址"/> 二级代理店</div>
      <div class="mt5"><el-avatar :size="20" src="图标地址"/> 三级代理店</div> 
    </div>
    <div class="info">
      <div class="input-item">
        <el-input v-model="addressInput">
          <template #prepend>请输入地址</template>
        </el-input>
      </div>
      <div class="input-item">
        <el-input v-model="shopInput">
          <template #prepend>请输入店号</template>
        </el-input>
      </div>
      <el-button type='primary' @click="handleSearch">
        点击搜索
      </el-button>
    </div>
    
    <!-- 添加加载进度条 -->
    <div class="loading-overlay" v-if="isLoading">
      <div class="spinner"></div>
      <h3 style="color: #409eff">正在加载代理店数据...</h3>
      <p style="color: #606266">已加载 {{ loadedCount }} / {{ totalCount }} 家代理店 ({{ Math.round(progress) }}%)</p>
      <el-progress :percentage="Math.round(progress)" status="success" :stroke-width="6"></el-progress>
    </div>
  </div>
</template>

<script>
import { onMounted, ref } from 'vue';
// import { Api } from "../manage/api";

export default {
  name: 'AgentMapBaidu',
  setup() {
    const addressInput = ref('');
    const shopInput = ref('');
    const isLoading = ref(true);
    const progress = ref(0);
    const loadedCount = ref(0);
    const totalCount = ref(0);
    
    let map = null;
    let markers = [];
    let localSearch = null;
    let baiduApiLoaded = false;
    let shopData = []; // 存储所有店铺数据
    let batchIndex = 0; // 当前批次索引
    const batchSize = 100; // 减少每批加载的数量
    const delayBetweenMarkers = 10; // 每个标记点之间的延迟(ms)

    // 百度地图点样式
    const getPointStyles = () => {
      if (!window.BMap) return null;
      return {
        '一级代理店': {
          color: '#fcb715',
          icon: '图标地址',
          size: new BMap.Size(50, 50),
          anchor: new BMap.Pixel(5, 5),
          opacity: 0.1
        },
        '二级代理店': {
          color: '#00862b',
          icon: '图标地址',   
          size: new BMap.Size(50, 50),
          anchor: new BMap.Pixel(5, 5),
          opacity: 0.1
        },
        '三级代理店': {
          color: '#015aef',
          icon: '图标地址',
          size: new BMap.Size(50, 50),
          anchor: new BMap.Pixel(5, 5),
          opacity: 0.1
        }
      };
    };

    const initBaiduApi = () => {
      return new Promise((resolve, reject) => {
        if (window.BMap) {
          resolve();
          return;
        }

        // 创建脚本标签
        const script = document.createElement('script');
        script.src = `https://api.map.baidu.com/api?v=3.0&ak=你的key&callback=onBaiduMapLoaded`;
        script.async = true;
        
        // 全局回调函数
        window.onBaiduMapLoaded = () => {
          baiduApiLoaded = true;
          resolve();
        };
        
        script.onerror = () => {
          console.error('百度地图API加载失败');
          reject(new Error('百度地图API加载失败'));
        };
        
        document.head.appendChild(script);
      });
    };

    const loadMap = () => {
      if (!window.BMap) {
        console.error('BMap is not defined');
        return;
      }
      
      map = new BMap.Map("container");
      const point = new BMap.Point(102.342785, 35.312316);
      map.centerAndZoom(point, 5);
      map.enableScrollWheelZoom();
      
      // 初始化本地搜索
      localSearch = new BMap.LocalSearch(map, {
        renderOptions: { map: map, panel: null },
        pageCapacity: 1
      });

      // 加载代理店数据
      loadAgentData();
      
      map.addEventListener("click", function(e) {
        console.log(e.point.lng + "," + e.point.lat);
      });
    };

    // 加载所有代理店数据
    const loadAgentData = async () => {
      if (!window.BMap) return;
      
      try { 
        // 获取所有店铺数据
        // shopData = await Api().GetALl({fcode: '', faddr: '', State: true}); // 此处请替换为实际接口
        shopData = [ { FDLDName: "梁xx", FAdr: "四川省西昌市宁远桥光xxx", FDLDCode2: "0376AO", FType: "二级代理店", FLong: "102.2518450000", FLat: "27.8949840000", FId: 1301} ]
        // shopData = shopData.slice(0, 2000);
        
        // 设置总数量
        totalCount.value = shopData.length;
        
        // 清除旧标记
        clearMarkers();
        
        // 开始分批加载
        await loadBatch();
      } catch (error) {
        console.error('加载代理店数据失败:', error);
        isLoading.value = false;
      }
    };
    
    // 分批加载数据(优化版)
    const loadBatch = async () => {
      if (!window.BMap) return;
      
      const start = batchIndex * batchSize;
      const end = Math.min(start + batchSize, totalCount.value);
      
      const pointStyles = getPointStyles();
      if (!pointStyles) return;
      
      // 处理当前批次的数据(添加延迟)
      for (let i = start; i < end; i++) {
        await processMarker(i, pointStyles);
        
        // 每处理10个标记点更新一次进度
        if ((i - start) % 10 === 0) {
          loadedCount.value = i + 1;
          progress.value = ((i + 1) / totalCount.value) * 100;
        }
      }
      
      // 更新加载状态
      loadedCount.value = end;
      progress.value = (end / totalCount.value) * 100;
      
      // 处理下一批次
      if (end < totalCount.value) {
        batchIndex++;
        // 批次之间添加更长的延迟
        await new Promise(resolve => setTimeout(resolve, 10));
        loadBatch();
      } else {
        // 所有数据加载完成
        isLoading.value = false;
      }
    };
    
    // 处理单个标记点(添加延迟)
    const processMarker = async (index, pointStyles) => {
      const shop = shopData[index];
      const lng = parseFloat(shop.FLong) || 0;
      const lat = parseFloat(shop.FLat) || 0;
      
      // 跳过无效坐标
      if (lng === 0 || lat === 0) {
        return;
      }
      
      const point = new BMap.Point(lng, lat);
      let shopType = '一级代理店';
      if (shop.FType === '二级代理店') {
        shopType = '二级代理店';
      } else if (shop.FType === '三级代理店') {
        shopType = '三级代理店';
      }
      
      const style = pointStyles[shopType];
      if (!style) {
        return;
      }
      
      // 创建图标
      const markerIcon = new BMap.Icon(style.icon, style.size, {
        imageOffset: style.offset,
        imageSize: style.size
      });
      
      const marker = new BMap.Marker(point, {
        icon: markerIcon,
        enableMassClear: true, 
        enableDragging: false,
        opacity: style.opacity || 1
      });
      
      const infoContent = `
        <div style="${'padding: 5px;min-width: 150px;color: ' + style.color};">
          <div>店号:${shop.FDLDCode2 || '无'}</div>
          <div>店主:${shop.FDLDName || '无'}</div>
          <div>地址:${shop.FAdr || '无'}</div>
          <div>类型:${shop.FType || '无'}</div>
        </div>
      `;
      
      const infoWindow = new BMap.InfoWindow(infoContent);
      
      marker.addEventListener("mouseover", function() {
        this.openInfoWindow(infoWindow);
      });
      
      map.addOverlay(marker);
      markers.push(marker);
      
      // 添加延迟,让浏览器有时间处理UI
      await new Promise(resolve => setTimeout(resolve, delayBetweenMarkers));
    };

    const clearMarkers = () => {
      if (!map || markers.length === 0) return;
      
      markers.forEach(marker => {
        map.removeOverlay(marker);
      });
      markers = [];
      console.log("清除所有标记");
    };

    const handleSearch = async() => {
      if (!window.BMap) {
        console.error('BMap is not defined');
        return;
      }
      
      if (addressInput.value) {
        localSearch.search(addressInput.value);
        return;
      }

      if (shopInput.value) {
        // let arr = await Api().GetALl({fcode: shopInput.value, faddr: '', State: true}); //此处请替换为实际接口地址
        let arr = [ { FDLDName: "梁xx", FAdr: "四川省西昌市宁远桥光xxx", FDLDCode2: "0376AO", FType: "二级代理店", FLong: "102.2518450000", FLat: "27.8949840000", FId: 1301} ]
        console.log(arr[0]);
        if( arr.length > 0){
           localSearch.search(arr[0].FAdr);
           console.log(arr[0].FAdr); 
        }
      }
    };

    const clearShopInput = () => shopInput.value = '';
    const clearAddressInput = () => addressInput.value = '';

    onMounted(async () => {
      try {
        await initBaiduApi();
        loadMap();
      } catch (error) {
        console.error('地图初始化失败:', error);
        isLoading.value = false;
      }
    });

    return {
      addressInput,
      shopInput,
      handleSearch,
      clearShopInput,
      clearAddressInput,
      isLoading,
      progress,
      loadedCount,
      totalCount
    };
  }
};
</script>

<style>
html, body, #container {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
}

.map-container {
  position: relative;
  height: 100vh;
  width: 100vw;
}

.input-card {
  position: absolute;
  bottom: 100px;
  right: 20px;
  background: white;
  padding: 10px;
  border-radius: 4px;
  box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
  z-index: 10;
}

.info {
  position: absolute;
  top: 20px;
  right: 20px;
  background: white;
  padding: 10px;
  border-radius: 4px;
  box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
  z-index: 10;
}

.input-item {
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}

.input-item-prepend {
  margin-right: 10px;
}

.mini-button {
  background: #4a90e2;
  color: white;
  border: none;
  padding: 8px 16px;
  border-radius: 4px;
  cursor: pointer;
  display: flex;
  align-items: center;
}

.mini-button:hover {
  background: #3a7bc8;
}

.icon-search {
  margin-right: 5px;
}

/* 加载覆盖层样式 */
.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(255, 255, 255, 0.85);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  z-index: 100;
  backdrop-filter: blur(3px);
}

.spinner {
  width: 50px;
  height: 50px;
  border: 5px solid rgba(64, 158, 255, 0.2);
  border-radius: 50%;
  border-top-color: #409eff;
  animation: spin 1s linear infinite;
  margin-bottom: 20px;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}
</style>

测试只是生成了1000个标点。
接下来要测试下2000个点,嗯有点小卡,但是还能操作,
5000个点试试,完美,动也动不了 简直漂亮
10000个点,芭比Q页面无响应浏览器卡死~~~

方法二:(解决万级标点渲染,结合echarts使用所需插件自行安装)

npm install echarts --save

测试25600+条标点~嗯秒出...还可以

测试一下搜索地址和店号定位标点~不错也是秒出~完结散花~~

代码如下:

 核心代码: 

 const initMap = () => {
      chartInstance = echarts.init(document.getElementById('map-chart'));
      
      // 初始配置 - 简化地图样式配置
      const option = {
        animation: true,
        tooltip: {
          trigger: 'item',
          formatter: params => {
            if (params.data) {
              const data = params.data;
              return `
                <div style="padding: 5px; min-width: 150px; color: ${shopTypeConfig[data.type]?.color || '#333'}">
                  <div>店号:${data.code || '无'}</div>
                  <div>店主:${data.name || '无'}</div>
                  <div>地址:${data.address || '无'}</div>
                  <div>类型:${data.type || '无'}</div>
                </div>
              `;
            }
            return '';
          }
        },
        bmap: {
          center: [102.342785, 35.312316],
          zoom: 5,
          roam: true,
          // 移除自定义样式,使用默认样式
          mapStyle: {}
        },
        series: [{
          name: '代理店',
          type: 'scatter', 
          coordinateSystem: 'bmap',
          data: [],
          symbolSize: function(val) {
            return shopTypeConfig[val.type]?.symbolSize || 10;
          },
          itemStyle: {
            color: function(val) {
              return shopTypeConfig[val.data?.type]?.color || '#333';
            }
          },
          emphasis: {
            itemStyle: {
              color: function(val) {
                return shopTypeConfig[val.data?.type]?.color || '#333';
              },
              borderWidth: 2,
              borderColor: '#fff'
            }
          }
        }]
      };
      
      chartInstance.setOption(option);
      
      // 获取百度地图实例
      bmap = chartInstance.getModel().getComponent('bmap').getBMap();
      bmap.enableScrollWheelZoom();
      
      // 初始化本地搜索
      localSearch = new BMap.LocalSearch(bmap, {
        renderOptions: { map: bmap, panel: null },
        pageCapacity: 1
      });
      
      loadAgentData();
    };

<template>
  <div class="map-container">
    <div id="map-chart" class="map" tabindex="0"></div>
    <div class="input-card">
      <div class="mt5"><el-avatar :size="20" src="图标地址"/>
         一级代理店
      </div>
      <div class="mt5"><el-avatar :size="20" src="图标地址"/>
         二级代理店
      </div>
      <div class="mt5"><el-avatar :size="20" src="图标地址"/>
         三级代理店
      </div> 
    </div>
    <div class="info">
      <div class="input-item">
        <el-input @keyup.enter="handleSearch" @input="getaddValue" v-model="addressInput">
          <template #prepend>请输入地址</template>
        </el-input>
      </div>
      <div class="input-item">
        <el-input @keyup.enter="handleSearch" @input="getaddFcode" v-model="shopInput">
          <template #prepend>请输入店号</template>
        </el-input>
      </div>
      <el-button type='primary'  @click="handleSearch">
        点击搜索
      </el-button> 
    </div>
  </div>
</template>

<script>
import { onMounted, ref, onBeforeUnmount } from 'vue';
import * as echarts from 'echarts';
import 'echarts/extension/bmap/bmap';

export default {
  name: 'AgentMapEcharts',
  setup() {
    const addressInput = ref('');
    const shopInput = ref('');
    const flageone =  ref(false)
    const flagetwo =  ref(false)
    let chartInstance = null;
    let bmap = null;
    let localSearch = null;

    // 店铺类型配置
    const shopTypeConfig = {
      '一级代理店': {
        color: '#fcb715',
        icon: '图标地址',
        symbolSize: 18 //图标在地图大小显示
      },
      '二级代理店': {
        color: '#00862b',
        icon: '图标地址',
        symbolSize: 16
      },
      '三级代理店': {
        color: '#015aef',
        icon: '图标地址',
        symbolSize: 16
      }
    };

    // 初始化地图和图表
    const initMap = () => {
      chartInstance = echarts.init(document.getElementById('map-chart'));
      
      // 初始配置 - 简化地图样式配置
      const option = {
        animation: true,
        tooltip: {
          trigger: 'item',
          formatter: params => {
            if (params.data) {
              const data = params.data;
              return `
                <div style="padding: 5px; min-width: 150px; color: ${shopTypeConfig[data.type]?.color || '#333'}">
                  <div>店号:${data.code || '无'}</div>
                  <div>店主:${data.name || '无'}</div>
                  <div>地址:${data.address || '无'}</div>
                  <div>类型:${data.type || '无'}</div>
                </div>
              `;
            }
            return '';
          }
        },
        bmap: {
          center: [102.342785, 35.312316],
          zoom: 5,
          roam: true,
          // 移除自定义样式,使用默认样式
          mapStyle: {}
        },
        series: [{
          name: '代理店',
          type: 'scatter', 
          coordinateSystem: 'bmap',
          data: [],
          symbolSize: function(val) {
            return shopTypeConfig[val.type]?.symbolSize || 10;
          },
          itemStyle: {
            color: function(val) {
              return shopTypeConfig[val.data?.type]?.color || '#333';
            }
          },
          emphasis: {
            itemStyle: {
              color: function(val) {
                return shopTypeConfig[val.data?.type]?.color || '#333';
              },
              borderWidth: 2,
              borderColor: '#fff'
            }
          }
        }]
      };
      
      chartInstance.setOption(option);
      
      // 获取百度地图实例
      bmap = chartInstance.getModel().getComponent('bmap').getBMap();
      bmap.enableScrollWheelZoom();
      
      // 初始化本地搜索
      localSearch = new BMap.LocalSearch(bmap, {
        renderOptions: { map: bmap, panel: null },
        pageCapacity: 1
      });
      
      loadAgentData();
    };

    // 加载代理店数据
    const loadAgentData = async () => {  
      try {
        // let shops = await Api().GetALl({fcode: '', faddr: '', State: true}); // 此处请替换为实际接口地址
        let shops = [ { FDLDName: "梁xx", FAdr: "四川省西昌市宁远桥光xxx", FDLDCode2: "0376AO", FType: "二级代理店", FLong: "102.2518450000", FLat: "27.8949840000", FId: 1301} ] 
        // console.log("店铺数据:", shops);
        
        // 转换数据格式
        const data = shops
          .filter(shop => {
            const lng = parseFloat(shop.FLong) || 0;
            const lat = parseFloat(shop.FLat) || 0;
            return lng !== 0 && lat !== 0;
          })
          .map(shop => {
            // if( shop.FType === '三级代理店'){
            //    console.log("==>", shop);
            // }
            const type = shop.FType || '一级代理店';
            return {
              name: shop.FDLDName,
              code: shop.FDLDCode2,
              address: shop.FAdr,
              type: type,
              value: [parseFloat(shop.FLong), parseFloat(shop.FLat), shop.FDLDName],
              symbol: `image://${shopTypeConfig[type]?.icon}`,
              symbolSize: shopTypeConfig[type]?.symbolSize || 10,
              itemStyle: {
                color: shopTypeConfig[type]?.color || '#333'
              }
            }; 
          });
        
        // 更新图表数据
        chartInstance.setOption({
          series: [{
            data: data
          }]
        });
      } catch (error) {
        console.error('加载代理店数据失败:', error);
      }
    };
     
    const getaddValue = () => { 
      flageone.value = true
      flagetwo.value = false
    };
    const getaddFcode = () => { 
       flagetwo.value = true
       flageone.value = false
    };
    // 处理搜索
    const handleSearch = async () => {
      if (!bmap) return;
      if (addressInput.value && flageone.value) {
        localSearch.search(addressInput.value);
        shopInput.value = ''
        return;
      }

      if (shopInput.value && flagetwo.value) {
        // let arr = await Api().GetALl({fcode: shopInput.value, faddr: '', State: true}); // 此处请替换为实际接口地址
        let arr = [ { FDLDName: "梁xx", FAdr: "四川省西昌市宁远桥光xxx", FDLDCode2: "0376AO", FType: "二级代理店", FLong: "102.2518450000", FLat: "27.8949840000", FId: 1301} ]
        if (arr.length > 0) {
          localSearch.search(arr[0].FAdr);
          addressInput.value = ''
        }
      }
    };

    // 窗口大小变化时重新调整图表大小
    const handleResize = () => {
      if (chartInstance) {
        chartInstance.resize();
      }
    };

    onMounted(() => {
      // 检查是否已加载百度地图API
      if (window.BMap) {
        initMap();
        return;
      }
      
      // 动态加载百度地图API
      const script = document.createElement('script');
      script.src = `https://api.map.baidu.com/api?v=3.0&ak=你的key&callback=initBMapCallback`; //需要换成百度地图的key
      script.async = true;
      
      window.initBMapCallback = () => {
        initMap();
      };
      
      script.onerror = () => {
        console.error('百度地图API加载失败');
      };
      
      document.head.appendChild(script);
      
      window.addEventListener('resize', handleResize);
    });

    onBeforeUnmount(() => {
      window.removeEventListener('resize', handleResize);
      if (chartInstance) {
        chartInstance.dispose();
      }
    });

    return {
      addressInput,
      shopInput,
      handleSearch,
      getaddValue,
      getaddFcode
    };
  }
};
</script>

<style>
.map-container {
  position: relative;
  height: 100vh;
  width: 100vw;
}

.map {
  height: 100%;
  width: 100%;
}

.input-card {
  position: absolute;
  bottom: 100px;
  right: 20px;
  background: white;
  padding: 10px;
  border-radius: 4px;
  box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
  z-index: 10;
}

.info {
  position: absolute;
  top: 20px;
  right: 20px;
  background: white;
  padding: 10px;
  border-radius: 4px;
  box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
  z-index: 10;
}

.input-item {
  display: flex;
  align-items: center; 
  margin-bottom: 10px;
}
</style>

官方: jspopularGL | 百度地图API SDK

有问题欢迎来聊~需要离线版本的可以@@

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐