在vue中如何获取项目src外层的config目录以及api接口proxy的target代理地址

一、获取config目录

因为后端proxy接口是放置在src外面的config目录中的,如果要方便获取,可以设置类似于用@代表src一样的路径别名。

找到 webpack配置目录,比如:webpack.base.conf.js,添加如下注释代码

resolve: {
    extensions: [".js", ".vue", ".json"],
    alias: {
      "@": resolve("src"),
      "#": resolve("config") //新增用#代替config文件夹
    }
  },

二、获取接口proxy代理地址

需求是某个接口需要服务器的hostnameport,这时就需要知道后端代理地址。比如下方的target地址。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

proxyTable的target地址

1、在需要获取地址的页面导入该文件

import API_CONFIG from "#/index.js";  //#即为第一步配置的config文件夹的别名

2、继续获取target地址

// 如果是开发环境
if (process.env.NODE_ENV == "development") {
		//将得到的target地址分割成数组
    let api = API_CONFIG.dev.proxyTable["/base"].target.split("/");
    this.form.hostName = api[0] + "//" + api[2];
  } else {
		//如果是生产环境
    this.form.hostName = location.protocol + "//" + location.host;
  }

如下是在生产环境中获取后的地址和环境变量打印出来的值:
环境变量打印出来的值

如果你对web前端开发、面试感兴趣的话可以加V:imqdcnn。群里有各种学习资源发放,免费答疑,更有行业深潜多年的技术牛人分析讲解。

祝你能成为一名优秀的WEB前端开发工程师!

<template> <template v-if="videoPlayList.length"> <template v-for="(item, index) in videoPlayList"> <VideosPlay :data="item" :index="index" /> </template> </template> <div class="box"> <div class="top-select"> <el-select v-model="selectedLayer" placeholder="影像图层" class="select-1" :show-arrow="false" clearable @change="handleLayerChange" @clear="clearLayer" > <el-option v-for="(item, index) in layers" :key="item.id" :label="item.title" :value="item.id" /> </el-select> <el-select v-model="baseMap" placeholder="矢量地图" :show-arrow="false" class="select-2" @change="handleBaseMapChange" value-key="id" multiple collapse-tags > <el-option v-for="item in baseMapList" :key="item.name" :label="item.name" :value="item" /> </el-select> <el-select v-model="selectedTile" placeholder="实景三维" class="select-2" @change="handle3dSwitchChange" multiple collapse-tags :show-arrow="false" value-key="id" > <el-option v-for="tile in tileList" :key="tile.id" :label="tile.title" :value="tile" /> </el-select> <el-select v-model="selectedCommunity" placeholder="动态监测" class="select-3" @change="handleCommunityChange" :show-arrow="false" > <el-option v-for="community in communityList" :key="community.name" :label="community.name" :value="community.name" /> </el-select> </div> </div> <!-- 坐标系转换弹窗 --> <el-dialog v-model="showCoordinateModal" title="坐标系转换" width="400px" @close="resetCoordinateForm" > <el-form :model="coordForm" label-width="100px"> <!-- 源坐标系下拉菜单 --> <el-form-item label="源坐标系"> <el-select v-model="coordForm.source" placeholder="请选择源坐标系" clearable class="coord-select" > <el-option label="WGS84" value="WGS84"></el-option> <el-option label="GCJ02(火星)" value="GCJ02"></el-option> <el-option label="BD09(百度)" value="BD09"></el-option> </el-select> </el-form-item> <!-- 目标坐标系下拉菜单 --> <el-form-item label="目标坐标系"> <el-select v-model="coordForm.target" placeholder="请选择目标坐标系" clearable class="coord-select" > <el-option label="WGS84" value="WGS84"></el-option> <el-option label="GCJ02(火星)" value="GCJ02"></el-option> <el-option label="BD09(百度)" value="BD09"></el-option> </el-select> </el-form-item> <el-form-item label="经度"> <el-input v-model.number="coordForm.lng" placeholder="输入经度" clearable ></el-input> </el-form-item> <el-form-item label="纬度"> <el-input v-model.number="coordForm.lat" placeholder="输入纬度" clearable ></el-input> </el-form-item> <el-form-item label="转换结果"> <el-input :value="coordForm.result" readonly placeholder="转换结果将显示在这里" ></el-input> </el-form-item> </el-form> <template #footer> <el-button @click="showCoordinateModal = false">取消</el-button> <el-button type="primary" @click="convertCoordinates">转换</el-button> </template> </el-dialog> </template> <script setup lang="ts"> import { onMounted, ref, onUnmounted } from "vue"; import { $prototype } from "../../main.ts"; import { getVeidoDetail } from "@/service/index"; import { ElMessage } from "element-plus"; import MVTImageryProvider from "mvt-imagery-provider"; import "/public/lib/video/mpegts/mpegts.js"; import "/public/img/div-graphic/divGraphic.css"; import { vectorLayes } from "@/config/index.ts"; import VideosPlay from "@/components/video/index.vue"; import { RefreshLeft } from "@element-plus/icons-vue"; var viewer: any; const selectedLayer = ref("baseImagery"); const selectedTile = ref([]); const selectedCommunity = ref(""); const baseMap = ref([]); const videoPlayList = ref([]); const addedTilesets = ref<Record<string, Cesium.Cesium3DTileset[]>>({}); const addedMvtLayers = ref<Record<string, Cesium.ImageryLayer[]>>({}); // 坐标系转换相关 const showCoordinateModal = ref(false); const coordForm = ref({ source: "", // 源坐标系 target: "", // 目标坐标系 lng: 0, // 经度 lat: 0, // 纬度 result: "" // 转换结果 }); const layers = [ { id: "baseImagery", title: "卫星" }, { id: "zhuzhou_beidou:GF01", title: "高分1号卫星遥感影像" }, { id: "zhuzhou_beidou:GF02", title: "高分2号卫星遥感影像" }, { id: "zhuzhou_beidou:GF06", title: "高分6号卫星遥感影像" }, { id: "zhuzhou_beidou:GF07", title: "高分7号卫星遥感影像" }, { id: "zhuzhou_beidou:lkyx", title: "渌口区影像" }, ]; const tileList = [ { id: "tile1", url: [ "http://124.232.190.30:9000/proxy/pk1725973637070/map/3dmode/20220312-1302/tileset.json", "http://124.232.190.30:9000/proxy/pk1725973591120/map/3dmode/20220312-1301/tileset.json", "http://124.232.190.30:9000/proxy/pk1725973529125/map/3dmode/2022022101/tileset.json", "http://124.232.190.30:9000/proxy/pk1725973404863/map/3dmode/2022011302/tileset.json", "http://124.232.190.30:9000/proxy/pk1725973226672/map/3dmode/20220312/tileset.json", "http://124.232.190.30:9000/proxy/pk1725952405569/map/3dmode/20220221/tileset.json", "http://124.232.190.30:9000/proxy/pk1725952315227/map/3dmode/20220220/tileset.json", ], title: "会展中心", }, { id: "tile2", url: [ "http://124.232.190.30:9000/proxy/pk1725804650206/map/3dmode/hhhg/tileset.json", ], title: "园区", }, ]; const communityList = [ { name: "铁塔视频" }, ]; const baseMapList = [ { id: "geomeg", name: "基础地图", url: "http://124.232.190.30:3011//yjy_pbf/{z}/{x}/{y}.pbf", type: "fill" }, { id: "lukou_farmland", name: "耕地", url: "http://124.232.190.30:9059/lukou_farmland/{z}/{x}/{y}", type: "fill" }, { id: "lukou_ecology", name: "生态", url: "http://124.232.190.30:9059/lukou_ecology/{z}/{x}/{y}", type: "fill" }, { id: "natural_", name: "自然区", url: "http://124.232.190.30:9059/natural_/{z}/{x}/{y}", type: "fill" }, { id: "lushui_river", name: "渌水流域", url: "http://124.232.190.30:9059/lushui_river/{z}/{x}/{y}", type: "fill" }, { id: "mishui_river", name: "洣水流域", url: "http://124.232.190.30:9059/mishui_river/{z}/{x}/{y}", type: "fill" }, ]; const sprite = "http://124.232.190.67:5432/sprite/sprite"; const glyphs = "http://124.232.190.67:5432/font/mapbox_glyphs/{fontstack}/{range}.pbf"; const baseMapUrl = "http://124.232.190.30:3011//yjy_pbf/layers.json"; // 坐标系转换工具类 const CoordinateConverter = { a: 6378245.0, ee: 0.006693421622965943, // 判断是否在国内 outOfChina(lng: number, lat: number): boolean { return (lng < 72.004 || lng > 137.8347) || (lat < 0.8293 || lat > 55.8271); }, // 纬度转换 transformLat(x: number, y: number): number { let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0; ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0; ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0; return ret; }, // 经度转换 transformLng(x: number, y: number): number { let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0; ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0; ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0; return ret; }, // WGS84转GCJ02 wgs84ToGcj02(lng: number, lat: number): [number, number] { if (this.outOfChina(lng, lat)) return [lng, lat]; let dLat = this.transformLat(lng - 105.0, lat - 35.0); let dLng = this.transformLng(lng - 105.0, lat - 35.0); const radLat = lat / 180.0 * Math.PI; let magic = Math.sin(radLat); magic = 1 - this.ee * magic * magic; const sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((this.a * (1 - this.ee)) / (magic * sqrtMagic) * Math.PI); dLng = (dLng * 180.0) / (this.a / sqrtMagic * Math.cos(radLat) * Math.PI); return [lng + dLng, lat + dLat]; }, // GCJ02转WGS84 gcj02ToWgs84(lng: number, lat: number): [number, number] { if (this.outOfChina(lng, lat)) return [lng, lat]; let dLat = this.transformLat(lng - 105.0, lat - 35.0); let dLng = this.transformLng(lng - 105.0, lat - 35.0); const radLat = lat / 180.0 * Math.PI; let magic = Math.sin(radLat); magic = 1 - this.ee * magic * magic; const sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((this.a * (1 - this.ee)) / (magic * sqrtMagic) * Math.PI); dLng = (dLng * 180.0) / (this.a / sqrtMagic * Math.cos(radLat) * Math.PI); const mgLat = lat + dLat; const mgLng = lng + dLng; return [lng * 2 - mgLng, lat * 2 - mgLat]; }, // GCJ02转BD09 gcj02ToBd09(lng: number, lat: number): [number, number] { const x = lng; const y = lat; const z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * Math.PI * 3000.0 / 180.0); const theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * Math.PI * 3000.0 / 180.0); return [z * Math.cos(theta) + 0.0065, z * Math.sin(theta) + 0.006]; }, // BD09转GCJ02 bd09ToGcj02(lng: number, lat: number): [number, number] { const x = lng - 0.0065; const y = lat - 0.006; const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * Math.PI * 3000.0 / 180.0); const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * Math.PI * 3000.0 / 180.0); return [z * Math.cos(theta), z * Math.sin(theta)]; }, // WGS84转BD09 wgs84ToBd09(lng: number, lat: number): [number, number] { const [gcjLng, gcjLat] = this.wgs84ToGcj02(lng, lat); return this.gcj02ToBd09(gcjLng, gcjLat); }, // BD09转WGS84 bd09ToWgs84(lng: number, lat: number): [number, number] { const [gcjLng, gcjLat] = this.bd09ToGcj02(lng, lat); return this.gcj02ToWgs84(gcjLng, gcjLat); } }; // 执行坐标系转换 function convertCoordinates() { const { source, target, lng, lat } = coordForm.value; // 验证输入 if (!source || !target) { ElMessage.warning('请选择源坐标系和目标坐标系'); return; } if (source === target) { ElMessage.info('源坐标系与目标坐标系相同,无需转换'); coordForm.value.result = `经度: ${lng.toFixed(6)}, 纬度: ${lat.toFixed(6)}`; return; } if (!lng || !lat || isNaN(lng) || isNaN(lat)) { ElMessage.warning('请输入有效的经纬度'); return; } if (lng < -180 || lng > 180 || lat < -90 || lat > 90) { ElMessage.warning('经纬度超出有效范围'); return; } // 执行转换 let result: [number, number] = [0, 0]; switch (true) { case source === "WGS84" && target === "GCJ02": result = CoordinateConverter.wgs84ToGcj02(lng, lat); break; case source === "GCJ02" && target === "WGS84": result = CoordinateConverter.gcj02ToWgs84(lng, lat); break; case source === "GCJ02" && target === "BD09": result = CoordinateConverter.gcj02ToBd09(lng, lat); break; case source === "BD09" && target === "GCJ02": result = CoordinateConverter.bd09ToGcj02(lng, lat); break; case source === "WGS84" && target === "BD09": const gcj = CoordinateConverter.wgs84ToGcj02(lng, lat); result = CoordinateConverter.gcj02ToBd09(gcj[0], gcj[1]); break; case source === "BD09" && target === "WGS84": const gcj2 = CoordinateConverter.bd09ToGcj02(lng, lat); result = CoordinateConverter.gcj02ToWgs84(gcj2[0], gcj2[1]); break; default: ElMessage.error("不支持的转换类型"); return; } coordForm.value.result = `经度: ${result[0].toFixed(6)}, 纬度: ${result[1].toFixed(6)}`; } // 重置转换表单 function resetCoordinateForm() { coordForm.value = { source: "", target: "", lng: 0, lat: 0, result: "" }; } // 基础地图切换处理 function handleBaseMapChange(items: any) { const currentSelectedIds = items.map((item: any) => item.id); const mvtsToRemove = Object.keys(addedMvtLayers.value).filter( (mvtId) => !currentSelectedIds.includes(mvtId) ); mvtsToRemove.forEach((mvtId) => { const layersToRemove = addedMvtLayers.value[mvtId]; if (layersToRemove && layersToRemove.length > 0) { layersToRemove.forEach((layer) => { try { const layers = viewer.imageryLayers._layers; for (let i = layers.length - 1; i >= 0; i--) { if (layers[i]._imageryProvider?.id === mvtId) { viewer.imageryLayers.remove(layers[i]); } } } catch (e) { console.error("Error removing MVT layer:", e); } }); delete addedMvtLayers.value[mvtId]; } }); items.forEach((item: any) => { if (!addedMvtLayers.value[item.id] || addedMvtLayers.value[item.id].length === 0) { addedMvtLayers.value[item.id] = []; loadVectorMvt(item.url, item.id, item.type); } }); } // 视频关闭事件监听 $prototype.emitter.on("video-list-play-close", (_id) => { videoPlayList.value = videoPlayList.value.filter((v) => v.id != _id); }); // 加载矢量地图 async function loadVectorMvt(data, layerName, type) { var tt = { name: "maplibres_yw", type: "vector", tiles: [data], bounds: [-180, -85.051129, 180, 85.051129], scheme: "xyz", }; var layersMapbox = []; const sourcesMapbox: any = {}; if (layerName == "geomeg") { await fetch(baseMapUrl) .then((response) => response.json()) .then((data) => { layersMapbox = JSON.parse(JSON.stringify(data.layers)); }); } else if (vectorLayes[layerName] == undefined) { const currentLayers = JSON.parse(JSON.stringify(vectorLayes[layerName])); currentLayers["id"] = currentLayers["id"] + layerName; currentLayers["source-layer"] = layerName; currentLayers["source"] = layerName; layersMapbox.push(currentLayers); } else { layersMapbox = JSON.parse(JSON.stringify(vectorLayes[layerName])); } sourcesMapbox[layerName] = tt; var exampleStyle = { id: data.id, name: "MapLibre", zoom: 10, layers: layersMapbox, bearing: 0, sources: sourcesMapbox, version: 8, metadata: { "maptiler:copyright": "cxwl" }, }; exampleStyle.glyphs = glyphs; exampleStyle.sprite = sprite; let provider = new MVTImageryProvider({ style: exampleStyle }); provider.id = layerName; viewer.imageryLayers.addImageryProvider(provider); addedMvtLayers.value[layerName].push(provider); if (layerName === "lukou_farmland" || layerName === "lukou_ecology") { viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(113.159047, 27.721148, 3270), duration: 3, }); } else { viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(113.490927, 27.048641, 406000), duration: 3, }); } } // 动态监测处理 var videoData = [113.182301, 27.971201]; async function handleCommunityChange(item: any) { if (item == "铁塔视频") { var data = await getVeidoDetail(); if (data.data != null) { addRandomGraphicByCount(videoData, data.data); } else { ElMessage.error(data.message); } } } // 添加铁塔标记 function addRandomGraphicByCount(position, url) { viewer.entities.add({ id: "tietaId", beof: "铁塔视频", name: "铁塔视频001", position: Cesium.Cartesian3.fromDegrees(position[0], position[1]), billboard: { image: "img/marker/mark-spjk.png", width: 30, height: 115, scale: 1.0, color: Cesium.Color.WHITE, eyeOffset: new Cesium.Cartesian3(0, 0, -10), }, label: { text: "铁塔视频", font: "14px sans-serif", fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 2, style: Cesium.LabelStyle.FILL_AND_OUTLINE, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, pixelOffset: new Cesium.Cartesian2(0, -30), }, properties: { capacityResourceName: "铁塔视频", url: url, name: "铁塔视频", id: "tieta_001", }, }); viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(position[0], position[1], 10000), duration: 3, }); } // 3D模型切换处理 function handle3dSwitchChange(items: any) { const currentSelectedIds = items.map((item: any) => item.id); const tilesToRemove = Object.keys(addedTilesets.value).filter( (tileId) => !currentSelectedIds.includes(tileId) ); tilesToRemove.forEach((tileId) => { addedTilesets.value[tileId].forEach((tileset) => { try { if (tileset && !tileset.isDestroyed()) { tileset.destroy(); } viewer.scene.primitives.remove(tileset); } catch (e) { console.error("Error removing tileset:", e); } }); delete addedTilesets.value[tileId]; }); items.forEach((item: any) => { if (!addedTilesets.value[item.id]) { addedTilesets.value[item.id] = []; item.url.forEach((url: string) => { const tileset = new Cesium.Cesium3DTileset({ url: url, skipLevelOfDetail: true, skipScreenSpaceErrorFactor: 16, baseScreenSpaceError: 1024, maximumScreenSpaceError: 10, immediatelyLoadDesiredLevelOfDetail: false, loadSiblings: false, cullWithChildrenBounds: true, cullRequestsWhileMoving: true, cullRequestsWhileMovingMultiplier: 10, preloadWhenHidden: true, preferLeaves: true, maximumMemoryUsage: 2048, progressiveResolutionHeightFraction: 0.5, dynamicScreenSpaceErrorDensity: 0.5, dynamicScreenSpaceErrorFactor: 1, dynamicScreenSpaceError: false, }); var heightOffset = 0; if (url.indexOf("20220220") >= 0) heightOffset = -32; else if (url.indexOf("2022022101") >= 0) heightOffset = -50.4; tileset.readyPromise .then((palaceTileset) => { viewer.scene.primitives.add(palaceTileset); addedTilesets.value[item.id].push(palaceTileset); const boundingSphere = palaceTileset.boundingSphere; const cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center); const surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0); const offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, heightOffset); const translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3()); palaceTileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation); viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromRadians( cartographic.longitude, cartographic.latitude, heightOffset + 10000 ), duration: 3, }); }) .catch((error) => { console.error("Error loading tileset:", error); }); }); } }); } // 影像图层切换处理 var currentImageryLayer: Cesium.ImageryLayer | null = null; var src; function handleLayerChange(val: any) { if (currentImageryLayer) { viewer.imageryLayers.remove(currentImageryLayer); currentImageryLayer = null; } if (!val) return; if (val === "baseImagery") { addImage(val); } if (val === "zhuzhou_beidou:GF07" || val === "zhuzhou_beidou:lkyx") { src = "EPSG:4326"; } else if (val !== "baseImagery") { src = "EPSG:4326x2"; } var imageryProvider = new Cesium.WebMapTileServiceImageryProvider({ url: "http://124.232.190.14:3013/geoserver/gwc/service/wmts", layer: val, format: "image/png", style: "", tileMatrixSetID: src, maximumLevel: 18, tilingScheme: new Cesium.GeographicTilingScheme({ numberOfLevelZeroTilesX: 2, numberOfLevelZeroTilesY: 1, }), tileMatrixLabels: [...Array(18).keys()].map((level) => (src + ":" + level).toString() ), }); currentImageryLayer = viewer.imageryLayers.addImageryProvider(imageryProvider); currentImageryLayer.id = val; } // 添加基础影像 async function addImage(val: any) { var rightImageProvider = new Cesium.UrlTemplateImageryProvider({ name: "影像图", type: "xyz", layer: val, url: "http://124.232.190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png", minimumLevel: 1, maximumLevel: 17, crs: "EPSG:3857", }); currentImageryLayer = viewer.imageryLayers.addImageryProvider(rightImageProvider); currentImageryLayer.id = val; rightImageProvider.splitDirection = Cesium.SplitDirection.right; } // 清除影像图层 function clearLayer() { if (currentImageryLayer) { viewer.imageryLayers.remove(currentImageryLayer); currentImageryLayer = null; } selectedLayer.value = ""; } // 组件挂载 onMounted(async () => { viewer = $prototype.$map; await addImage("baseImagery"); const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); const scene = $prototype.$map.scene; const ellipsoid = scene.globe.ellipsoid; handler.setInputAction(function (click) { const pick = $prototype.$map.scene.pick(click.position); const cartesians = $prototype.$map.camera.pickEllipsoid(click.position, ellipsoid); var data = null; if (cartesians) { const cartographic = ellipsoid.cartesianToCartographic(cartesians); const longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6); const latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6); data = { longitude: longitude, latitude: latitude }; console.log(longitude + "," + latitude); } if (pick && pick.primitive._imageId != undefined && pick.primitive._imageId.indexOf("mark-spjk") >= 0) { var obj = pick.id._properties; videoPlayList.value.push({ name: obj.name, url: obj.url, id: obj.id }); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); }); // 组件卸载 onUnmounted(() => { Object.values(addedTilesets.value).forEach((tilesets) => { tilesets.forEach((tileset) => { viewer.scene.primitives.remove(tileset); }); }); addedTilesets.value = {}; }); </script> <style lang="scss" scoped> .box { position: absolute; top: 15%; right: 80px; overflow: hidden; } .top-select { display: flex; align-items: center; justify-content: center; gap: 0px; } .select-1, .select-2, .select-3 { background: linear-gradient(180deg, #00f0f87f 10%, #173c6a 100%); border-radius: 2px; border: 1px solid #00f0f87f; } .select-1 { width: 110px; border-radius: 5px 0 0 5px; } .select-2 { flex: 1; width: 90px; } .select-3 { flex: 1; width: 180px; } /* 坐标系转换按钮样式 */ .coordinate-btn { background: linear-gradient(180deg, #00f0f87f 10%, #173c6a 100%); border: 1px solid #00f0f87f; color: #b4fdff; border-radius: 0 5px 5px 0; padding: 0 15px; display: flex; align-items: center; gap: 5px; &:hover { background: linear-gradient(180deg, #00f0f8 10%, #173c6a 100%); color: #fff; box-shadow: 0 0 10px rgba(0, 240, 248, 0.5); } } /* 自定义Element组件样式 */ :deep(.el-select__wrapper) { background: transparent !important; box-shadow: none !important; } :deep(.el-select__caret) { color: #3cffff; } :deep(.el-select__placeholder), :deep(.el-select__selected-item), :deep(.el-select-dropdown__item) { color: #b4fdff !important; } :deep(.el-tag.el-tag--info) { --el-tag-bg-color: #3cffff96 !important; } /* 确保下拉菜单正常显示 */ :deep(.el-select-dropdown) { display: block !important; background: rgba(1, 28, 82, 0.8) !important; border: 1px solid #00f0f87f !important; z-index: 9999 !important; } :deep(.el-select-dropdown__item) { color: #b4fdff !important; &:hover { background: rgba(0, 240, 248, 0.2) !important; } &.selected { background: rgba(0, 240, 248, 0.3) !important; } } </style> <style lang="scss"> /* 全局样式保持不变 */ .el-select-dropdown__item { color: #b4fdff !important; } .el-select__popper.el-popper { border: 1px solid #3f3f41 !important; background: rgba(1, 28, 82, 0.8) !important; } .el-select-dropdown { border: none !important; background: rgba(1, 28, 82, 0.8) !important; &::-webkit-scrollbar { width: 6px; height: 6px; } &::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.1); border-radius: 3px; } &::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.3); border-radius: 3px; &:hover { background: rgba(255, 255, 255, 0.4); } } } .el-select-dropdown__item.is-hovering { border: none !important; background: rgba(1, 28, 82, 0.8) !important; } .is-focus .el-select__wrapper { box-shadow: none !important; } /* ================= 坐标系转换弹窗样式优化 ================= */ .coordinate-dialog { .el-dialog__headerbtn .el-dialog__close { color: #b4fdff !important; &:hover { color: #fff !important; } } /* 内容区域样式 */ .el-dialog__body { padding: 20px; background: transparent; } /* 表单样式 */ .coord-form { .el-form-item { margin-bottom: 20px; } .el-form-item__label { color: #b4fdff; font-weight: bold; } /* 输入框样式 */ .el-input { .el-input__wrapper { background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(0, 240, 248, 0.5); box-shadow: 0 0 5px rgba(0, 240, 248, 0.2) inset; color: #b4fdff; border-radius: 4px; transition: all 0.3s; &:hover { border-color: #00f0f8; box-shadow: 0 0 8px rgba(0, 240, 248, 0.4) inset; } &.is-focus { border-color: #00f0f8; box-shadow: 0 0 12px rgba(0, 240, 248, 0.6) inset; } } .el-input__inner { color: #b4fdff; &::placeholder { color: rgba(180, 253, 255, 0.6); } } } /* 结果输入框特殊样式 */ .el-form-item:last-child .el-input__wrapper { background: rgba(0, 240, 248, 0.1) !important; border: 1px solid rgba(0, 240, 248, 0.8) !important; } } /* 底部按钮区域 */ .el-dialog__footer { padding: 15px 20px; background: linear-gradient(90deg, rgba(23, 60, 106, 0.5), rgba(0, 240, 248, 0.2)); border-top: 1px solid rgba(0, 240, 248, 0.3); border-radius: 0 0 8px 8px; } /* 按钮样式 */ .cancel-btn { background: transparent; border: 1px solid rgba(0, 240, 248, 0.5); color: #b4fdff; &:hover { background: rgba(0, 240, 248, 0.2); border-color: #00f0f8; color: #fff; } } .convert-btn { background: linear-gradient(90deg, rgba(0, 240, 248, 0.7), rgba(23, 60, 106, 0.9)); border: none; color: #fff; font-weight: bold; box-shadow: 0 0 10px rgba(0, 240, 248, 0.5); &:hover { background: linear-gradient(90deg, rgba(0, 240, 248, 0.9), rgba(23, 60, 106, 1)); box-shadow: 0 0 15px rgba(0, 240, 248, 0.7); transform: translateY(-1px); } &:active { transform: translateY(1px); } } } </style>如上所示代码,其中我想知道卫星,矢量地图这些是使用了element的哪些组件布局,
最新发布
07-13
<think>我们观察代码中的布局部分,主要使用了Element Plus的以下组件进行布局: 1. **el-select**:用于下拉选择框,用于选择影像图层、矢量地图、实景三维和动态监测。 2. **el-option**:作为el-select的下拉选项。 3. **el-dialog**:用于坐标系转换的弹窗。 4. **el-form** 和 **el-form-item**:在弹窗中用于构建表单,包含下拉菜单和输入框。 5. **el-input**:在表单中用于输入经度和纬度。 6. **el-button**:在弹窗底部用于取消和转换操作。 布局结构如下: - 最外层是`<template>`,其中包含: - 一个条件渲染的`<template v-if="videoPlayList.length">`,用于循环渲染视频播放组件。 - 一个`<div class="box">`,里面包含一个`<div class="top-select">`,这个div中并列放置了四个`el-select`组件,分别对应: - 影像图层(卫星) - 矢量地图 - 实景三维 - 动态监测 - 一个坐标系转换的弹窗(`el-dialog`) 在样式中,通过CSS对位置和样式进行了调整,例如将选择框组定位在右上角,并设置了背景、边框等样式。 具体到每个选择框: - 影像图层:`el-select`,v-model绑定`selectedLayer` - 矢量地图:`el-select`,v-model绑定`baseMap`,多选 - 实景三维:`el-select`,v-model绑定`selectedTile`,多选 - 动态监测:`el-select`,v-model绑定`selectedCommunity` 在弹窗中,使用`el-form`构建表单,每个表单项(`el-form-item`)包含一个标签和一个输入组件(`el-select`或`el-input`)。 因此,主要使用的Element Plus组件有:Select选择器、Option选项、Dialog对话框、Form表单、FormItem表单项、Input输入框、Button按钮。 布局方式:通过flex布局将四个选择器水平排列,通过绝对定位将整个选择框组定位在右上角。 §§相关问题§§: 1.Vue中如何实现多个el-select组件的水平排列? 2. 如何通过绝对定位将元素固定在页面的右上角? 3. 在Element Plus中,如何自定义el-select的下拉框样式? 4.Vue中,如何实现弹窗表单的数据绑定和验证?</think>从提供的代码来看,"卫星"、"矢量地图"、"实景三维"和"动态监测"这四个功能模块主要使用了以下 Element Plus 组件进行布局: ### 主要使用的 Element Plus 组件: 1. **`<el-select>` 选择器组件** - 用于创建下拉选择框 - 每个功能模块对应一个独立的 `el-select` 组件 - 关键属性: ```vue v-model="selectedLayer" // 影像图层(卫星) v-model="baseMap" // 矢量地图 v-model="selectedTile" // 实景三维 v-model="selectedCommunity" // 动态监测 ``` 2. **`<el-option>` 选项组件** - 作为 `el-select` 的下拉选项 - 每个选项对应一个功能项 - 示例: ```vue <el-option v-for="(item, index) in layers" :key="item.id" :label="item.title" :value="item.id" /> ``` 3. **`<el-dialog>` 对话框组件** - 用于坐标系转换功能 - 包含表单元素 4. **表单组件**(在对话框内): - `<el-form>` 表单容器 - `<el-form-item>` 表单项 - `<el-input>` 输入框 ### 布局结构分析: ```html <div class="box"> <div class="top-select"> <!-- 影像图层(卫星) --> <el-select v-model="selectedLayer" placeholder="影像图层"> <el-option v-for="(item, index) in layers" ... /> </el-select> <!-- 矢量地图 --> <el-select v-model="baseMap" placeholder="矢量地图" multiple> <el-option v-for="item in baseMapList" ... /> </el-select> <!-- 实景三维 --> <el-select v-model="selectedTile" placeholder="实景三维" multiple> <el-option v-for="tile in tileList" ... /> </el-select> <!-- 动态监测 --> <el-select v-model="selectedCommunity" placeholder="动态监测"> <el-option v-for="community in communityList" ... /> </el-select> </div> </div> <!-- 坐标系转换弹窗 --> <el-dialog v-model="showCoordinateModal" title="坐标系转换"> <el-form ...> <el-form-item ...> <el-select ...> ... </el-select> </el-form-item> </el-form> </el-dialog> ``` ### 关键布局特点: 1. **Flex 水平布局** 通过 CSS 实现四个选择器的水平排列: ```css .top-select { display: flex; align-items: center; justify-content: center; gap: 0px; } ``` 2. **差异化样式** 每个选择器有独立的样式类控制外观: ```css .select-1 { /* 影像图层 */ } .select-2 { /* 矢量地图 & 实景三维 */ } .select-3 { /* 动态监测 */ } ``` 3. **多选支持** 矢量地图和实景三维支持多选: ```vue <el-select multiple collapse-tags> ``` 4. **响应式设计** 使用弹性宽度适应不同内容: ```css .select-1 { width: 110px; } .select-2 { flex: 1; width: 90px; } .select-3 { flex: 1; width: 180px; } ``` 5. **定位控制** 整体容器固定在右上角: ```css .box { position: absolute; top: 15%; right: 80px; } ``` ### 功能与组件对应关系: | 功能模块 | 组件 | 数据源 | 关键特性 | |------------|--------------------|-----------------|-----------------------| | 影像图层 | `el-select` | `layers` | 单选框,卫星影像切换 | | 矢量地图 | `el-select` | `baseMapList` | 多选框,支持折叠标签 | | 实景三维 | `el-select` | `tileList` | 多选框,3D模型加载 | | 动态监测 | `el-select` | `communityList` | 单选框,视频监控管理 | | 坐标系转换 | `el-dialog`+表单 | - | 弹窗式坐标转换工具 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值