Skip to content

Vue3 + 腾讯地图初始化

1 开发者账号注册

  • 去腾讯位置服务控制台注册账号并进入我的应用界面
  • 创建应用,保留生成的 key

2 引入项目

  • 在 index.html 中引入资源,注意连接中的 key 参数要换成第一步中应用的 key 值

    html
    <script src="https://map.qq.com/api/gljs?v=1.exp&key=xxxx"></script>

3 初始化地图

  • 详情参考官网文档

  • 新建一个组合式函数用于初始化地图 src/composables/map/useInitMap.js

    js
    import { reactive, onMounted } from 'vue';
    export default function useInitMap(domId, center) {
        let map = reactive({
            dom: null,
            instance: null,
        });
    
        const initMap = () => {
            map.dom = document.getElementById(domId);
            map.instance = new window.TMap.Map(map.dom, {
                center: new window.TMap.LatLng(...center), // 中心点坐标
                zoom: 17.2, // 缩放级别
                pitch: 43.5, // 俯仰角
                rotation: 45, // 地图旋转角度
            });
        };
    
        onMounted(() => {
            initMap();
        });
    
        return { map };
    }
  • 在页面中使用

    vue
    <script setup>
    import useInitMap from '../composables/map/useInitMap';
    let { map } = useInitMap({ domId: 'map', center: [39.98412, 116.307484] });
    </script>
    
    <template>
        <div id="map"></div>
    </template>

4 定位组件

  • 详情参考官网文档

  • index.html 内引入组件,注意填入提前准备好的 key

    html
    <script src="https://apis.map.qq.com/tools/geolocation/min?key=xxxx&referer=myapp"></script>
  • 创建一个组合式函数用于使用定位组件 src/composables/map/useLocation.js

    js
    import { onBeforeUnmount, onMounted, reactive } from 'vue';
    export default function useLocation(map) {
        let geolocation = reactive({
            location: null,
            instance: null,
        });
    
        // 获取一次当前定位
        const getLocation = () => {
            geolocation.instance.getLocation(
                (position) => {
                    geolocation.location = position;
                },
                (err) => {
                    console.error('定位获取失败:', err);
                },
                { timeout: 8000 }
            );
        };
    
        // 当前定位居中显示
        const setCenter = () => {
            const { lat, lng } = geolocation.location;
            const center = new window.TMap.LatLng(lat, lng);
            map.instance.setCenter(center);
        };
    
        // 每 5 秒刷新一次定位,注意此处要用实际的 key 替换 xxxx
        let timerPosition = null;
        onMounted(() => {
            geolocation.instance = new window.qq.maps.Geolocation('xxxx', 'myapp');
            timerPosition = setInterval(() => {
                getLocation();
            }, 5000);
        });
        onBeforeUnmount(() => {
            clearInterval(timerPosition); // 停止监听
        });
    
        return {
            geolocation,
            getLocation,
            setCenter,
        };
    }
  • 在页面中使用

    vue
    <script setup>
    import { onMounted } from 'vue';
    import useInitMap from '../composables/map/useInitMap';
    import useLocation from '../composables/map/useLocation';
    let { map } = useInitMap({ domId: 'map' });
    let { getLocation, geolocation, setCenter } = useLocation(map);
    onMounted(() => {
        getLocation();
    });
    </script>
    
    <template>
        <div id="map"></div>
        <button @click="setCenter">setCenter</button>
        <pre>{{ geolocation.location }}</pre>
    </template>

5 自定义覆盖物

  • 自定义覆盖物可以继承构造函数的方法来创建一个类,src/utils/mapOverlay/OverlayImg.js

    js
    // 自定义图片覆盖物
    export default class OverlayImg extends window.TMap.DOMOverlay {
        constructor(options) {
            super(options);
        }
    
        // 初始化:获取配置参数
        onInit({ position, src, map } = {}) {
            Object.assign(this, { position, src, map });
        }
    
        // 创建DOM元素,返回一个Element,使用this.dom可以获取到这个元素
        createDOM() {
            this.onMouseEnter = function (e) {
                this.emit('mouseenter', e.target.firstChild);
            }.bind(this);
            this.onMouseLeave = function (e) {
                this.emit('mouseleave', e.target.firstChild);
            }.bind(this);
            this.onClick = function (e) {
                this.emit('click', e.target.firstChild);
            }.bind(this);
            let mydom = document.createElement('div');
            mydom.innerHTML = '';
            mydom.style.cssText = `background-image: url('${this.src}');`;
            mydom.setAttribute('class', 'overlayImg');
            mydom.addEventListener('click', this.onClick);
            mydom.addEventListener('mouseenter', this.onMouseEnter);
            mydom.addEventListener('mouseleave', this.onMouseLeave);
    
            return mydom;
        }
    
        // 更新DOM元素,在地图移动/缩放后执行
        updateDOM() {
            if (!this.map) {
                return;
            }
    
            // 经纬度坐标转容器像素坐标
            let position = new window.TMap.LatLng(...this.position);
            let pixel = this.map.projectToContainer(position);
    
            // 使图中心点对齐经纬度坐标点
            let left = pixel.getX() - this.dom.clientWidth / 2 + 'px';
            let top = pixel.getY() - this.dom.clientHeight / 2 + 'px';
            this.dom.style.transform = `translate(${left}, ${top})`;
        }
    
        // 销毁时
        onDestroy() {
            if (this.onClick) {
                this.dom.removeEventListener(this.onClick);
            }
            if (this.onMouseLeave) {
                this.dom.removeEventListener(this.onMouseLeave);
            }
            if (this.onMouseEnter) {
                this.dom.removeEventListener(this.onMouseEnter);
            }
        }
    }
  • 在页面中使用,让一个图片动起来

    vue
    <script setup>
    import { onMounted } from '@vue/runtime-core';
    import useInitMap from '../composables/map/useInitMap';
    import OverlayImg from '../utils/mapOverlay/OverlayImg.js';
    
    let { map } = useInitMap({ domId: 'map' });
    
    onMounted(() => {
        new OverlayImg({
            map: map.instance,
            position: [39.98412, 116.307484],
            src: '/man.png',
        });
    });
    </script>
    
    <template>
        <div id="map"></div>
    </template>
    
    <style lang="scss">
    .overlayImg {
        width: 200px;
        height: 200px;
        background-repeat: no-repeat;
        background-position: -800px 0;
        animation: man_run 1s steps(7, end) both infinite;
    }
    @keyframes man_run {
        0% {
            background-position: -800px 0;
        }
        100% {
            background-position: -2200px 0;
        }
    }
    </style>