uniapp 地图添加,删除,编辑标记,在地图中根据屏幕范围中呈现标记
前言
小程序实现新功能,在地图中选取位置添加标记,并在地图中呈现添加的标记,(呈现的是根据当前屏幕范围内的标记),并对标记进行分享,删除,编辑,导航,并从分享标记点位置打开页面的时候在呈现该标记的信息详情,
部分代码解释
scale:地图缩放级别
markers:标记点
callouttap:标记点点击事件
markertap:markers内容的点击事件,就是自定义内容的点击事件
regionchange:推拽事件
regionchange - begin :拖拽开始事件
regionchange - end:拖拽结束事件
this.mapContext = uni.createMapContext("map", this); // 创建地图上下文
that.mapContext.getCenterLocation: 获取中心点位置
that.mapContext.getRegion : 获取后获取对角坐标
that.mapContext.getScale : 获取缩放级别
更多更详细地图上下文接口点击这里(uniapp官网,进去就是地图上下文相关)
uni.chooseLocation 和 uni.getLocation 使用的时候需要先声明
部分功能图片预览
声明:图片中内容为随机添加,内容也是胡乱写的
拖动地图,位置也会及时更新,选取添加的标记点位置
地图首页
添加修改标记页面和搜索页面就没必要放上来了,都是一些基础的样式和添加逻辑,根据个人情况写就行了,主要就是添加标记,(添加页面传递参数就是进度和纬度,有重要这两个数据就可以了),bijiaoInfos,就是分享和搜索页面传递过来的,根据id请求详情,拿到经纬度,把这个坐标定为中心点,再让地图重新加载,然后在自动弹出这个id的详情弹窗,就是示例的第二张图,通过搜索和分享进来看到的就是这个页面。
还有 - 记得点赞!!
<template>
<view>
<view class="search-box">
<view class="search" @click="searchFocus">
<text class="iconfont icon-sousuo-copy-copy"></text>
<text>请输入搜索内容</text>
<!-- <input type="text" v-model="search" @focus="searchFocus" placeholder="请输入搜索内容"> -->
</view>
</view>
<view class="titleNum">
当前区域标记数量为: {{ titleNum }}
</view>
<map id="map" class="map" style="width: 100%; height: 100vh;" :scale="scale" :latitude="latitude"
:longitude="longitude" :markers="covers" @callouttap='mapAction' @markertap="mapAction"
@regionchange="regionchange">
</map>
<uni-popup ref="popup" background-color="#fff">
<view class="popup-content">
<text @click="closePopup" class="iconfont icon-x"></text>
<view class="popup-content-top">
<view>{{ bijiaoInfo.title }}</view>
<view>{{ bijiaoInfo.address }}</view>
</view>
<view class="popup-content-content">
<view class="popup-content-title">备注</view>
<view class="popup-content-text">{{ bijiaoInfo.bz }}</view>
</view>
<view class="popup-content-content">
<view class="popup-content-title">创建人</view>
<view class="popup-content-text">{{ bijiaoInfo.username }} - {{ bijiaoInfo.addtime }}</view>
</view>
<view class="popup-img">
<image @click="previewImage(index)" v-for="item, index in bijiaoInfo.picurls_path" :key="index"
:src="item" mode="scaleToFill" />
</view>
<view class="popup-bom">
<view class="popup-bom-left">
<view class="popup-bom-left-item del" @click="delBiaoJi">
<text class="iconfont icon-shanchu"></text>
<text>删除</text>
</view>
<button open-type="share" class="popup-bom-left-item">
<text class="iconfont icon-fenxiang"></text>
<text>分享</text>
</button>
<view class="popup-bom-left-item" @click="biaoJiSave">
<text class="iconfont icon-beizhu"></text>
<text>编辑</text>
</view>
</view>
<view @click="goNavigation" class="popup-bom-right">导航</view>
</view>
</view>
</uni-popup>
<uni-popup ref="alertDialog" type="dialog">
<uni-popup-dialog type="error" cancelText="取消" confirmText="确定" title="提示"
:content="'您确定要删除' + bijiaoInfo.title + '标记点吗?'" @confirm="dialogConfirm"></uni-popup-dialog>
</uni-popup>
<view @click="goMyLocation" class="iconfont icon-wodeweizhi"></view>
<view class="gongNeng">
<view class="gongNeng-item" @click="quanLanAction">
<view class="iconfont icon-quanlan"></view>
<view>全览</view>
</view>
<view class="gongNeng-item huadian" @click="biaoJiAction">
<view class="iconfont icon-weizhi"></view>
<view>画点</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
titleNum: 0,
currentLocation: {},
scale: 14,// 地图缩放级别
id: null, //
title: 'map',
// 地图中心点 为空 默认北京
latitude: null,
longitude: null,
covers: [],
myLatitude: null,
myLongitude: null,
search: '',//搜索内容
searchList: [],
mapContext: '',//地图对象
zuobiao: {},//拖拽坐标
my_zuobiao: {},//我的坐标
isMarking: false, // 标记模式开关
centerMarker: null, // 中心点标记
type: 'bottom',
bijiaoInfo: {},
currentPage: 1,
totle_page: 0,
}
},
onLoad(options) {
console.log("options", JSON.parse(JSON.stringify(options)));
if (options.id) {
this.id = options.id;
this.bijiaoInfos();
}
// this.biaojiIndex();
uni.$on('callreload', () => {
this.biaojiIndex();
});
this.getLocation();
this.mapContext = uni.createMapContext("map", this); // 创建地图上下文
this.getInitialFocusCoordinates(); // 获取首次屏幕对焦经纬度
},
onShow() {
uni.getStorage({
key: 'currentLocation',
success: (res) => {
this.currentLocation = res.data
}
})
// latitude: 34.745982,郑州中心点
// longitude: 113.658233,
},
// 下拉刷新
// onPullDownRefresh() {
// this.getInitialFocusCoordinates(); // 获取首次屏幕对焦经纬度
// uni.showToast({
// title: '刷新成功',
// icon: 'success',
// duration: 1000
// })
// uni.stopPullDownRefresh(); // 停止刷新
// },
methods: {
searchFocus() {
uni.navigateTo({
url: '/biaoji/searchBiaoJi'
})
},
getLocation() {
uni.getLocation({
type: 'wgs84', // 获取经纬度坐标
accuracy: 'high', // 请求高精度位置
success: (res) => {
console.log("获取经纬度坐标", JSON.parse(JSON.stringify(res)));
// that.latitude = parseFloat(res.latitude.toFixed(5));
// that.longitude = parseFloat(res.longitude.toFixed(5));
this.latitude = parseFloat(res.latitude.toFixed(5));
this.longitude = parseFloat(res.longitude.toFixed(5));
this.myLatitude = parseFloat(res.latitude.toFixed(5));;
this.myLongitude = parseFloat(res.longitude.toFixed(5));;
this.covers = [{
id: 1,
latitude: res.latitude,
longitude: res.longitude,
iconPath: '../static/imgs/map/我的位置.png',
width: 25,
height: 25,
name: '我的位置',
}]
},
fail: (err) => {
console.error('获取位置信息失败', err);
}
});
},
// 分享过来传来的id 显示标记点详情
async bijiaoInfos() {
const res = await this.$axios("biaoji/biaojiInfo", {
id: this.id,
});
console.log("标记地点详情", JSON.parse(JSON.stringify(res.data)));
if (res.data.code == 0) {
this.bijiaoInfo = res.data.result;
const latitude = parseFloat(res.data.result.latitude)
const longitude = parseFloat(res.data.result.longitude)
this.mapContext.moveToLocation({
latitude: latitude.toFixed(5),
longitude: longitude.toFixed(5),
success: () => {
// 添加平滑过渡效果
const timer = setTimeout(() => {
// 在移动后更新缩放级别
this.latitude = latitude.toFixed(5),
this.longitude = longitude.toFixed(5),
this.scale = 14; // 设置为更适合查看的缩放级别
clearTimeout(timer);
this.$refs.popup.open(this.type);
}, 300); // 确保地图移动有足够的时间
},
fail: () => {
uni.showToast({
title: '移动到我的位置失败',
icon: 'none',
duration: 2000
});
}
});
}
},
// 回到我的位置
goMyLocation() {
// 检查用户位置是否可用
if (this.myLatitude === null || this.myLongitude === null) {
uni.showToast({
title: '无法获取当前位置,请确保已授权定位服务',
icon: 'none',
duration: 2000
});
return;
}
// 使用 moveToLocation 平滑移动到用户的位置
this.mapContext.moveToLocation({
latitude: this.myLatitude,
longitude: this.myLongitude,
success: () => {
// 添加平滑过渡效果
const timer = setTimeout(() => {
// 在移动后更新缩放级别
this.latitude = this.myLatitude;
this.longitude = this.myLongitude;
this.scale = 16; // 缩放级别
clearTimeout(timer);
}, 300); // 确保地图移动有足够的时间
},
fail: () => {
uni.showToast({
title: '移动到我的位置失败',
icon: 'none',
duration: 2000
});
}
});
},
// 全览
quanLanAction() {
if (this.myLatitude === null || this.myLongitude === null) {
uni.showToast({
title: '无法获取当前位置,请确保已授权定位服务',
icon: 'none',
duration: 2000
});
return;
}
// 使用 moveToLocation 平滑移动到用户的位置
this.mapContext.moveToLocation({
latitude: this.myLatitude,
longitude: this.myLongitude,
success: () => {
// 添加平滑过渡效果
const timer = setTimeout(() => {
// 在移动后更新缩放级别
this.latitude = this.myLatitude;
this.longitude = this.myLongitude;
this.scale = 11; // 缩放级别
clearTimeout(timer);
}, 300); // 确保地图移动有足够的时间
},
fail: () => {
uni.showToast({
title: '全览失败',
icon: 'none',
duration: 2000
});
}
});
},
async GetMapData() {
const res = await this.$axios("work/getMap", {
lat: this.location.latitude,
lon: this.location.longitude
});
console.log("当前位置的名称", JSON.parse(JSON.stringify(res)));
if (res.data.code == 0) {
this.location_data = res.data.result;
} else {
uni.showToast({
title: res.data.msg,
icon: 'none',
duration: 1000
})
}
},
// 获取首次屏幕对焦经纬度
getInitialFocusCoordinates() {
this.mapContext.getRegion({
success: (res) => {
console.log("获取首次屏幕对焦经纬度", JSON.parse(JSON.stringify(res)));
const northeast = res.northeast; // 东北角
const southwest = res.southwest; // 西南角
const zuobiao = {
northeast: northeast,
southwest: southwest
};
this.zuobiao = [zuobiao.northeast, zuobiao.southwest];
this.biaojiIndex();
},
fail: (err) => {
console.error('获取对焦经纬度失败:', err);
}
});
},
// 标记地点数据
async biaojiIndex() {
const res = await this.$axios("biaoji/biaojiIndex", {
title: '',
zuobiao: this.zuobiao,
scale: this.scale,
page: '',//页码
limit: '',//每页数量
})
console.log("标记地点数据", JSON.parse(JSON.stringify(res.data)));
if (res.data.code == 0) {
this.titleNum = res.data.totle_num;
this.covers = res.data.lists.map(item => {
return {
id: item.id,
latitude: parseFloat(item.latitude),
longitude: parseFloat(item.longitude),
// iconPath: '/static/images/map.png',
width: 22,
height: 22,
callout: {
content: item.title,
display: 'ALWAYS',
color: '#ffffff',
fontSize: 12,
borderRadius: 4,
bgColor: '#000',
padding: '5',
}
}
});
} else {
uni.showToast({
title: res.data.msg,
icon: 'none',
duration: 1000
})
}
},
// 地图标记点点击事件
async mapAction(e) {
console.log("markers 内容的点击事件", JSON.parse(JSON.stringify(e)));
this.$refs.popup.open(this.type);
const res = await this.$axios("biaoji/biaojiInfo", {
id: e.detail.markerId
});
console.log("标记地点详情", JSON.parse(JSON.stringify(res.data)));
if (res.data.code == 0) {
this.bijiaoInfo = res.data.result;
}
},
//监听地图拖拽
regionchange(data) {
// console.log("拖拽", JSON.parse(JSON.stringify(data)));
const that = this;
if (data.type == "end") {
// 获取拖拽后的中心点
that.mapContext.getCenterLocation({
success: function (res) {
that.latitude = parseFloat(res.latitude.toFixed(5));
that.longitude = parseFloat(res.longitude.toFixed(5));
// 获取后获取对角坐标
that.mapContext.getRegion({
success: (res) => {
const zuobiao = {
northeast: res.northeast,
southwest: res.southwest
};
that.zuobiao = [zuobiao.northeast, zuobiao.southwest];
// 获取缩放级别
that.mapContext.getScale({
success: (res) => {
if (res.scale !== that.scale) {
that.scale = res.scale; // 更新缩放级别
}
}
})
that.biaojiIndex();
}
})
}
});
}
},
// 添加标记点
biaoJiAction() {
uni.getSetting({
success: (res) => {
if (res.authSetting['scope.userLocation']) { /* 用户授权成功时走这里 */
this.handerChooseLocation()
} else if (res.authSetting['scope.userLocation'] === undefined) { /* 用户未授权时走这里 */
console.log('没有授权')
this.handleOpenSetting()
} else { /* 用户拒绝了授权后走这里 */
console.log('拒绝了授权 false')
this.handleOpenSetting()
}
},
})
},
handerChooseLocation() {
uni.chooseLocation({
latitude: this.latitude,
longitude: this.longitude,
success: (res) => {
// console.log('wx.chooseLocation res=', res)
uni.setStorageSync('currentLocation', res)
uni.navigateTo({
url: '/biaoji/biaojiInfo?status=1&res=' + JSON.stringify(res)
})
},
fail: function (err) {
console.log('取消按钮', err)
}
})
},
handleOpenSetting() {
wx.openSetting({
success: (res) => {
console.log('定位 openSetting', res)
if (res.authSetting["scope.userLocation"]) {
this.handerChooseLocation()
}
}
})
},
// 关闭弹窗
closePopup() {
this.$refs.popup.close();
if (this.id != null) {
this.getInitialFocusCoordinates(); // 获取首次屏幕对焦经纬度
this.id = null;
}
},
// 右上角分享
onShareAppMessage() {
return {
title: this.bijiaoInfo.title,
path: '/biaoji/biaoji?id=' + this.bijiaoInfo.id, //自定义路径
// imageUrl: '分享图片链接',
};
},
// 右上角分享到朋友圈
onShareTimeline() {
return {
title: this.bijiaoInfo.title,
path: '/biaoji/biaoji', //自定义路径
// imageUrl: this.shareImg //自定义展示图片
};
},
// 导航
goNavigation() {
// 导航跳转
uni.openLocation({
latitude: parseFloat(this.bijiaoInfo.latitude),
longitude: parseFloat(this.bijiaoInfo.longitude),
name: this.bijiaoInfo.title,
address: this.bijiaoInfo.address,
success: function (res) {
console.log('打开系统位置地图成功')
},
fail: function (error) {
console.log(error)
}
})
},
// 图片预览
previewImage(index) {
uni.previewImage({
urls: this.bijiaoInfo.big_picurls,
current: index, // 当前显示图片的索引
loop: true // 是否开启图片轮播
});
},
// 删除标记点
async delBiaoJi() {
this.$refs.alertDialog.open()
},
// 删除标记点
async dialogConfirm() {
const res = await this.$axios("biaoji/biaojiDel", {
id: this.bijiaoInfo.id
})
console.log("删除标记点", JSON.parse(JSON.stringify(res)));
if (res.data.code == 0) {
this.$refs.popup.close()
uni.showToast({
title: '删除成功',
icon: 'success',
duration: 1000
})
this.getLocation();
this.biaojiIndex();
this.getInitialFocusCoordinates(); // 获取首次屏幕对焦经纬度
} else {
uni.showToast({
title: res.data.msg,
icon: 'none',
duration: 1000
})
}
},
// 修改标记点
biaoJiSave() {
this.$refs.popup.close()
uni.navigateTo({
url: '/biaoji/biaojiInfo?status=2&id=' + this.bijiaoInfo.id
})
},
}
}
</script>
<style lang="scss" scoped>
.search-box {
background-color: white;
padding: 0.5rem 0;
.search {
width: 90%;
margin: auto;
display: flex;
align-items: center;
font-size: 14px;
background-color: #f7f7f7;
padding: 0.4rem;
border-radius: 30px;
.icon-sousuo-copy-copy {
font-size: 14px;
margin-right: 10px;
margin-left: .5rem;
}
text {
color: DarkGray;
}
}
}
.icon-wodeweizhi {
position: fixed;
left: 2%;
bottom: 5%;
background-color: white;
padding: 0.5rem;
z-index: 3;
border-radius: 10px;
}
.gongNeng {
position: fixed;
right: 2%;
bottom: 5%;
border-radius: 10px;
background-color: white;
padding: 0.5rem;
z-index: 3;
.gongNeng-item {
font-size: 12px;
text-align: center;
}
.huadian {
margin-top: 0.5rem;
.iconfont {
margin-bottom: 0.3rem;
}
}
}
.popup-content {
position: relative;
padding: 1rem 0;
// font-size: 1px;
.icon-x {
position: absolute;
top: 1rem;
right: 1rem;
font-size: 20px;
}
.popup-content-top {
margin: 0 1rem;
border-bottom: 1px solid #f7f7f7;
padding-bottom: 0.5rem;
view:nth-of-type(1) {
font-size: 14px;
margin-top: 0.3rem;
font-weight: bold;
}
view:nth-of-type(2) {
font-size: 10px;
margin-top: 0.3rem;
color: #666666;
}
}
.popup-content-content {
margin: 0 1rem;
border-bottom: 1px solid #f7f7f7;
padding-bottom: 0.5rem;
.popup-content-text {
margin-top: 0.3rem;
font-size: 12px;
}
}
.popup-content-title {
font-weight: bold;
font-size: 12px;
margin-top: 0.3rem;
}
.popup-img {
margin: 0.5rem 1rem;
image {
margin-right: 0.3rem;
width: 80px;
height: 80px;
}
}
.popup-bom {
margin: 0 1rem;
margin-top: 3rem;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #f7f7f7;
.popup-bom-left {
display: flex;
align-items: center;
font-size: 12px;
.popup-bom-left-item {
.iconfont {
margin-right: 0.2rem;
}
}
.del {
color: #f56c6c;
}
button {
font-size: 12px;
background-color: white;
// height: 60px;
}
button::after {
border: none;
}
}
.popup-bom-right {
color: white;
background-color: #377fff;
border-radius: 30px;
padding: 0.3rem 0.8rem;
font-size: 14px;
text-align: center;
}
}
}
.searchDialog {
background-color: white;
height: 50vh;
}
.titleNum {
position: fixed;
left: 0.2rem;
top: 3.5rem;
background-color: white;
padding: 0.3rem;
z-index: 5;
font-size: 14px;
border-radius: 5px;
}
</style>