本篇文章呢主要是想对自己平时在开发项目时遇到的问题做一下记录,方便自己后续复习,后续会继续更新这个文档的
1、百度地图功能
实现代码
<template>
<div class="bmapgl">
<el-dialog
:model-value="openMap"
title="位置选择"
width="1000px"
@close="cancel"
>
<el-form label-width="80px">
<el-row>
<el-col :span="10">
<el-form-item label="当前地点">
<el-input
size="small"
type="text"
id="suggestId"
v-model="addressInfo.address"
placeholder="请输入地点"
@blur="onBlurClick"
/>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="位置经度">
<el-input
size="small"
type="text"
v-model="addressInfo.longitude"
readonly
/>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="位置纬度">
<el-input
size="small"
type="text"
v-model="addressInfo.latitude"
readonly
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div
class="baidu"
ref="mapRef"
id="baidumap"
style="width: 100%; height: 450px"
></div>
<template #footer>
<span class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="confirmSelect"> 确 定 </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup >
import { onMounted, watch, ref, reactive } from "vue";
import { ElMessage } from "element-plus";
const emit = defineEmits(["confirmMapAddress"]);
const props = defineProps({
openMap:{
type:Boolean,
default:false,
},
address:{
type:String,
default:''
},
longitude:{
type:[Number,String],
},
latitude:{
type:[Number,String]
}
})
let map = ref(null);
const mapZoom = ref(15);
const ak = ref("7eVTXNtnM12OxEIly2uL6uBaj9YRtOmy");
// let mapShow = ref(false);
let addressInfo = reactive({
// 地址信息
longitude: "", // 经度
latitude: "", // 纬度
province: "", // 省
city: "", // 市
district: "", // 区
address: "", // 详细地址
});
watch(
() => props.openMap,
() => {
if (!props.openMap) {
map.value && map.value.destroy();
}else{
// initMap();
init()
}
},
{ deep: true }
);
onMounted(() => {
init()
// initMap();
});
let geocoder;
const init = () => {
map.value = null;
BMPGL(ak.value).then((BMapGL) =>{
map.value = new BMapGL.Map("baidumap");
var zoomCtrl = new BMapGL.ZoomControl(); // 添加缩放控件
map.value.addControl(zoomCtrl);
var cityCtrl = new BMapGL.CityListControl(); // 添加城市列表控件
map.value.addControl(cityCtrl);
var LocationControl = new BMapGL.LocationControl(); // 添加定位控件,用于获取定位
map.value.addControl(LocationControl);
var scaleCtrl = new BMapGL.ScaleControl(); // 添加比例尺控件
map.value.addControl(scaleCtrl);
map.value.setMapType(); // 设置地图类型为标准地图模式;
var localcity = new BMapGL.LocalCity();
localcity.get((e) => {
map.value.centerAndZoom(e.name, mapZoom.value);
});
let point;
addressInfo.address = props.address
if( props.longitude !== ''){
addressInfo.longitude = Number(props.longitude)
}
if(props.latitude !== ''){
addressInfo.latitude = Number(props.latitude)
}
//初始化的时候如果有经纬度,需要先在地图上添加点标记
if (addressInfo.longitude && addressInfo.latitude) {
point = new BMapGL.Point(addressInfo.longitude, addressInfo.latitude);
map.value.centerAndZoom(point, mapZoom.value);
var marker2 = new BMapGL.Marker(point);
//在地图上添加点标记
setTimeout(()=> {
map.value.addOverlay(marker2);
var opts = {
width : 200, // 信息窗口宽度
height: 80, // 信息窗口高度
title : "地址" , // 信息窗口标题
enableMessage:false,//设置允许信息窗发送短息
}
var infoWindow = new BMapGL.InfoWindow(addressInfo.address, opts); // 创建信息窗口对象
map.value.openInfoWindow(infoWindow,point);
},1000)
}
map.value.enableScrollWheelZoom(true);
map.value.setHeading(64.5);
map.value.setTilt(73);
geocoder = new BMapGL.Geocoder();
//点击下拉框的值
map.value.addEventListener(
"click",
function (e) {
// 判断是否点击了标注点
if(!e.overlay || !(e.overlay instanceof BMapGL.Marker)){
map.value.clearOverlays();
var point1 = new BMapGL.Point(e.latlng.lng, e.latlng.lat);
// 创建点标记
var marker1 = new BMapGL.Marker(point1);
// 在地图上添加点标记
map.value.addOverlay(marker1);
addressInfo.longitude = e.latlng.lng;
addressInfo.latitude = e.latlng.lat;
// var geoc = new BMapGL.Geocoder(); // 创建地址解析器的实例
geocoder.getLocation(point1, (rs) => {
let adr = rs.addressComponents;
addressInfo.address =
adr.province +
adr.city +
adr.district +
adr.street +
adr.streetNumber; // 省市区街道门牌号
});
}
}
);
})
}
const onBlurClick = (event) => {
addressInfo.address = event.target.value
if(addressInfo.address && addressInfo.address !== ''){
geocoder.getPoint(
addressInfo.address,
pot => {
if (pot) {
addressInfo.longitude = pot.lng;
addressInfo.latitude = pot.lat;
map.value.clearOverlays();
var point1 = new BMapGL.Point(pot.lng, pot.lat);
map.value.centerAndZoom(point1, mapZoom.value);
// 创建点标记
var marker1 = new BMapGL.Marker(point1);
// 在地图上添加点标记
map.value.addOverlay(marker1);
} else {
addressInfo.address = ''
addressInfo.longitude = '';
addressInfo.latitude = '';
map.value.clearOverlays();
}
},
{
// 这里可以设置地址解析的选项
}
);
}else{
addressInfo.longitude = '';
addressInfo.latitude = '';
map.value.clearOverlays();
}
}
const initMap = () => {
map.value = null;
BMPGL(ak.value).then((BMapGL) => {
map.value = new BMapGL.Map("baidumap");
var ac = new BMapGL.Autocomplete({
//建立一个自动完成的对象
input: "suggestId",
location: map.value,
});
ac.enableAutoComplete = false
var zoomCtrl = new BMapGL.ZoomControl(); // 添加缩放控件
map.value.addControl(zoomCtrl);
var cityCtrl = new BMapGL.CityListControl(); // 添加城市列表控件
map.value.addControl(cityCtrl);
var LocationControl = new BMapGL.LocationControl(); // 添加定位控件,用于获取定位
map.value.addControl(LocationControl);
var scaleCtrl = new BMapGL.ScaleControl(); // 添加比例尺控件
map.value.addControl(scaleCtrl);
map.value.setMapType(); // 设置地图类型为标准地图模式;
var localcity = new BMapGL.LocalCity();
localcity.get((e) => {
map.value.centerAndZoom(e.name, mapZoom.value);
});
let point;
addressInfo.address = props.address
if(props.address !== ''){
setTimeout(() => {
ac.setInputValue(addressInfo.address);
},1000)
}
if( props.longitude !== ''){
addressInfo.longitude = Number(props.longitude)
}
if(props.latitude !== ''){
addressInfo.latitude = Number(props.latitude)
}
//初始化的时候如果有经纬度,需要先在地图上添加点标记
if (addressInfo.longitude && addressInfo.latitude) {
point = new BMapGL.Point(addressInfo.longitude, addressInfo.latitude);
map.value.centerAndZoom(point, mapZoom.value);
var marker2 = new BMapGL.Marker(point);
//在地图上添加点标记
setTimeout(()=> {
map.value.addOverlay(marker2);
var opts = {
width : 200, // 信息窗口宽度
height: 80, // 信息窗口高度
title : "地址" , // 信息窗口标题
enableMessage:false,//设置允许信息窗发送短息
}
var infoWindow = new BMapGL.InfoWindow(addressInfo.address, opts); // 创建信息窗口对象
map.value.openInfoWindow(infoWindow,point);
},1000)
}
map.value.enableScrollWheelZoom(true);
map.value.setHeading(64.5);
map.value.setTilt(73);
//点击下拉框的值
map.value.addEventListener(
"click",
function (e) {
// 判断是否点击了标注点
if(!e.overlay || !(e.overlay instanceof BMapGL.Marker)){
map.value.clearOverlays();
var point1 = new BMapGL.Point(e.latlng.lng, e.latlng.lat);
// 创建点标记
var marker1 = new BMapGL.Marker(point1);
// 在地图上添加点标记
map.value.addOverlay(marker1);
addressInfo.longitude = e.latlng.lng;
addressInfo.latitude = e.latlng.lat;
var geoc = new BMapGL.Geocoder(); // 创建地址解析器的实例
geoc.getLocation(point1, (rs) => {
let adr = rs.addressComponents;
addressInfo.address =
adr.province +
adr.city +
adr.district +
adr.street +
adr.streetNumber; // 省市区街道门牌号
});
}
}
);
ac.addEventListener("onconfirm", function (e) {
addressInfo.longitude = ''
addressInfo.latitude = ''
//鼠标点击下拉列表后的事件
var _value = e.item.value;
addressInfo.address =
_value.province +
_value.city +
_value.district +
_value.street +
_value.business;
// 搜索
map.value.clearOverlays(); //清除地图上所有覆盖物
//智能搜索
var local = new BMapGL.LocalSearch(map.value, {
onSearchComplete: () => {
//获取第一个智能搜索的结果
const pp = local.getResults().getPoi(0).point;
map.value.centerAndZoom(pp, mapZoom.value);
map.value.addOverlay(new BMapGL.Marker(pp)); //添加标注
addressInfo.longitude = pp.lng;
addressInfo.latitude = pp.lat;
},
});
local.search(addressInfo.address);
});
});
};
/**
* 确认选择
*/
const confirmSelect = () => {
if (addressInfo.address == "") {
ElMessage({
message: "请选择位置",
type: "error",
center: true,
});
return;
}
emit("confirmMapAddress", addressInfo,false);
};
/**
* 取消选择
*/
const cancel = () => {
addressInfo.address = ''
addressInfo.longitude = ''
addressInfo.latitude = ''
emit("cancelMap", false);
};
function BMPGL(ak) {
return new Promise(function (resolve, reject) {
window.init = function () {
// eslint-disable-next-line
resolve(BMapGL);
};
const script = document.createElement("script");
script.type = "text/javascript";
script.src = `https://api.map.baidu.com/api?v=3.0&type=webgl&ak=${ak}&callback=init`;
script.onerror = reject;
document.head.appendChild(script);
});
}
</script>
<style>
.tangram-suggestion {
z-index: 99999;
}
</style>
<style scoped lang="scss">
:deep(.BMap_cpyCtrl) {
display: none !important;
}
:deep(.BMap_cpyCtrl) {
display: none !important;
}
:deep(.el-dialog__header),
:deep(.el-dialog__footer) {
padding: 15px 20px;
}
:deep(.el-dialog__body) {
border-top: 1px solid #e8eaec;
border-bottom: 1px solid #e8eaec;
padding: 20px;
}
:deep(.el-dialog__headerbtn) {
top: 0;
font-size: 18px;
}
:deep(.el-dialog) {
border-radius: 8px;
}
</style>
initMap方法是可以实现检索功能的,但是后面发现检索个人开发注册的时候是有限制的,如果想无限用就要付费了,所以就把检索去除了,就有了现在的init跟失焦事件完成的
刚开始的难点可能在编辑的时候,要回显出来,地址及标注,刚开始的初始想法错了,导致走了不少弯路
最后经同事提醒,发现原来回显的地址已经出来了,只不过是被自动创建给刷新覆盖了,然后发现了这个之后,问题就好解决了
把input框的值重写使用 setInputValue
ac.setInputValue(addressInfo.address)
2、使用elementUI Plus组件上传图片功能
vue页面代码
<el-form-item label="形象图" prop="ticketImage">
<el-upload
class="avatar-uploader"
:action="uploadImgUrl"
:headers="headers"
:show-file-list="true"
list-type="picture-card"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
:file-list="fileList"
:limit="1"
:before-remove="handleAvatarDelete"
:on-preview="handleAvatarPreview"
:class="{ hide: fileList.length >= 1 }"
>
<el-icon class="avatar-uploader-icon"><Plus /></el-icon>
<template #tip>
<div class="el-upload__tip">
建议上传尺寸750*450,1M以内
</div>
</template>
</el-upload>
<el-dialog v-model="dialogVisible" title="预览">
<img w-full :src="form.ticketImage" alt="暂无图片" style="display: block; max-width: 100%; margin: 0 auto" />
</el-dialog>
</el-form-item>
js代码
const uploadList = ref([]);
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + '/common/upload'); // 上传的图片服务器地址
const headers = ref({ Authorization: 'Bearer ' + getToken() });
const fileList = ref([]);
const beforeAvatarUpload = (file) => {
if(file){
const isLt = file.size / 1024 / 1024 < 1
if(!isLt){
proxy.$modal.msgError(`图片大小不能超过 1MB!`);
return false;
}
}
// if (fileSize) {
// const isLt = file.size / 1024 / 1024 < props.fileSize;
// if (!isLt) {
// proxy.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
// return false;
// }
// }
proxy.$modal.loading('正在上传图片,请稍候...');
}
const handleAvatarSuccess = (res, file) => {
if (res.code === 200) {
form.value.ticketImage = res.fileName
uploadList.value.push({ name: res.fileName, url: res.url });
fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value);
// console.log('fileList.value',fileList.value)
uploadList.value = []
proxy.$modal.closeLoading();
} else {
}
}
const handleAvatarPreview = (file) => {
dialogVisible.value = true;
}
const handleAvatarDelete = (file) => {
fileList.value = []
form.value.ticketImage = ''
}
css(主要是想去除自带的动效)
:deep(.el-date-editor .el-input__prefix) {
display: none;
}
:deep(.hide .el-upload--picture-card) {
display: none;
}
.avatar-uploader :deep(.el-upload-list__item) {
transition: none !important;
}
3、使用elementUI Plus组件中el-date-picker默认回显当前年总回显1970问题
new Date().getFullYear()
console.log('year',year) // 2024
打印出来是2024,但是页面上回显的确是1970,百度了之后发现要转换一下类型
new Date().getFullYear().toString()
之后就可以了,在此记录一下