LeafletJS 简单使用1 - 地图标点 L.marker()、清除标点 layerGroup.clearLayers() 【SuperMap iClient for Leaflet】超图的使用
【1】超图的使用、SuperMap 超图 vue.config.js 打包配置(ES6语法转换)。【2】Uncaught SyntaxError: Unexpected token ... 报错:语法错误;Cannot assign to read only property 'export' of object '报错:babel.config.js配置sourceType;SyntaxErro
·
目录
一、业务需求
- 展示出地图,并在指定的经纬度展示对应的图标,点击图标展示详细信息
- 有搜索功能,进行搜索时,重新根据搜索后的数据在地图进行标点
二、参考文档
地图开发商提供的文档(该文档中API是地图厂商基于 LeafletJS 封装的他们 gis 超图用到的 API _ 最终要在内网中使用该文档类似的只能内网用的文档进行开发 _ 内网不能访问互联网的地址)
LeafJS 参考文档
三、实现思路
- 在 vue 项目中实现,首先下载依赖
①npm install @supermap/iclient-leaflet
: 超图依赖(地图厂商自己的 _ 版本 11.0.1)
②npm install leaflet
:LeafletJS 依赖(不用下载,下载超图依赖的时候会自动带上该依赖) - 生成一张地图(设置中心点、最大缩放级别、当前缩放级别等等)
- 根据搜索获取的数据中 经纬度 和 标点图标 在地图上进行标点
- 搜索数据时,先将所有标点清除,然后根据搜索后的数据重新进行标点
四、参考代码
4.1 安装依赖
npm install @supermap/iclient-leaflet
4.2 生成一张地图
-
html 中要有一个放地图的盒子
<div id="map"></div>
#map { position: absolute; top: 0; bottom: 0; width: calc(100% - 20px); border: 2px solid red; // 调页面添加的样式,看的清晰一点,之后会去掉 }
-
public/index.html 中引入 css 文件
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.css" /> <link rel="stylesheet" href="https://iclient.supermap.io/dist/leaflet/iclient-leaflet.min.css" />
以上导入 css 文件办法有点麻烦,直接在需要使用到css文件的页面中导入 leaflet 依赖中的 css 即可
import 'leaflet/dist/leaflet.css'
【注意】一定要记得引入 css 文件,不然地图出来的瓦片不全,并且瓦片拼接很乱
-
导入依赖
import L from 'leaflet' import 'leaflet/dist/leaflet.css' import { tiledMapLayer } from '@supermap/iclient-leaflet'
-
生成一张地图
var url = 'https://iserver.supermap.io/iserver/services/map-china400/rest/maps/China' // var url = 'https://iserver.supermap.io/iserver/services/map-china400/rest/maps/China_4326' // var url = 'https://iserver.supermap.io/iserver/services/map-china400/rest/maps/ChinaDark' this.map = L.map('map', { // this.map初始值为 null center: [22.822074, 108.371154], // 中心点[经度, 纬度] maxZoom: 18, // 最大层级 zoom: 11 // 当前层级 }) tiledMapLayer(url).addTo(this.map) // 添加地图(tiledMapLayer() 方法是地图厂商自己封装的,我们也可以用 LeafletJS 自己的方法进行地图的添加)
-
地图初步展示
4.3 标点_自定义标点图标
- 进行标点_初步实现
/**** 标记图标 start ****/ var marker = L.marker([22.822074, 108.371154], { // L.marker([纬度, 经度], {}) // 此处数据之后在 e.options 中可以取到 title: '标点标记的title', clickable: true, // 是否可以点击 draggable: false, // 是否可以拖拽 icon: L.icon({ iconUrl: 'https://api.map.baidu.com/lbsapi/getpoint/Images/logo.gif', // 标点图标地址 iconSize: [50, 50] // 图标大小 }) }).on('click', (e) => { // 点击事件 console.log('e----', e) console.log('"点击图标"----', '点击图标') }) marker.bindPopup(`<span style="color:red;">我是点击图标时弹出框展示的内容</span>`).openPopup() // 由于要取当前标点信息,下边添加信息用 (e)=>{} 而不是直接写模板字符串 marker.addTo(this.map) // 为了方便清除标点,下边添加标注点不用该方法 /**** 标记图标 end ****/ /**** 官网 ****/ // L.marker([51.5, -0.09]) // .addTo(this.map) // .bindPopup('A pretty CSS3 popup.<br> Easily customizable.') // .openPopup() /**** 地图厂商封装 ****/ // var marker = L.marker([纬度, 经度], { icon: markerIcon }).on('click', function (e) { // L.popup().setLatLng(e.latlng).setContent(innerHTML2).openOn(map) // 通过popup添加点击弹出框 // })
- 地图标点标记初步展示(地图中心点处 “百度图标” 即为标的点)
- 根据返回数据进行标点 _ 并对展示信息弹框进行样式处理
methods:{ // 加点标注 addMakersToMap() { let layers = [] // 为添加、清除图标做准备【方法二_1】 this.markers.forEach((item) => { // this.markers 为接口返回的需要进行标点的数据 var marker = new L.marker([item.wd, item.jd], { title: item.jgmc, clickable: true, draggable: false, // opacity: 0.5, // 不透明度 info: item, // 当前标点数据,点击图标展示信息时用 icon: L.icon({ iconUrl: `/images/${this.jglxIconObj[item.jglx]}.png`, iconSize: [30, 36] }) }).on('click', (e) => { console.log('"点击图标"----', '点击图标') }) /**** 点击图标弹出信息框 start ****/ marker .bindPopup((e) => { console.log('点击图标 e----', e) return `<div class="popup"> <p class="title">${ e.options.info.jgmc || '暂无' }</p> <p><i class="iconfont ico-didian"></i><span>${ e.options.info.jgdz || '暂无' }</span></p> <p><i class="iconfont ico-yewu"></i><span>${ e.options.info.kbyw || '暂无' }</span></p> <p><i class="iconfont ico-dianhua"></i><span>${ e.options.info.lxdh || '暂无' }</span></p> <p><i class="iconfont ico-shijian"></i><span>${ e.options.info.gzsj || '暂无' }</span></p> <p><i class="iconfont ico-cheguansuo"></i><span>${ e.options.info.jls || '暂无' }</span></p> ${ ['6', '7', '9', '11'].indexOf(e.options.info.jglx) > -1 ? `<p><i class="iconfont ico-yewuchuangkou"></i><span>${ e.options.info.cks || '暂无' }</span></p>` : '' } ${ e.options.info.jglx === '1' ? `<p><i class="iconfont ico-diannao"></i><span>${ e.options.info.kws || '暂无' }</span></p>` : '' } ${ ['2', '3'].indexOf(e.options.info.jglx) > -1 ? `<p><i class="iconfont ico-che"></i><span>${ e.options.info.kcs || '暂无' }</span></p>` : '' } ${ e.options.info.jglx === '2' ? `<p><i class="iconfont ico-changdi"></i><span>${ e.options.info.ksxls || '暂无' }</span></p>` : '' } ${ e.options.info.jglx === '3' ? `<p><i class="iconfont ico-malu"></i><span>${ e.options.info.ksxls || '暂无' }</span></p>` : '' } ${ e.options.info.jglx === '4' ? `<p><i class="iconfont ico-jiancezhan"></i><span>${ e.options.info.jcxs || '暂无' }</span></p>` : '' } ${ e.options.info.jglx === '5' ? `<p><i class="iconfont ico-chayan"></i><span>${ e.options.info.cytds || '暂无' }</span></p>` : '' } </div>` }) .openPopup() /**** 点击图标弹出信息框 end ****/ // marker.addTo(this.map) // 将图标添加到地图上【方法一】(由于还要清除图标,所以不用该方法添加图标,用方法二) layers.push(marker) // 【方法二_2】 }) this.layerGroup = L.layerGroup(layers); // this.layerGroup 初始值为 null【方法二_3】 this.map.addLayer(this.layerGroup) // 将图标添加到地图上【方法二_4】 }, }
<style lang='scss' scoped> #map { position: absolute; top: 0; bottom: 0; width: calc(100% - 20px); border: 2px solid red; } /* 去掉原本点击图标展示对话框样式 */ ::v-deep .leaflet-popup-content-wrapper, ::v-deep .leaflet-popup-tip { background-color: transparent; box-shadow: unset; } ::v-deep .leaflet-popup-close-button { display: none; } </style> <style lang="scss"> #MapHome { /* 自己写 点击图标显示图标信息 对话框的样式 */ .popup { position: absolute; left: 65px; top: 10px; width: 294px; font-family: 'MicroSoft Yahei'; background: rgba(#000, 0.6); color: #fff; font-size: 14px; line-height: 30px; letter-spacing: 2px; text-align: left; p { padding: 0 12px; span { display: inline-block; width: calc(100% - 30px); vertical-align: top; } .iconfont { display: inline-block; margin-right: 6px; color: rgba(#fff, 0.5); &.ico-chepai::before { margin-left: -4px; } } } .title { padding: 2px 12px; background: rgba(#fff, 0.2); font-size: 16px; line-height: 40px; text-align: center; } .btns { border-top: 1px solid rgba(#fff, 0.2); .el-button { display: inline-block; width: calc((100% - 17px) / 2); color: #3ac7e0; &.warning { color: #ffb555; } } .el-divider { background-color: rgba(#fff, 0.2); } } .popCorner { position: absolute; width: 0; height: 0; &.cornerRT { border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-left: 10px solid rgba(#000, 0.46); right: -10px; top: 10px; } &.cornerRB { border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-left: 10px solid rgba(#000, 0.6); right: -10px; bottom: 10px; } &.cornerLT { border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-right: 10px solid rgba(#000, 0.46); left: -10px; top: 10px; } &.cornerLB { border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-right: 10px solid rgba(#000, 0.6); left: -10px; bottom: 10px; } } } } </style>
- 根据返回数据进行标点展示
4.4 清除标点
- 侦听
jglxSeleList
(复选框数据_处理成数组后进行搜索接口的传参) → 先判断是否有值- 有值_调用标记点的方法_清除所有标记点_获取新的数据_根据新的数据重新进行标记点
- 无值_当前页面如果还有标记_清除所有标记
watch() { jglxSeleList: { handler(val) { if (val && this.map) { this.queryParam.jglx = this.jglx2Str(val) // 将所有的复选框数据转为一个数组 if (this.queryParam.jglx.length === 0) { // this.map.iclear() if(this.layerGroup !== null) this.layerGroup.clearLayers() // 移除所有标记 } else { this.fetchMonDeptConfigList() // 获取新的I标记点的数据 } } }, immediate: true, deep: true }, }, methods: { fetchMonDeptConfigList() { console.log('获取机构list 11111----', 11111) if (this.map) { if(this.layerGroup !== null) this.layerGroup.clearLayers() // 移除所有标记 } fetchMonDeptConfigList(this.queryParam).then((res) => { console.log('获取机构list res----', res) this.common.CheckCode(res, null, () => { if (res.data && res.data.length > 0) { this.markers = res.data // 获取到新的标记点数据 this.addMakersToMap() // 重新添加标记点 this.map.panTo(new L.LatLng(this.markers[0].wd, this.markers[0].jd)) // 重新设置中心点(第一个标点数据为中心点) } else { this.$message({ type: 'info', message: '未查询到相关机构网点' }) } }) }) }, }
五、用到的 API
- 标点
let maeker = new L.marker()
- 点击标点图标-展示内容:
marker.bindPopup('展示文字').openPopup()
- 添加图层的 group:
this.layerGroup = L.layerGroup(layers);
- 添加图层:
this.map.addLayer(this.layerGroup)
- 清除所有标记点:
this.layerGroup.clearLayers()
- 清除一个标记点:
this.map.removeLayer(this.layer)
本文未涉及- this.layer 是
L.polygon([[经度, 纬度],...], {color:'blue',fillColor:'none',opacity: 0.2 }
(经纬度是二维数据,实际是化线的api,opacity:透明度,fileColor:填充颜色,color:边框颜色) - 添加标记点
this.map.addLayer(this.layer);
- this.layer 是
- 点击标点图标-展示内容:
- 设置地图中心点
this.map.panTo(new L.LatLng(纬度, 经度))
六、整体代码 + 页面展示
- 整体代码
<!-- 地图 - new - 参照地图厂商demo写的 --> <template> <div id="MapHome"> <div class="queryDiv"> <el-input placeholder="通过机构关键字查询" suffix-icon="iconfont ico-chaxun" v-model="jggjz" ></el-input> </div> <el-checkbox-group v-model="jglxSeleList"> <el-collapse v-model="activeNames" class="jglxCon" accordion> <el-collapse-item v-for="(item, index) in jglxList" :name="item.name" :key="item.key"> <template slot="title"> <el-checkbox class="checkAll" v-model="item.allCheck" :checked="item.allCheck" @change="handleCheckAll(item.allCheck, index)" :label="item.key" ></el-checkbox> <p class="title"> <span class="pdl20">{{ item.name }}</span> <span class="floatR">{{ item.count }}</span> </p> </template> <el-checkbox v-for="obj in item.xllist" :key="obj.key" :label="obj.key" name="jglxSeleList" > <i :class="['iconfont', obj.icon]"></i> <span>{{ obj.name }}</span> <span class="floatR">{{ obj.count }}</span> </el-checkbox> <!-- --> </el-collapse-item> </el-collapse> </el-checkbox-group> <!-- <cdt-map @result="mapInit"></cdt-map> --> <div id="map"></div> </div> </template> <script> import { mapGetters } from 'vuex' // import CdtMap from '@/components/cdt-map/index' import { fetchMonDeptConfigList, queryMonDeptCount } from '@/api/service.js' import L from 'leaflet' import 'leaflet/dist/leaflet.css' import { tiledMapLayer } from '@supermap/iclient-leaflet' export default { name: 'Map', components: { // CdtMap }, data() { return { map: null, jggjz: '', // 机构关键字 markers: [], jgdlList: [], jglxList: [], jglxIconObj: {}, jglxSeleList: [], // 选中显示的机构类型 activeNames: [], // 下拉框展开 activeItem: {}, // 选中的网点 cornerType: '', // 弹框角标 flag1: false, // flag2: false, // 地图初始化成功 queryParam: {}, // 查询条件 layerGroup: null // 地图标点图标 } }, computed: { ...mapGetters(['sysList']) }, watch: { jglxSeleList: { handler(val) { if (val && this.map) { this.queryParam.jglx = this.jglx2Str(val) if (this.queryParam.jglx.length === 0) { if (this.layerGroup !== null) this.layerGroup.clearLayers() // 移除所有标记 } else { this.fetchMonDeptConfigList() } } }, immediate: true, deep: true }, jggjz: { handler(val) { if (this.map) { if (val) { this.queryParam = { jgmc: val } } else { this.queryParam = { jglx: this.jglx2Str(this.jglxSeleList) } } this.fetchMonDeptConfigList() } }, immediate: true, deep: true } }, mounted() { this.queryMonDeptCount() // 地图首页机构数量统计接口 this.mapInit() }, methods: { mapInit() { console.log('"init start"----', 'init start') var url = 'https://iserver.supermap.io/iserver/services/map-china400/rest/maps/China' // var url = 'https://iserver.supermap.io/iserver/services/map-china400/rest/maps/China_4326' // var url = 'https://iserver.supermap.io/iserver/services/map-china400/rest/maps/ChinaDark' this.map = L.map('map', { center: [22.822074, 108.371154], maxZoom: 18, zoom: 11 }) tiledMapLayer(url).addTo(this.map) console.log('"init end"----', 'init end') }, // 加点标注 addMakersToMap() { let layers = [] // 为清除图标做准备 this.markers.forEach((item) => { var marker = new L.marker([item.wd, item.jd], { title: item.jgmc, clickable: true, draggable: false, // opacity: 0.5, // 不透明度 info: item, // 当前标点数据,点击图标展示信息时用 icon: L.icon({ iconUrl: `/images/${this.jglxIconObj[item.jglx]}.png`, iconSize: [30, 36] }) }).on('click', (e) => { console.log('e----', e) console.log('"点击图标"----', '点击图标') }) /**** 点击图标弹出信息框 start ****/ marker .bindPopup((e) => { console.log('点击图标 e----', e) return `<div class="popup"> <p class="title">${ e.options.info.jgmc || '暂无' }</p> <p><i class="iconfont ico-didian"></i><span>${ e.options.info.jgdz || '暂无' }</span></p> <p><i class="iconfont ico-yewu"></i><span>${ e.options.info.kbyw || '暂无' }</span></p> <p><i class="iconfont ico-dianhua"></i><span>${ e.options.info.lxdh || '暂无' }</span></p> <p><i class="iconfont ico-shijian"></i><span>${ e.options.info.gzsj || '暂无' }</span></p> <p><i class="iconfont ico-cheguansuo"></i><span>${ e.options.info.jls || '暂无' }</span></p> ${ ['6', '7', '9', '11'].indexOf(e.options.info.jglx) > -1 ? `<p><i class="iconfont ico-yewuchuangkou"></i><span>${ e.options.info.cks || '暂无' }</span></p>` : '' } ${ e.options.info.jglx === '1' ? `<p><i class="iconfont ico-diannao"></i><span>${ e.options.info.kws || '暂无' }</span></p>` : '' } ${ ['2', '3'].indexOf(e.options.info.jglx) > -1 ? `<p><i class="iconfont ico-che"></i><span>${ e.options.info.kcs || '暂无' }</span></p>` : '' } ${ e.options.info.jglx === '2' ? `<p><i class="iconfont ico-changdi"></i><span>${ e.options.info.ksxls || '暂无' }</span></p>` : '' } ${ e.options.info.jglx === '3' ? `<p><i class="iconfont ico-malu"></i><span>${ e.options.info.ksxls || '暂无' }</span></p>` : '' } ${ e.options.info.jglx === '4' ? `<p><i class="iconfont ico-jiancezhan"></i><span>${ e.options.info.jcxs || '暂无' }</span></p>` : '' } ${ e.options.info.jglx === '5' ? `<p><i class="iconfont ico-chayan"></i><span>${ e.options.info.cytds || '暂无' }</span></p>` : '' } <div :class="['popCorner', cornerType]"></div> </div>` }) .openPopup() /**** 点击图标弹出信息框 end ****/ // marker.addTo(this.map) // 将图标添加到地图上【方法一】(由于还要清除图标,所以不用该方法添加图标) layers.push(marker) }) this.layerGroup = L.layerGroup(layers) this.map.addLayer(this.layerGroup) // 将图标添加到地图上【方法二】 }, // 地图首页机构数量统计接口 queryMonDeptCount() { queryMonDeptCount().then((res) => { this.common.CheckCode(res, null, () => { let jglxList = res.data jglxList.map((item) => { return (item.allCheck = true) }) this.jglxList = jglxList this.jglxList.forEach((item) => { this.jgdlList.push(item.key) item.xllist.forEach((obj) => { this.jglxSeleList.push(obj.key) this.jglxIconObj[obj.key] = obj.icon }) }) this.flag1 = true }) }) }, // 获取机构list fetchMonDeptConfigList() { if (this.map) { if (this.layerGroup !== null) this.layerGroup.clearLayers() // 移除所有标记 } fetchMonDeptConfigList(this.queryParam).then((res) => { this.common.CheckCode(res, null, () => { if (res.data && res.data.length > 0) { this.markers = res.data this.addMakersToMap() this.map.panTo(new L.LatLng(this.markers[0].wd, this.markers[0].jd)) // 取第一条标点数据的经纬度作为地图的中心点 } else { this.$message({ type: 'info', message: '未查询到相关机构网点' }) } }) }) }, // 获取jglx to string jglx2Str(val) { let jglx = val.filter((item) => { if (this.jgdlList.indexOf(item) < 0) { return item } }) return jglx.join(',') }, addArr(val) { let flag = false for (let i = 0; i < this.jglxSeleList.length; i++) { if (this.jglxSeleList[i] === val) { flag = true break } } if (!flag) { this.jglxSeleList.push(val) } }, cutArr(val) { for (let i = 0; i < this.jglxSeleList.length; i++) { if (this.jglxSeleList[i] === val) { this.jglxSeleList.splice(i, 1) break } } }, // 全选/反选 handleCheckAll(val, index) { this.jglxList[index].allCheck = !val if (this.jglxList[index].allCheck) { this.jglxList[index].xllist.forEach((row) => { this.addArr(row.key) }) } else { this.jglxList[index].xllist.forEach((row) => { this.cutArr(row.key) }) } this.$forceUpdate() } } } </script> <style lang='scss' scoped> #map { position: absolute; top: 0; bottom: 0; width: calc(100% - 20px); border: 2px solid red; } /* 去掉原本点击图标展示对话框样式 */ ::v-deep .leaflet-popup-content-wrapper, ::v-deep .leaflet-popup-tip { background-color: transparent; box-shadow: unset; } ::v-deep .leaflet-popup-close-button { display: none; } </style> <style lang="scss"> #MapHome { $colorList: #063b7f, #4a7feb, #33a8e4, #1da8ad, #e88e19, #e75748; $color1: #063b7f; $color2: #4a7feb; $color3: #33a8e4; $color4: #1da8ad; $color5: #e88e19; $color6: #e75748; width: 100%; height: 100%; .queryDiv { position: absolute; left: 80px; top: 20px; width: 380px; z-index: 999; .el-input { .el-input__inner { border: none; padding-right: 60px; height: 60px; box-shadow: 3px 3px 5px #ccc; } .el-input__suffix { right: 12px; .el-input__icon { width: 45px; font-size: 42px; line-height: 60px; } } } } .jglxCon { position: absolute; left: 80px; top: 96px; width: 226px; z-index: 999; .el-collapse-item { margin-bottom: 8px; .el-collapse-item__header { height: 40px; border-radius: 8px; border-bottom: none !important; padding: 0 10px; color: #fff; &.is-active { height: 40px; border-bottom: 1px solid rgba(#fff, 0.5) !important; border-radius: 8px 8px 0 0; transition: transform 0.3s; } .title { width: calc(100% - 16px); text-align: left; } .pdl20 { padding-left: 26px; } .el-collapse-item__arrow { position: absolute; left: 30px; } .el-checkbox__label { // color: transparent!important; display: none; } .el-checkbox.is-checked { background: none !important; } } .el-collapse-item__wrap { // padding: 6px 0; border-radius: 0 0 8px 8px; .el-checkbox { display: block; margin-right: 0; padding: 0 10px; width: 100%; text-align: left; color: #fff; letter-spacing: 2px; line-height: 30px; .el-checkbox__label { padding-left: 6px; width: calc(100% - 16px); .iconfont { display: inline-block; width: 20px; color: rgba(#fff, 0.5); } } } } .el-checkbox.is-checked { .el-checkbox__label, .iconfont { color: #fff; } .el-checkbox__inner { background-color: #fff; border-color: #fff; } } @each $c in $colorList { $i: index($colorList, $c); // 获取索引 &:nth-child(#{$i}) { .el-collapse-item__header { background: $c; } .el-collapse-item__wrap { background: rgba($c, 0.7); } .el-checkbox.is-checked { background: rgba($c, 0.85); .el-checkbox__inner::after { border-color: $c; } } } } } } .popup { position: absolute; left: 65px; top: 10px; width: 294px; font-family: 'MicroSoft Yahei'; background: rgba(#000, 0.6); color: #fff; font-size: 14px; line-height: 30px; letter-spacing: 2px; text-align: left; p { padding: 0 12px; span { display: inline-block; width: calc(100% - 30px); vertical-align: top; } .iconfont { display: inline-block; margin-right: 6px; color: rgba(#fff, 0.5); &.ico-chepai::before { margin-left: -4px; } } } .title { padding: 2px 12px; background: rgba(#fff, 0.2); font-size: 16px; line-height: 40px; text-align: center; } .btns { border-top: 1px solid rgba(#fff, 0.2); .el-button { display: inline-block; width: calc((100% - 17px) / 2); color: #3ac7e0; &.warning { color: #ffb555; } } .el-divider { background-color: rgba(#fff, 0.2); } } .popCorner { position: absolute; width: 0; height: 0; &.cornerRT { border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-left: 10px solid rgba(#000, 0.46); right: -10px; top: 10px; } &.cornerRB { border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-left: 10px solid rgba(#000, 0.6); right: -10px; bottom: 10px; } &.cornerLT { border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-right: 10px solid rgba(#000, 0.46); left: -10px; top: 10px; } &.cornerLB { border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-right: 10px solid rgba(#000, 0.6); left: -10px; bottom: 10px; } } } } </style>
- 效果展示
七、报错
打包后 - 报错1: SyntaxError: Unexpected token ...
-
以上代码在互联网环境运行正常,在内网环境会报如下错误
-
找了一天原因,发现是使用的地图厂商的依赖
@supermap/iclient-leaflet
的问题,导致的报错Uncaught SyntaxError: Unexpected token ...
(这个报错是提示有语法错误) -
报错原因
@supermap/iclient-leaflet
依赖有用ES6语法,项目打包的时候需要进行配置 -
解决
- 进行配置:项目打包时进行语法转换(地图厂商提供的官网截图↓↓↓)
- 首先安装依赖
npm i babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime -D
然后进行配置
const fs = require('fs') const webpack = require('webpack') const path = require('path') // 【主要代码】 const APP_Version = 'V1.0.1' const Timestamp = new Date().getTime(); //当前时间为了防止打包缓存不刷新,所以给每个js文件都加一个时间戳 module.exports = { // 基本路径 publicPath: './', // 输出文件目录 outputDir: 'superviseAppWeb', // 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。 // assetsDir: '', //指定生成的 index.html 的输出路径 (相对于 outputDir)。也可以是一个绝对路径。 indexPath: 'index.html', // 是否使用包含运行时编译器的 Vue 构建版本。设置为 true 后你就可以在 Vue 组件中使用 template 选项了,但是这会让你的应用额外增加 10kb 左右。 runtimeCompiler: true, // 默认情况下 babel-loader 会忽略所有 node_modules 中的文件。如果你想要通过 Babel 显式转译一个依赖,可以在这个选项中列出来。 transpileDependencies: [], // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。 productionSourceMap: false, // eslint-loader 是否在保存的时候检查 lintOnSave: true, // webpack配置 // 如果这个值是一个对象,则会通过 webpack-merge 合并到最终的配置中。 // 如果这个值是一个函数,则会接收被解析的配置作为参数。该函数及可以修改配置并不返回任何东西,也可以返回一个被克隆或合并过的配置版本。 // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md chainWebpack: () => { }, configureWebpack: { plugins: [ new webpack.DefinePlugin({ 'process.env': { BUILD_LOCAL: JSON.stringify(process.env.BUILD_LOCAL) } }), // new webpack.ProvidePlugin({ // $: "jquery", // jQuery: "jquery", // "windows.jQuery": "jquery" // }) ], output: { // 输出重构 打包编译后的 文件名称 【模块名称.版本号.时间戳】 filename: `[name].${APP_Version}.${Timestamp}.js`, chunkFilename: `[name].${APP_Version}.${Timestamp}.js` }, /**** 【主要代码】@supermap/iclient-leaflet 依赖打包配置(npm安装依赖) start ****/ module: { rules: [{ // 使用babel-loader将ES6语法转换为ES5 test: /\.js$/, include: [ path.resolve(__dirname, "node_modules/@supermap/iclient-common"), path.resolve(__dirname, "node_modules/@supermap/iclient-leaflet"), // 由于iClient对Elasticsearch的API进行了封装而Elasticsearch也使用了ES6的语法 path.resolve(__dirname, "node_modules/elasticsearch"), ], loader: 'babel-loader', options: { presets: ['@babel/preset-env'], plugins: [ [ '@babel/plugin-transform-runtime', { absoluteRuntime: false, corejs: false, helpers: false, regenerator: true, useESModules: false } ] ] } }] } /**** @supermap/iclient-leaflet 依赖打包配置(npm安装依赖) end ****/ }, // vue-loader 配置项 // css相关配置 css: { // 是否使用css分离插件 ExtractTextPlugin extract: false, // 开启 CSS source maps? sourceMap: false, // css预设器配置项 loaderOptions: { sass: { data: fs.readFileSync('src/styles/variables.scss', 'utf-8') } }, // 启用 CSS modules for all css / pre-processor files. modules: false }, // 是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建。 parallel: require('os').cpus().length > 1, // PWA 插件相关配置 // see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa pwa: {}, // webpack-dev-server 相关配置 devServer: { host: '0.0.0.0', port: 8080, https: false, hotOnly: false, open: true, // 自动打开浏览器 proxy: { "/etm/": { target: "http://192.168.31.125:8094/etm/", // 缉查布控地图服务 changeOrigin: true, pathRewrite: {"^/etm/": ""} }, '/': { ws: false, // proxy websockets target: 'http://192.168.0.26:9000', // target: 'http://192.168.11.209:9381', // 郑胡训 // target: 'http://192.168.11.139:9181', // 何斌 // target: 'http://192.168.0.42:9999', // 获取token // target: 'http://192.168.0.42:9181', // target: 'http://192.168.20.37:9181', pathRewrite: {'^/': ''}, changeOrigin: true, secure: false } } }, // 第三方插件配置 pluginOptions: { // ... }, }
- 不使用地图厂商的依赖
@supermap/iclient-leaflet
使用leaflet
依赖(也就是不使用超图封装的tiledMapLayer()
方法,用 LeafletJS 自己的TileLayer()
方法) 【没有试过】
- 进行配置:项目打包时进行语法转换(地图厂商提供的官网截图↓↓↓)
打包后 - 报错2:TypeError: Cannot assign to read only property 'export' of object '#<Object>'
- 报错1解决之后出现报错2
百度发现是@babel/plugin-transform-runtime
依赖的问题,需要在babel.config.js
添加sourceType: 'unambiguous'
参考:https://blog.csdn.net/qq_41619796/article/details/108076869// babel.config.js文件 module.exports = { presets: [ '@vue/app' ], plugins: ['@babel/plugin-proposal-nullish-coalescing-operator'], sourceType: 'unambiguous' // 【主要代码】 }
内网 - 报错3:SyntaxError: Unexpected token , in JSON at position 10
更多推荐
已为社区贡献1条内容
所有评论(0)