当前位置:   article > 正文

vue3.0 + typescript openlayers实现地图标点、移动、画线、显示范围、测量长度、测量面积、画三角形、画正方形、画圆、线选、画笔、清除测量、清除、地图上展示弹窗等功能_vue3 openlayers

vue3 openlayers

vue3.0 + typescript openlayers实现地图标点、移动、画线、显示范围、测量长度、测量面积、画三角形、画正方形、画圆、线选、画笔、清除测量、清除地图所有等功能

由于最近项目中用到了地图,所以今天有时间把代码摘出来,自己写个地图的小demo标记下
话不多说,先看效果:

map1

1、安装ol

 npm i ol@6.14.1
  • 1

这是我的目录结构
在这里插入图片描述

2、下面是OpenlayerMap/index.vue(地图)的代码,记得申请地图得key,记得填到下方的代码中

<template>
  <div class="openlayersMap">
    <div id="map"></div>

    <!-- 鼠标经纬度指示 -->
    <div
      id="mouse-position"
      :style="assignMouseIndicatePosition"
      v-if="needMouseIndicate"
    ></div>

    <!-- 图层上展示的弹窗 -->
    <div id="popup-box">
      <!-- <span id="popup-closer"></span> -->
      <div id="popup-content">
        <slot :value="sol"></slot>
      </div>
    </div>

    <div id="popup-box-right" :style="{top:'-90px',left:'5px'}">
      <hr :style="{border: '2px solid #2af0e1',borderRadius: '40px',width:'2vw',marginTop:'80px'}"/>
      <div id="popup-content">
        <slot name="right" :value="sol">
        </slot>
      </div>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted, nextTick } from "vue";
import { getTopLeft, getWidth } from "ol/extent";
import { getArea, getLength } from "ol/sphere";
import { Map, View, Feature, Overlay } from "ol";
import { Draw, Modify, Snap } from "ol/interaction";
import { Circle as CircleGeo } from "ol/geom";
import { Circle, Fill, Stroke, Style, Text, Icon } from "ol/style";
import { Tile, Vector as VectorLayer } from "ol/layer";
import { defaults, MousePosition } from "ol/control";
import { get, fromLonLat } from "ol/proj";
import WMTSTileGrid from "ol/tilegrid/WMTS";
import { createStringXY } from "ol/coordinate";
import { WMTS, Vector as VectorSource } from "ol/source";
import { LineString, Point, Polygon } from "ol/geom";
import { createBox, createRegularPolygon } from "ol/interaction/Draw";
import CircleStyle from "ol/style/Circle";
import { unByKey } from "ol/Observable";
const startImg: any = require("@/image/startPoint.png"); //轨迹起点图标
const endImg: any = require("@/image/endPoint.png"); //轨迹终点图标
// 是否显示地图的经纬度指示
const props = withDefaults(defineProps<{ needMouseIndicate: boolean }>(), {
  needMouseIndicate: true
});
const modelMange: String='';
let sol: any = ref(null); // 插槽回填数据
let assignMouseIndicatePosition: IMosueIndicatePosition;
let drawSource: VectorSource;
let drawVector: any = null;
let exportDrawVector: any = ref(null);
let map: Map | undefined = undefined;
const exportMap =ref<any>(null)
let saveVectorLayer: any | null = null;
let mousePositionControl: MousePosition;
const layerObj: any=ref(null);
const isActivePopup:any=ref(false);
const singleLayer:any=ref(null);
const saveGroupLayer:any=ref(null);  //图形Layer

const draw:any=ref(null);  //画笔
const drawList:any=ref([]);  //
const snap:any=ref(null);  //

const state=reactive<any>({
  shapeType:'',
  layerIndex:0,
  drawCache:[],
  helpTooltip:'',
  continueLineMsg:'',
  helpTooltipElement:null,
  measureTooltipElement:null,
  measureTooltip:null,
  sketch:null,
  listener:null,

  //路径相关
  routeMap:[],

})

/**
 * 在地图上绘制图层
 */
//#region
const initDrawSource = () => {
  drawSource = new VectorSource();
  drawVector = new VectorLayer({
    source: drawSource,
    style: new Style({
      fill: new Fill({
        color: "rgba(255, 255, 255, 0.2)",
      }),
      stroke: new Stroke({
        color: "#ffcc33",
        width: 2,
      }),
      image: new Circle({
        radius: 7,
        fill: new Fill({
          color: "#ffcc33",
        }),
      }),
    }),
  });
  exportDrawVector.value=drawVector
  const modify = new Modify({ source: drawSource });
  // exportMap.value.addInteraction(modify)
  return modify;
};
// 得到初始化地图控制器
function getIninialControl(mouseInfoTargetId: string = "mouse-position") {
  if (props.needMouseIndicate) {
    mousePositionControl = new MousePosition({
      coordinateFormat: createStringXY(5),
      projection: "EPSG:4326",
      className: "custom-mouse-position",
      target: document.getElementById(mouseInfoTargetId) || undefined,
      undefinedHTML: " ",
    });
    return defaults({ zoom: false, rotate: false }).extend([
      mousePositionControl,
      // 全屏插件
      // new FullScreen(),
    ]);
  } else {
    return defaults({ zoom: false, rotate: false });
  }
}
// 地图初始化
const initMap=()=>{
  try {
    let projection: any = get("EPSG:4326");
    let projectionExtent = projection!.getExtent();
    let size = getWidth(projectionExtent) / 256;
    let resolutions = new Array(18);
    let matrixIds = new Array(18);
    const modify = initDrawSource();

    for (let i = 1; i <= 18; i++) {
      resolutions[i] = size / Math.pow(2, i);
      matrixIds[i] = i;
    }
    map = new Map({
      controls: getIninialControl(),
      layers: [
        // 卫星图层数据
        new Tile({
          source: new WMTS({
            url: "http://t{0-7}.tianditu.gov.cn/img_c/wmts?tk=你的KEY",//这里是你申请的key
            layer: "img",
            style: "default",
            matrixSet: "c",
            projection: projection,
            format: "tiles",
            tileGrid: new WMTSTileGrid({
              origin: getTopLeft(projectionExtent),
              resolutions: resolutions,
              matrixIds: matrixIds,
            }),
            wrapX: true,
          }),
        }),
        // 卫星行政数据
        new Tile({
          source: new WMTS({
            url: "http://t{0-7}.tianditu.gov.cn/cia_c/wmts?tk=你的KEY",//这里是你申请的key
            layer: "cia", //vec/cva img/cia
            matrixSet: "c",
            format: "tiles",
            style: "default",
            projection: projection,
            tileGrid: new WMTSTileGrid({
              origin: getTopLeft(projectionExtent),
              resolutions: resolutions,
              matrixIds: matrixIds,
            }),
            wrapX: true,
          }),
        }),
        drawVector,
      ],
      target: "map",
      view: new View({
        center: [108.8821,34.2227], // 初始化中心点 西安软件园
        maxZoom: 18,
        minZoom: 8,
        zoom: 15,//地图层级
        projection: "EPSG:4326",
      }),
    });
    exportMap.value=map
    map.addInteraction(modify);
  } catch (err) {
    console.log(err);
  }
}

// 在页面上展示点
const lastShowPoints= (dataList: any[], imgStr: string,scale: number=1,fn?: any,)=>{   
  if (dataList.length === 0)  return;
  try {
    let features: any[] = []; // 定义坐标s
    imgStr =require(`../../image/${imgStr}`);
    let vectorLayer = new VectorLayer({
      renderBuffer: 200,
      source: new VectorSource(),
      style: (feature) => [
        new Style({
          image: new Icon({
            src: imgStr,
            scale: scale,
            // imgSize: [50, 50],
          }),
        }),
      ],
    });
    // console.log('points',dataList);
    dataList.forEach((item) => {
      item.sol = fn(JSON.parse(JSON.stringify(item)));
      if ((item.lng || item.longitude) && (item.lat || item.latitude)) {
        let newObj = Object.assign({}, item);
        const wz=[+item.lng?item.lng:item.longitude, +item.lat?item.lat:item.latitude];
        // console.log('wz',wz);
        newObj.geometry = new Point(wz);
        features.push(new Feature(newObj));
        if(item.sol.circle){
          let circleFeature = new Feature({  //添加面
            geometry: new CircleGeo([wz[0]*1,wz[1]*1], 0.005)
          });
          circleFeature.setStyle(new Style({  // 设置样式
            fill: new Fill({
              color: 'rgba(255, 255, 255, 0.1)'
            }),
            stroke: new Stroke({
              color: 'rgba(217, 11, 53, 0.4)',
              lineDash: [20, 10]
            })
          }));
          features.push(circleFeature);
        }
      }
    });
    vectorLayer.getSource()!.addFeatures(features);
    map!.addLayer(vectorLayer);
    saveVectorLayer=vectorLayer
    return saveVectorLayer
  } catch (error) {
    console.log(error);
  }
}

//点数组绘图
const groupPlot=(data:any,color?:string,borderColor?:string)=>{
  console.log(color);
  color=color || "rgba(252, 51, 40, 0.2700)"
  let source = new VectorSource();
  let style = new Style({
    text: new Text({
        // font: '15px Microsoft YaHei',
        // text:'xxxx',
        fill: new Fill({
          color: '#fff'
        })
    }),
    fill: new Fill({
        color
    }),
    stroke: new Stroke({
        color: borderColor || 'rgba(252, 51, 40, 1)',
        width:  2
    }),
    image: new Circle({
        radius: 10,
        fill: new Fill({
            color: '#ffcc33'
        })
    })
  });
  //矢量图层
  let vectorLayer = new VectorLayer({
      source: source,
      style: style,
  });    
  let features: any[] = [];
 
  //多边形要素类
  data.map((n:any)=>{
    //声明一个新的数组
    let coordinatesPolygon = new Array();
    
    //循环遍历将经纬度转到"EPSG:4326"投影坐标系下
    for (let i = 0; i < n.pointList.length; i++) {
        let pointTransform = fromLonLat([n.pointList[i][0], n.pointList[i][1]], "EPSG:4326");
        coordinatesPolygon.push(pointTransform);
    }
    let feature = new Feature({
        ...n,
        geometry: new Polygon([coordinatesPolygon]),//多边形此处注意一定要是[坐标数组]
    });
    features.push(feature)
  })
  
  source.addFeatures(features);
  map!.addLayer(vectorLayer);
  saveGroupLayer.value=vectorLayer;
  return vectorLayer
}
 // 点击地图后的交互(主要是图标)
const mapClick=()=>{    
  map!.on("click", (event) => {
    console.log(784,event)
   
    removeModel();
    let bool=true;
    let pixel =map!.getEventPixel(event.originalEvent);
    map?.forEachFeatureAtPixel(pixel, (feature: any,a) => {     
      try {
        let myfeature;
        if(feature.values_.features){//聚合点击
          myfeature=feature.values_.features[0];
        }else{
          myfeature=feature;
        }
        // console.log('myfeature',myfeature);
        
        if(!myfeature.values_.sol) return
        sol.value=myfeature.values_.sol;
        console.log('sol',sol.value)
        // console.log('sol',sol.value || myfeature.values_);
        let x = myfeature.get("longitude") || myfeature.get("lng"),
          y = myfeature.get("latitude") || myfeature.get("lat");
        let coordinate = [x, y]; 
        //来控制弹框样式         
        let popupClass="popup-box";   //popup-box-right
        if(sol.value.popupClass) popupClass=sol.value.popupClass
        //来控制弹框边距样式
        // this.modelMangebottom=this.sol.bottom || '0';     
        // this.modelMangeleft=this.sol.left || '0';     
        let overlay = new Overlay({ 
          element: document.getElementById(popupClass) || undefined,
        });
        
        map!.addOverlay(overlay);
        overlay.setPosition(coordinate);
        layerObj.value = overlay;
        bool=false
        isActivePopup.value=true;
      } catch (error) {
        console.log(error);
      }   
    });
    // if((this.$parent as any).isPopup && (this.$parent as any).isPopup.length>0) (this.$parent as any).isPopup=[];
    
    if(bool) map!.removeLayer(singleLayer.value);
  });
}

//清除已打开的弹框
const removeModel=()=>{
  if(isActivePopup.value){
    layerObj.value.setPosition(undefined);
    sol.value = {};
    layerObj.value=null;
    isActivePopup.value=false
  }
}

// 移动到指定中心点位
const moveToPoint=async (x: number, y: number)=>{
  // console.log(x,y);
  map!.getView().animate({
    center: [x, y],
  });
}

//画线
const drawLine=(bool:boolean)=>{
    draw.value && map!.removeInteraction(draw.value);
    draw.value = new Draw({
      source:drawVector.getSource(),
      type: "LineString",
      freehand: bool,
      stopClick: true,
    });
    exportMap.value.addInteraction(draw.value);
    draw.value && draw.value.on('drawend',() =>drawList.value.push(draw.value))
    // console.log('drawVector',drawVector);
    return draw.value;
}

// 多边形
const drawPolygon=()=>{
  draw.value && map!.removeInteraction(draw.value);
  draw.value = new Draw({
    source: drawVector.getSource(),
    type: "Polygon",
    stopClick: true,
  });
  exportMap.value.addInteraction(draw.value);
  draw.value && draw.value.on('drawend',() =>drawList.value.push(draw.value))
}

// 画圆
const drawCircle=(type:string)=>{
  draw.value && map!.removeInteraction(draw.value);
  if (type == "triangle") {
    //正三角
    draw.value = new Draw({
      source: drawVector.getSource(),
      type: "Circle",
      geometryFunction: createRegularPolygon(3),
      stopClick: true,
    });
  } else if (type == "circle") {
    draw.value = new Draw({
      //正圆
      source: drawVector.getSource(),
      type: "Circle",
      stopClick: true,
    });
  } else if (type == "square") {
    draw.value = new Draw({
      //正方形
      source: drawVector.getSource(),
      type: "Circle",
      geometryFunction: createRegularPolygon(4),
      stopClick: true,
    });
  } else if (type == "rectangle") {
    draw.value = new Draw({
      //长方形
      source: drawVector.getSource(),
      type: "Circle",
      geometryFunction: createBox(),
      stopClick: true,
    });
  }
  snap.value = new Snap({source: drawSource });
  exportMap.value.addInteraction(snap.value); //鼠标捕捉
  exportMap.value.addInteraction(draw.value);
  draw.value && draw.value.on('drawend',() =>drawList.value.push(draw.value))
}

 /** 测距、测面*/
const measure=(type:string)=>{
  draw.value && exportMap.value.removeInteraction(draw.value);
  state.shapeType = type;
  state.layerIndex++;
  state.drawCache[state.layerIndex] = {
    feature: null,
    measureTooltip: null,
  };
  if (draw.value) {
    exportMap.value.removeInteraction(draw.value);
  }
  // 添加map事件
  addMapEvent();
}

const addMapEvent=()=>{
  exportMap.value.on("pointermove", (evt:any) => {
    draw.value? pointerMoveHandler(evt): exportMap.value.removeOverlay(state.helpTooltip);
  });
  exportMap.value.getViewport().addEventListener("mouseout", () => {
    state.helpTooltipElement &&
    state.helpTooltipElement.classList.add("hidden");
  });
  addInteraction();
}

const addInteraction=()=> {
  draw.value = new Draw({
    source: drawVector.getSource(),
    type: state.shapeType,
    style: new Style({
      fill: new Fill({ color: "rgba(255, 255, 255, 0.2)" }),
      stroke: new Stroke({
        color: "rgba(255, 255, 255, 1)",
        lineDash: [10, 10],
        width: 2,
      }),
      image: new CircleStyle({
        radius: 5,
        stroke: new Stroke({ color: "rgba(255, 255, 255, 0.8)" }),
        fill: new Fill({ color: "rgba(255, 255, 255, 0.2)" }),
      }),
    }),
  });
  exportMap.value.addInteraction(draw.value);
  createMeasureTooltip();
  createHelpTooltip();
  drawHandler();
}

const createMeasureTooltip=()=>{
  if(state.measureTooltipElement) {
    state.measureTooltipElement.parentNode.removeChild(
      state.measureTooltipElement
    );
  }
  state.measureTooltipElement = document.createElement("div");
  state.measureTooltipElement.className = "ol-tooltip ol-tooltip-measure";
  state.measureTooltip = new Overlay({
    element: state.measureTooltipElement,
    offset: [0, -15],
    positioning: "bottom-center",
  });
  exportMap.value.addOverlay(state.measureTooltip);
}

const createHelpTooltip=()=>{
  if (state.helpTooltipElement) {
    state.helpTooltipElement.parentNode.removeChild(state.helpTooltipElement);
  }
  state.helpTooltipElement = document.createElement("div");
  state.helpTooltipElement.className = "ol-tooltip hidden";
  state.helpTooltip = new Overlay({
    element: state.helpTooltipElement,
    offset: [15, 0],
    positioning: "center-left",
  });
  exportMap.value.addOverlay(state.helpTooltip);
}

const drawHandler=()=>{
  draw.value.on("drawstart", (evt:any) => {
    state.sketch = evt.feature;
    let tooltipCoord = evt.coordinate;

    state.listener = state.sketch.getGeometry().on("change", (evt:any) => {
      let output;
      const geom = evt.target;
      if (geom instanceof LineString) {
        output = formatLength(geom);
        tooltipCoord = geom.getLastCoordinate();
      } else if (geom instanceof Polygon) {
        output = formatArea(geom);
        tooltipCoord = geom.getInteriorPoint().getCoordinates();
      }
      let closeBtn =
        "<i class='tooltip-close-btn tooltip-close-btn_" +
        state.layerIndex +
        "' data-index='" +
        state.layerIndex +
        "'></i>";
        state.measureTooltipElement.innerHTML = output + closeBtn;
        state.measureTooltip.setPosition(tooltipCoord);
        state.drawCache[state.layerIndex].measureTooltip = state.measureTooltip;
    });
  });

  draw.value.on("drawend", (evt:any) => {
    // console.log('hhhh');
    
    // (this.$parent as any).toolsindex ='';
    state.drawCache[state.layerIndex].feature = evt.feature;
    state.measureTooltipElement.className = "ol-tooltip ol-tooltip-static";
    state.measureTooltip.setOffset([0, -7]);
    state.sketch = null;
    state.measureTooltipElement = null;
    createMeasureTooltip();
    unByKey(state.listener);
    exportMap.value.removeInteraction(draw.value);
    draw.value = null;        
    // 删除图层
    const self = this;
    document?.querySelector(".tooltip-close-btn_" + state.layerIndex).addEventListener("click", function (e:any) {
      // console.log('dataset',e);
      
      // state.drawVector
      //     .getSource()
      //     .removeFeature(state.drawCache[state.dataset.index].feature);
      //     state.map.removeOverlay(
      //       state.drawCache[state.dataset.index].measureTooltip
      //   );
      //   delete state.drawCache[state.dataset.index];
      });
  });
}

const formatLength=(line:any)=>{
  const sourceProj = exportMap.value.getView().getProjection(); //获取投影坐标系
  var length = getLength(line, { projection: sourceProj });
  var output;
  if (length > 100) {
    output = Math.round((length / 1000) * 100) / 100 + " " + "km";
  } else {
    output = Math.round(length * 100) / 100 + " " + "m";
  }
  return output;
}

const formatArea=(polygon:any)=>{
  const sourceProj = exportMap.value.getView().getProjection(); //获取投影坐标系
  const geom = polygon.clone().transform(sourceProj, "EPSG:3857");
  const area = getArea(geom);

  let output;
  if (area > 10000) {
    output =
      Math.round((area / 1000000) * 100) / 100 + " " + "km<sup>2</sup>";
  } else {
    output = Math.round(area * 100) / 100 + " " + "m<sup>2</sup>";
  }
  return output;
}

const pointerMoveHandler=(evt:any)=>{
  if (evt.dragging) {
    return;
  }
  /** @type {string} */
  var helpMsg = "测量";

  if (state.sketch) {
    var geom = state.sketch.getGeometry();
    if (geom instanceof LineString) {
      helpMsg = state.continueLineMsg;
    }
  }
  state.helpTooltipElement.innerHTML = helpMsg;
  state.helpTooltip.setPosition(evt.coordinate);
  state.helpTooltipElement.classList.remove("hidden");
}
// **************

//路径相关
// 开始显示一条轨迹
const  showWay=async(_routeInfo: IRouteInfo)=>{  
  if (state.routeMap.some((route:any) => route.id === _routeInfo.id)) {
    // 已经有了路径,直接移动视野到该点
    moveToPoint(_routeInfo.gis[0][0], _routeInfo.gis[0][1]);
    return;
  }
  
  // 根据一系列点设置地图视野中点
  const point = _routeInfo.gis[0];

  // 将地图设置到最大缩放度
  const view = map!.getView();
  const MaxZoom = view.getMaxZoom();
  const MinZoom = view.getMinZoom();
  const zoom = Math.ceil((MaxZoom + MinZoom) / 2);
  view.setZoom(zoom);

  await moveToPoint(point[0], point[1]);

  showRouterMap(_routeInfo);
}

// 路径显示
const showRouterMap=(_routeInfo: any)=>{
  let pointsList = _routeInfo.gis;
  // pointsList.map(n=>{
  //   n=[1*n[0],1*n[1]]
  // })
  let roadLine = new LineString(pointsList);
  let output=formatLength(roadLine)
  console.log('output',pointsList,output);
  
  let roadLineSource = new VectorSource({
    features: [new Feature(roadLine)],
  });
  const roadLineLayer = new VectorLayer({
    source: roadLineSource,
    style: new Style({
      stroke: new Stroke({
        color: "#38A0FF",
        width: 4,
      }),
    }),
  });
  map!.addLayer(roadLineLayer);
  let pointLayer1 = addVectorLabel({
    pointsList: pointsList[0],
    txt: "起",
  });
  let pointLayer2 = addVectorLabel({
    pointsList: pointsList[pointsList.length - 1],
    txt: "终",
  });
  let label = addVectorLabel({
    pointsList: [pointsList[0][0], pointsList[0][1]],
    txt: _routeInfo.name + ",全程" + output,
    fill: "#111111",
    stroke: "#ffffff",
  });

  // 保存实例
  state.routeMap.push({
    id: _routeInfo.id as string,
    routeLayerExample: roadLineLayer,
    vectorLabels: [label],
    points: [pointLayer1, pointLayer2],
  });
}

// 添加矢量标签(例如路径的起终点、描述)
const addVectorLabel=(opt: any)=>{
  let vectorSource = new VectorSource(); //矢量标注的数据源
  const layer = new VectorLayer({
    source: vectorSource,
  }); //矢量标注图层
  map!.addLayer(layer);
  if (opt.txt == "起" || opt.txt == "终") {
    // 添加起点以及终点的layer
    let newFeature = new Feature({
      geometry: new Point(opt.pointsList || []),
    });
    newFeature.setStyle(
      new Style({
        image: new Icon({
          src: opt.txt == "起" ? startImg : endImg,
          offset: [0, -26],
          offsetOrigin: "bottom-right",
          size: [32, 60],
        }),
        fill: new Fill({ color: "#ffffff" }),
        zIndex: 1,
      })
    );
    // 将新要素添加到数据源中
    vectorSource.addFeature(newFeature);
    return layer;
  }
  let overlayerElement = document.createElement("div");
  overlayerElement.className = "ol-tooltip-draw-route";
  overlayerElement.innerHTML = opt.txt;
  const overlayObj = new Overlay({
    element: overlayerElement,
    offset: [0, -30],
    positioning: "bottom-center",
  });
  overlayObj.setPosition(opt.pointsList);
  map!.addOverlay(overlayObj);
  return overlayObj;
}

// 清除部分路径
const clearRoute=(_routeId: number|string | Array<number|string>)=>{  
  if (Array.isArray(_routeId)) {
    for (let routeId of _routeId) {
      let routeWayIndex = state.routeMap.findIndex((it:any)=>it.id == routeId)
      let routeItem = state.routeMap[routeWayIndex]
      // console.log('routeItem',routeItem,state.routeMap,routeId);
      
      exportMap.value.removeLayer(routeItem.routeLayerExample);
      routeItem.points?.forEach((it:any) => exportMap.value.removeLayer(it));
      routeItem.vectorLabels.forEach((it:any) => exportMap.value.removeOverlay(it));
      state.routeMap.splice(routeWayIndex, 1);
    }
  } else {
    if (!_routeId) return;
    let routeWayIndex = state.routeMap.findIndex((it:any)=>it.id == _routeId)
    let routeItem = state.routeMap[routeWayIndex]

    exportMap.value.removeLayer(routeItem.routeLayerExample);
    routeItem.points?.forEach((it:any) => exportMap.value.removeLayer(it));
    routeItem.vectorLabels.forEach((it:any) => exportMap.value.removeOverlay(it));
    state.routeMap.splice(routeWayIndex, 1);
  }
}

nextTick(()=>{
  
})
defineExpose({measure,removeModel,lastShowPoints,groupPlot,moveToPoint,exportMap,drawLine,drawPolygon,drawCircle,draw,exportDrawVector,state,showWay,clearRoute})

onMounted(() => {
  initMap();
  mapClick()
});

</script>

<style lang="scss" scoped>
.openlayersMap {
  width: 100%;
  height: 100%;
  #map {
    height: 100%;
  }
  #mouse-position {
    position: absolute;
    top: 10px;
    right: 20px;
    color: #fff;
    font-weight: bold;
    font-size: 18px;
  }
  #popup-box{
    bottom: 25px;
    left: 0px;
    background-color: rgba(0, 0, 1, 0.5);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
  }
  #popup-box ,#popup-box-right{
    position: absolute;
    z-index: -1;
    box-sizing: border-box;
    padding: 4px 6px;
    border-radius: 4px;
    
    border: 2px solid #84f199;
    min-width: 280px;
    position: absolute;
    // bottom: 20px;
    // left: -50px;
    #popup-closer {
      font-size: 14px;
      height: 20px;
      line-height: 20px;
      text-align: right;
      position: absolute;
      right: 0;
      top: 0;
      margin-right: 4px;
      user-select: none;
      cursor: pointer;
      color: #fff;
    }
    #popup-content {
      // margin-top: 24px;
      display: flex;
      max-height: 600px;
      // overflow-y: scroll;
      position: relative;
    }
    &:after,
    &:before {
      top: 100%;
      border: solid transparent;
      content: " ";
      height: 0;
      width: 0;
      position: absolute;
      pointer-events: none;
    }
    &:after {
      border-top-color: white;
      border-width: 10px;
      left: 48px;
      margin-left: -10px;
    }
    &:before {
      border-top-color: #cccccc;
      border-width: 11px;
      left: 48px;
      margin-left: -11px;
    }
  }
  #popup-box-right{
    // bottom: -24vh;
    // left: 2vh;
    border: none;
    display: flex;
    &:after,
    &:before {content:none;}
    > #popup-content{
        background: url("~@/image/chart.png") no-repeat;
        background-size: 100% 100%;
    }
  }
  
}
</style>


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640
  • 641
  • 642
  • 643
  • 644
  • 645
  • 646
  • 647
  • 648
  • 649
  • 650
  • 651
  • 652
  • 653
  • 654
  • 655
  • 656
  • 657
  • 658
  • 659
  • 660
  • 661
  • 662
  • 663
  • 664
  • 665
  • 666
  • 667
  • 668
  • 669
  • 670
  • 671
  • 672
  • 673
  • 674
  • 675
  • 676
  • 677
  • 678
  • 679
  • 680
  • 681
  • 682
  • 683
  • 684
  • 685
  • 686
  • 687
  • 688
  • 689
  • 690
  • 691
  • 692
  • 693
  • 694
  • 695
  • 696
  • 697
  • 698
  • 699
  • 700
  • 701
  • 702
  • 703
  • 704
  • 705
  • 706
  • 707
  • 708
  • 709
  • 710
  • 711
  • 712
  • 713
  • 714
  • 715
  • 716
  • 717
  • 718
  • 719
  • 720
  • 721
  • 722
  • 723
  • 724
  • 725
  • 726
  • 727
  • 728
  • 729
  • 730
  • 731
  • 732
  • 733
  • 734
  • 735
  • 736
  • 737
  • 738
  • 739
  • 740
  • 741
  • 742
  • 743
  • 744
  • 745
  • 746
  • 747
  • 748
  • 749
  • 750
  • 751
  • 752
  • 753
  • 754
  • 755
  • 756
  • 757
  • 758
  • 759
  • 760
  • 761
  • 762
  • 763
  • 764
  • 765
  • 766
  • 767
  • 768
  • 769
  • 770
  • 771
  • 772
  • 773
  • 774
  • 775
  • 776
  • 777
  • 778
  • 779
  • 780
  • 781
  • 782
  • 783
  • 784
  • 785
  • 786
  • 787
  • 788
  • 789
  • 790
  • 791
  • 792
  • 793
  • 794
  • 795
  • 796
  • 797
  • 798
  • 799
  • 800
  • 801
  • 802
  • 803
  • 804
  • 805
  • 806
  • 807
  • 808
  • 809
  • 810
  • 811
  • 812
  • 813
  • 814
  • 815
  • 816
  • 817
  • 818
  • 819
  • 820
  • 821
  • 822
  • 823
  • 824
  • 825
  • 826
  • 827
  • 828
  • 829
  • 830
  • 831
  • 832
  • 833
  • 834
  • 835
  • 836
  • 837
  • 838
  • 839
  • 840
  • 841
  • 842
  • 843
  • 844
  • 845
  • 846
  • 847
  • 848
  • 849
  • 850
  • 851
  • 852
  • 853
  • 854
  • 855
  • 856
  • 857
  • 858
  • 859
  • 860
  • 861
  • 862
  • 863
  • 864
  • 865
  • 866
  • 867
  • 868
  • 869
  • 870
  • 871
  • 872
  • 873
  • 874
  • 875
  • 876

3、下面是OpenlayerMap/index.ts的代码

import OpenLayerMap from "./index.vue"

export {
    OpenLayerMap
}
  • 1
  • 2
  • 3
  • 4
  • 5

4、这是我地图中用到的三张图片,chart.png是地图上弹窗的背景图。icon.png是个标点的小图标,剩下两个是地图画轨迹时一个起点和终点的图标,如果你粘贴我的代码,没这几张图片会报错
在这里插入图片描述
把几张图片分别给大家贴出来吧:
chart.png

在这里插入图片描述
endPoint.png
在这里插入图片描述
startPoint.png
请添加图片描述
icon.png
在这里插入图片描述

5、全局引入

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
//引入地图
import components from "@/components/index";
let app=createApp(App)
Object.values(components).forEach((com) => {
  app.use(com);
});
app.use(store).use(router).use(Antd).mount('#app')

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

6、页面代码

<template>
  <div class="Box">
    <div class="homeBox">
      <div class="leftBox">
        <a-button type="primary" @click="showIcon">在地图上显示点</a-button
        ><br /><br />
        <a-button type="primary" @click="moveXiAn([108.9423, 34.261])"
          >移动到西安钟楼</a-button
        ><br /><br />
        <a-button type="primary" @click="moveXiAn([108.8821, 34.2227])"
          >移动到初始点</a-button
        ><br /><br />
        <a-button type="primary" @click="trajectory">显示一段轨迹</a-button
        ><br /><br />
        <a-button type="primary" @click="clearTrajectory"
          >清除上面的轨迹</a-button
        ><br /><br />
        <a-button type="primary" @click="range">显示范围</a-button><br /><br />
      </div>
      <!-- 地图 -->
      <section class="map-wrap">
        <OpenlayerMap
          ref="mapRef"
          :assignMouseIndicatePosition="{
            zIndex: 1,
            right: '83px',
            top: '14px',
            fontSize: '16px',
            fontWeight: '400',
            color: '#fff',
          }"
        >
          <!-- 地图弹框 -->
          <template #right="sol">
            <div :style="{ width: '0vh' }"></div>
            <div>
              <div class="map_right" v-if="sol.value?.showLength">
                <div v-for="(item, l) in sol.value.show" :key="l">
                  <span v-for="(n, i) in item" :key="i">{{ n }}</span>
                </div>
                <button v-if="sol.value.button">
                  {{ sol.value.buttonText ? sol.value.buttonText : "查看" }}
                </button>
              </div>
              <div class="map_right" v-else>
                <span v-for="(n, i) in sol.value?.show" :key="i">{{ n }}</span>
                <button v-if="sol.value?.button">
                  {{ sol.value.buttonText ? sol.value.buttonText : "查看" }}
                </button>
              </div>
            </div>
          </template>
        </OpenlayerMap>
        <!-- 工具箱 -->
        <div class="work-box">
          <div class="tool">
            <div v-for="(n, i) in toolData" :key="i">
              <span>{{ n.title }}</span>
              <div>
                <span
                  :style="{ color: toolsindex == `${i}${l}` ? '#409EFF' : '' }"
                  v-for="(e, l) in n.data"
                  :key="l"
                  @click="clickTool(e, i, l)"
                  >{{ e.title }}</span
                >
              </div>
            </div>
          </div>
        </div>
      </section>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { defineComponent, reactive, ref, onMounted, nextTick } from "vue";
const mapRef = ref<null | HTMLElement>(null);

const data = ref<any>([
  {
    id: 14,
    name: "张三",
    longitude: "108.8821",
    latitude: "34.2227",
    pointList: [
      [108.8646, 34.2136],
      [108.8695, 34.2134],
      [108.8647, 34.2187],
    ],
  },
  {
    id: 14,
    name: "李四",
    longitude: "108.8867",
    latitude: "34.2283",
    pointList: [
      [108.8943, 34.2149],
      [108.8951, 34.2127],
      [108.8909, 34.2135],
      [108.8973, 34.2122],
    ],
  },
]);
const toolData = ref<any>([
  {
    title: "基础",
    key: 0,
    data: [
      { title: "测量距离" },
      { title: "测量面积" },
      { title: "清除测量" },
    ],
  },
  {
    title: "消防",
    key: 1,
    data: [
      { title: "画笔" },
      { title: "隔离带" },
      { title: "线选" },
      { title: "框选" },
      { title: "多边形选" },
      { title: "圈选" },
      { title: "清除" },
    ],
  },
]);
const toolsindex = ref<string>("");
//地图跳转
function moveXiAn(coordinate: any) {
  (mapRef.value as any).moveToPoint(...coordinate);
}
//显示轨迹
function trajectory() {
  let gis = [
    [108.9423, 34.261],
    [108.9424, 34.2568],
    [108.9478, 34.2566],
    [108.9538, 34.2496],
  ];
  (mapRef.value as any).showWay({
    id: 11, //id
    gis: gis,
    name: "轨迹", //
  });
}
function clearTrajectory() {
  (mapRef.value as any).clearRoute(11);
}
//地图上显示图标
function showIcon() {
  data.value.forEach((item: any) => {
    nextTick(() => {
      (mapRef.value as any).lastShowPoints(
        data.value,
        "icon.png",
        1,
        (item: any) => {
          return {
            show: [
              `${item.name}`,
              `纬度:${item.latitude},经度:${item.longitude}`,
            ],
            data: item,
            popupClass: "popup-box-right",
            bottom: "-13vh",
            left: "15px",
            button: true, //地图弹窗是否显示按钮
            buttonText: "点击", //地图弹窗按钮文字
            circle: true, //是否展示范围
          };
        }
      );
    });
  });
}

//地图上显示范围
function range() {
  nextTick(() => {
    (mapRef.value as any).groupPlot(data.value);
  });
}
//点击工具
function clickTool(n:any,i:number,l:number){
  if(toolsindex.value=='') toolsindex.value=`${i}${l}`; else {
    toolsindex.value='';
    nextTick(()=>{
      (mapRef.value as any).exportMap.removeInteraction((mapRef.value as any).draw);
      (mapRef.value as any).draw = null;
    });
  }
  switch (`${i}${l}`) {
    case '00': //测量距离
    if(toolsindex.value==`00`) (mapRef.value as any).measure("LineString");
      break;
    case '01': //测量面积
    if(toolsindex.value==`01`) (mapRef.value as any).measure("Polygon");
      break;
    case '02': //清除测量
    if(toolsindex.value==`02`) {
      for (const key in (mapRef.value as any).state.drawCache) {
        (mapRef.value as any).exportMap.removeOverlay(
          (mapRef.value as any).state.drawCache[key].measureTooltip
        );
      }
      (mapRef.value as any).exportDrawVector.getSource().clear();
      toolsindex.value =''
    }
      break;
    case "01": //测量距离
      if (toolsindex.value == `01`) (mapRef.value as any).measure("LineString");
      break;
    case "02": //测量面积
      if (toolsindex.value == `02`) (mapRef.value as any).measure("Polygon");
      break;
    case "03": //清除测量
      if (toolsindex.value == `03`) {
        for (const key in (mapRef.value as any).drawCache) {
          (mapRef.value as any).map.removeOverlay(
            (mapRef.value as any).drawCache[key].measureTooltip
          );
        }
        (mapRef.value as any).drawVector.getSource().clear();
        toolsindex.value = "";
      }
      break;
    case "10": //点
      if (toolsindex.value == `10`) (mapRef.value as any).drawLine(true);
      break;
    case "11": //正三角 隔离带
      if (toolsindex.value == `11`) (mapRef.value as any).drawCircle("triangle");
      break;
    case "12": //线
      if (toolsindex.value == `12`) (mapRef.value as any).drawLine(false);
      break;
    case "13": //正方形
      if (toolsindex.value == `13`) (mapRef.value as any).drawCircle("square");
      break;
    case "14": //多边形
      if (toolsindex.value == `14`) (mapRef.value as any).drawPolygon();
      break;
    case "15": //圆形
      if (toolsindex.value == `15`) (mapRef.value as any).drawCircle("circle");
      break;
    case '16': //清除
    if(toolsindex.value==`16`){     
      (mapRef.value as any).exportDrawVector.getSource().clear();
      toolsindex.value =''
    } break;
    default:
      break;
  }
  (mapRef.value as any).draw && (mapRef.value as any).draw.on("drawend", () => {
      (mapRef.value as any).exportMap.removeInteraction((mapRef.value as any).draw);
      (mapRef.value as any).draw = null;
      toolsindex.value = '';
    });
}

</script>
<style lang="scss" scoped>
.Box {
  width: 100%;
  height: 100vh;
  position: relative;
  .homeBox {
    width: 100%;
    height: 100%;
    border: 1px solid gray;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    .leftBox {
      width: 20%;
    }
    .map-wrap {
      flex: 1;
      height: 100%;
      position: relative;
    }
  }
}

//地图弹窗样式
.map_right {
  color: #fff;
  font-size: 14px;
  padding: 15px 20px;
  display: flex;
  flex-direction: column;
  span:nth-child(n) {
    display: flex;
    flex-direction: column;
    margin-bottom: 10px;
    white-space: nowrap;
  }
  span:nth-child(1) {
    font-size: 16px;
    font-weight: 500;
    margin-top: 10px;
  }
  > button {
    // color: #409EFF;
    background: #409eff;
    text-align: center !important;
    padding: 6px 0;
    border: none;
    margin: 10px 16px 20px 16px;
    cursor: pointer;
  }
}
.work-box {
  display: flex;
  align-items: center;
  color: #fff;
  position: absolute;
  bottom: 60px;
  left: 30px;
  .tool {
    position: absolute;
    // bottom: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    border: 1px solid;
    margin: 0 20px;
    background: gray;
    border-radius: 5px;
    > * {
      padding: 0 10px;
      display: flex;
      width: 510px;
      align-items: center;
      > span {
        font-size: 16px;
        font-weight: 700;
      }
      > div:first-child {
        border-bottom: 1px solid;
      }
      > div {
        margin: 3px 10px;
        display: flex;
        flex: 1;
        justify-content: space-around;
        span {
          display: inline-block;
          padding: 8px;
          border: 1px solid;
          cursor: pointer;
          margin: 3px 5px;
          font-size: 14px;
          border-radius: 5px;
        }
      }
    }
  }
}
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/607446
推荐阅读
相关标签
  

闽ICP备14008679号