Vue3 对接高德地图之点击可下钻省市
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
免费下载资源
·
一、效果如下如所示(点击右下角的地址可以定位到该位置):
二、在vue中的使用
- 父组件
<template>
<div class="paths">
<div v-for="(item,index) in paths" :key="index" class="path-item" @click="clickPath(item)">{{item.name}}</div>
</div>
<AMap ref="projectMap" :config="mapConfig" @featureClick="featureClick"></AMap>
</template>
<script>
import {onMounted, ref} from "vue";
import updata from "@/common/updata";
import iconPoint from "../assets/marker.png";
let infoWindow = null
export default {
name: "projectMap2",
setup(){
const projectMap = ref()
const paths = ref([
{name:"全国",adcode:100000,level:'province'},
])
const pathCode = ref([100000])
const mapConfig = ref({
zoomEnable:true,
zoom:4.8
})
//获取项目分布
const getProjectMap = (level) => {
return new Promise(resolve => {
let data = {}
if(level === 'province'){
data = {
type:"省",
}
}else if(level === 'city'){
data = {
type:"市",
province:paths.value[1].name
}
}else{
data = {
type:"区",
province:paths.value[1].name,
city:paths.value[2].name
}
}
updata.getProjectMap(data).then(res=>{
if(res.code === '2000'){
projectMap.value.clear()
res.data.map(item=>{
let position = [Number(item.lng),Number(item.lat)]
let len = String(item.number).length
let scale = 1
let baseSize = 50
if(len<2){
baseSize = 50
}else if(len === 3){
baseSize = 60
}else{
baseSize = 70
}
let icon = new AMap.Icon({
image:iconPoint,
size:new AMap.Size(baseSize, baseSize*scale),
imageSize: new AMap.Size(baseSize, baseSize*scale),
})
projectMap.value.setMarker({
position: position,
offset: new AMap.Pixel(-25, -25),
icon: icon,
}, {
offset: new AMap.Pixel(0, -(baseSize/4.5)), //设置文本标注偏移量
content: '<div style="color:red;width:40px;">' + item.number + '</div>', //设置文本标注内容
direction: 'center', //设置文本标注方位
},(marker,_map)=>{
if(infoWindow){
closeInfoWindow()
infoWindow = null
}
let address = item.area ? item.area : item.city ? item.city : item.province
marker.content = '<div class="infoWindow">' +
`<div class="projectName">${address}:引进项目<span>${item.number}</span>个</div>`+
'</div>';
infoWindow = new AMap.InfoWindow({
isCustom: true,
offset: new AMap.Pixel(50, -30)
});
function showInfoWindow (e) {
infoWindow.setContent(e.target.content);
infoWindow.open(_map, e.target.getPosition());
}
function closeInfoWindow () {
_map.clearInfoWindow();
}
marker.on('mouseout', closeInfoWindow);
marker.on('mouseover', showInfoWindow);
}
)
})
resolve(data.value)
}
})
})
}
const featureClick = ({adcode,level,name}) => {
if(!pathCode.value.includes(adcode)){
if(level === 'district') return
let types = {
"province":"city",
"city":"district"
}
pathCode.value.push(adcode)
paths.value.push({name:name,adcode:adcode,level:types[level]})
// let zoom = level === 'province' ? 4.8 : level === 'city' ? 7 : 9
getProjectMap(types[level]).then(res=>{
projectMap.value.switchAreaNode(adcode)
})
}
}
const clickPath = (item) => {
if(paths.value[paths.value.length - 1].adcode !== item.adcode){
for(let i = 0;i<paths.value.length;i++){
if(paths.value[i].adcode === item.adcode){
getProjectMap(item.level).then(res=>{
// let zoom = item.level === 'city' ? 4.8 : item.level === 'district' ? 7 : 4.8
projectMap.value.switchAreaNode(item.adcode)
paths.value.splice(i + 1)
pathCode.value.splice(i + 1)
})
break;
}
}
}
}
onMounted(()=>{
projectMap.value.ready(()=>{
getProjectMap('province').then(()=>{
projectMap.value.switchAreaNode(100000,[
{adcode:100000,zoom:4.5,center:[106.2203,39.00214]},
{adcode:150000,zoom:5.5},
{adcode:650000,zoom:5.8},
{adcode:630000,zoom:6.5},
{adcode:540000,zoom:6},
{adcode:510000,zoom:6.8},
{adcode:520000,zoom:7.5},
{adcode:440000,zoom:7.5},
{adcode:350000,zoom:7.5},
{adcode:320000,zoom:7.5},
{adcode:370000,zoom:7.5},
{adcode:420000,zoom:7.2},
])
})
})
})
return {
mapConfig,
projectMap,
paths,
featureClick,
clickPath
}
}
}
</script>
<style scoped lang="less">
.paths{
position: absolute;
bottom:150px;
width:300px;
right:930px;
z-index: 1000;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
background: #04498d;
display: flex;
flex-direction: column-reverse;
.path-item{
font-weight: bold;
cursor: pointer;
padding:20px;
&:last-child{
background: #0061C0;
}
}
}
:deep(.infoWindow){
background: rgba(1, 18, 52, 0.8);
padding:5px;
.projectName{
font-size:16px;
white-space: nowrap;
color:white;
span{
color: #ffbc04;
}
}
}
</style>
2.Map子组件
<template>
<div class="AMap">
<div :id="id" :style="getStyle()" class="map-container"></div>
<!-- <img class="map-cover" v-if="showCover" src="../assets/images/map-cover.png" alt=""> -->
</div>
</template>
<script>
import {onBeforeMount, reactive, ref} from 'vue'
import AMapLoader from "@amap/amap-jsapi-loader";
export default {
name: "AMap",
props:{
config:Object
},
setup(props,cxt) {
const showCover = ref(false)
let map = reactive(null)
let mass = reactive(null)
let districtExplorer = reactive(null)
let currentAreaNode = reactive(null)
let markers = reactive([])
let heatmap = reactive(null)
const id = ref('map_' + String(Math.random()).split('.')[1])
const scale = ref(2)
const zoom = ref(3)
const transform = ref("translate(-50% , -50%) scale(2)")
const center = ref([106.2203,39.00214])
const switchConfig = ref([])
const defaultConfig = ref({
center:center.value,
mapStyle:'amap://styles/527e13e12603a649d24cb36aadb097ea',
zoom:zoom.value,
resizeEnable: true,
rotateEnable:false,
pitchEnable:false,
zoomEnable: false, //是否允许缩放
dragEnable:true, //是否允许拖拽
viewMode:'3D',//开启3D视图,默认为关闭
buildingAnimation:true,//楼块出现是否带动画
expandZoomRange:true,
zooms:[3,20],
})
const mapConfig = Object.assign(defaultConfig.value,props.config)
//创建地图
const createMap = (id) => {
window._AMapSecurityConfig = {
securityJsCode:'77963cbc37bc03014370e4ed3451447f',
}
return new Promise((resolve, reject) => {
if ('AMap' in window) {
resolve(new AMap.Map(id, mapConfig))
} else{
AMapLoader.load({
key: '043e0e2a9b32576106486e1170f8d18c',
version:'1.4.15',
AMapUI: {
version: '1.1',
plugins:['overlay/SimpleMarker','geo/DistrictExplorer']
},
plugins:['AMap.Scale','AMap.ToolBar','AMap.DistrictSearch','AMap.ImageLayer','AMap.InfoWindow','AMap.DistrictLayer','AMap.LabelsLayer','Map3D',"AMap.Heatmap","AMap.GeoJSON"],
}).then((AMap)=>{
resolve(new AMap.Map(id, mapConfig))
}).catch(e => {
reject(e)
})
}
})
}
//删除所有标记
const removeMarker = () => {
map.remove(markers)
markers = []
}
//设置标记
const setMarker = (config,labelConfig,callback) => {
let marker = new AMap.Marker(config);
if(labelConfig){
marker.setLabel(labelConfig)
}
if(callback){
callback(marker,map)
}
markers.push(marker)
map.add(marker)
}
//清空地图
const clear = () => {
map.clearMap()
}
//设置水波图------------------------------------开始-------------------------------------
//设置水波图-------------------------------------结束------------------------------------
//自定义窗体---------------------------------------开始---------------------------------
//构建自定义窗体并打开
const openInfoWindow = (position,content) => {
let infoWindow = new AMap.InfoWindow({
isCustom: true, //使用自定义窗体
content: content,
offset: new AMap.Pixel(0, 0),
})
infoWindow.open(map, position)
}
//关闭窗体
const closeInfoWindow = () => {
map.clearInfoWindow()
}
//自定义窗体---------------------------------------结束---------------------------------
//AMap ui设置行政边界------------------------------------开始-------------------------------------
//加载行政区域
const loadAreaNode = (adcode, callback) => {
districtExplorer.loadAreaNode(adcode, function (error, areaNode) {
if (error) {
if (callback) {
callback(error);
}
return;
}
if (callback) {
callback(null, areaNode);
}
});
}
const switchAreaNode = (adcode,config,callback) => {
if(config){
switchConfig.value = config
}
loadAreaNode(adcode, function (error, areaNode) {
if (error) {
if (callback) {
callback(error);
}
return;
}
currentAreaNode = areaNode;
//设置当前使用的定位用节点
districtExplorer.setAreaNodesForLocating([currentAreaNode]);
refreshAreaNode(areaNode);
if(zoom){
setZoomAndCenter(zoom)
}
if (callback) {
callback(null, areaNode);
}
});
}
//绘制某个区域的边界
const renderAreaPolygons = (areaNode) => {
//更新地图视野
map.setBounds(areaNode.getBounds(), null, null, true);
//像素平移
switchConfig.value.map(item=>{
if (areaNode.adcode === item.adcode) {
let zoom = item.zoom
let center = item.center ? item.center : null
map.setZoomAndCenter(zoom,center)
}
})
districtExplorer.clearFeaturePolygons();
var lnglatData = [];
//绘制子区域
districtExplorer.renderSubFeatures(areaNode, function (feature, i) {
lnglatData.push(feature.properties);
return {
cursor: "pointer",
bubble: true,
strokeColor: "#2BE8F6", //线颜色
strokeOpacity: 1, //线透明度
strokeWeight: 1, //线宽
fillColor: "#0061C0", //填充色
fillOpacity: 0.7, //填充透明度
};
});
//绘制父区域
districtExplorer.renderParentFeature(areaNode, {
cursor: "pointer",
bubble: true,
strokeColor: "#D8F6FF", //线颜色
strokeOpacity: 1, //线透明度
strokeWeight:2, //线宽
fillColor: "#0061C0", //填充色
fillOpacity: 0, //填充透明度
});
function toggleHoverFeature(feature, isHover, position) {
if (!feature) {
return;
}
var props = feature.properties;
//更新相关多边形的样式
var polys = districtExplorer.findFeaturePolygonsByAdcode(props.adcode);
for (var i = 0, len = polys.length; i < len; i++) {
polys[i].setOptions({
strokeColor: "#00BAF6", //线颜色
strokeOpacity: 1, //线透明度
strokeWeight: 1, //线宽
fillColor: isHover ? "#07ABD4" : "#0061C0", //填充色
fillOpacity: isHover ? 0.8 : 0.7, //填充透明度
});
}
}
//移入移出事件
districtExplorer.on(
"featureMouseout featureMouseover",
function (e, feature) {
toggleHoverFeature(
feature,
e.type === "featureMouseover",
e.originalEvent ? e.originalEvent.lnglat : null
);
}
);
//点击事件
districtExplorer.on("featureClick", async (e, feature) => {
const { adcode,center,level, name } = feature.properties;
cxt.emit('featureClick',{adcode,center,name,level})
});
lnglatData.forEach((item) => {
//创建纯文本标记
let text = new AMap.Text({
text: item.name,
anchor: "center", // 设置文本标记锚点
draggable: false,
// cursor: "pointer",
pointer: 'none',
zIndex: 0,
style: {
backgroundColor: "transparent",
border: "none",
color: "#7df6ec",
fontSize: "12px",
},
position: item.centroid || item.center,
map: map,
});
text.on('click',()=>{
const { adcode,level, name,center } = item;
cxt.emit('featureClick',{adcode,level, name,center})
})
});
showCover.value = true
}
const refreshAreaNode = (areaNode) => {
districtExplorer.setHoverFeature(null);
renderAreaPolygons(areaNode);
}
//AMap ui设置行政边界-------------------------------------结束------------------------------------
const setMassMarks = (data,size = 7) => {
var style = [ {
url: 'https://webapi.amap.com/images/mass/mass1.png',
anchor: new AMap.Pixel(4, 4),
size: new AMap.Size(size, size),
zIndex: 2,
}];
mass = new AMap.MassMarks(data, {
opacity: 0.8,
zIndex: 111,
cursor: 'pointer',
style: style
});
map.add(mass)
}
const setCircleMarker = (center) => {
var circleMarker = new AMap.CircleMarker({
center:center,
radius:10+Math.random()*10,//3D视图下,CircleMarker半径不要超过64px
strokeColor:'white',
strokeWeight:2,
strokeOpacity:0.5,
fillColor:'rgba(0,0,255,1)',
fillOpacity:0.5,
zIndex:10,
bubble:true,
cursor:'pointer',
clickable: true
})
map.add(circleMarker)
}
//设置热力图
const setHeatmap = (data,max = 1,config) => {
heatmap = new AMap.Heatmap(map, Object.assign({
radius: 10,
opacity: 1,
zIndex:1000,
gradient: {
0.1: "RGBA(12, 232, 12, 1)",
0.7: "RGBA(194, 44, 30, 1)",
1.0: "RGBA(199, 44, 30, 1)",
},
},config));
heatmap.setDataSet({
data: data,
max: max,
});
}
//判断时候具有已经渲染的图层
const has = (coverage) => {
return eval(coverage)
}
//删除图层
const remove = (arr) => {
let list = []
arr.map(item=>{
if(eval(item)){
list.push(eval(item))
}
})
if(list.length){
map.remove(list);
}
}
//这是缩放比例
const setZoom = (value) => {
map.setZoom(value)
}
//设置缩放比例和中心点
const setZoomAndCenter = (zoom,center) => {
map.setZoomAndCenter(zoom,center)
}
const ready = (callback,zoomValue) => {
createMap(id.value).then(_map=>{
map = _map
if(zoom){
zoom.value = zoomValue
}
window.AMapUI.load(['ui/geo/DistrictExplorer', 'lib/$'], function(DistrictExplorer, $) {
//创建一个实例
districtExplorer = window.districtExplorer = new DistrictExplorer({
eventSupport: true,
map: map
});
if(callback){
callback(map)
}
});
})
}
const getStyle = () => {
return{
transform:transform.value
}
}
const resize = () => {
let h = 2160/window.innerHeight
let w = 3840/window.innerWidth
if (h > w) {
transform.value = `translate(-50% , -50%) scale(${h})`
scale.value = h
} else {
transform.value = `translate(-50% , -50%) scale(${w})`
scale.value = h
}
}
onBeforeMount(()=>{
resize()
window.addEventListener("resize", (evt) => {
resize()
});
})
return {
id,
showCover,
setMarker,
setHeatmap,
has,
remove,
ready,
setZoom,
setZoomAndCenter,
switchAreaNode,
getStyle,
clear,
setCircleMarker,
setMassMarks,
removeMarker,
openInfoWindow,
closeInfoWindow,
}
}
}
</script>
<style scoped lang="less">
.AMap{
//为了适配 3840 * 2160 做缩放处理
height:100%;
width:100%;
position: relative;
overflow: hidden;
.map-cover{
position: absolute;
z-index: 1;
height:100%;
width:100%;
pointer-events: none;
}
.map-container{
height:50%;
width:50%;
position: absolute;
top:50%;
left:50%;
transform-origin: 50% 50%;
}
}
</style>
GitHub 加速计划 / vu / vue
207.55 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:3 个月前 )
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 5 个月前
e428d891
Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
更多推荐
已为社区贡献1条内容
所有评论(0)