在vue3.3中以vueuse的形式使用leaflet

910 阅读2分钟

1.前置知识

  • vue3:至少了解过vue3的新特性
  • typescript:至少了解过ts的类型声明
  • leaflet:了解leaflet基础的使用方法

2.封装原因

使用过leaflet的小伙伴都知道,leaflet和echarts一样有很多的配置项,仅仅是显示一个基础的地图都需要将同样的操作编写多次

<template>
   <div id="baseMap" ref="map"></div>
</template>

<script setup lang="ts">
import * as L from 'leaflet@1.9.4'
import 'leaflet/dist/leaflet.css'
import { ref,onMounted } from 'vue@3.3.2'
const map = ref<any>('')// 地图实例
const  url = `https://tiles.stadiamaps.com/tiles/stamen_terrain/{z}/{x}/{y}{r}.jpg` //瓦片图地址
const initMap = ()=>{
  const bounds = L.latLngBounds(L.latLng(21, 119.54), L.latLng(26, 122)) // 限制地图的拖动范围
  const osm = L.tileLayer(url.value, {
      maxNativeZoom: 15,
      maxZoom: 15
    })
    map.value = L.map('baseMap', {
      center: [23.62788, 120.31094],
      zoomControl: false,
      zoom: 12,
      minZoom: 8,
      maxZoom: 15,
      attributionControl: false,
      layers: [osm],
      maxBounds: bounds
    })
}
onMounted(()=>{
  initMap()
})
</script>

<style lang="less" scoped>
#baseMap{
  width:300px;
  height:300px;
}
</style>
      

这样一个基础的地图就显示出来了

image.png

但是每一次要使用leaflet创建地图都要将该代码编写一次,造成了代码的冗余,维护性也较差

3.开始封装

现在的需求变成了去掉这些重复的代码,返回给我一个地图实例;这种功能和vueuse中看到的工具函数十分相像;

创建一个useLeaflet.ts

先引入leaflet和leaflet默认样式

import * as L from 'leaflet'
import 'leaflet/dist/leaflet.css'

将冗余的操作都塞进来

export const useLeaflet = ()=>{
     const bounds = L.latLngBounds(L.latLng(-90, -180), L.latLng(90, 180))
     const osm = L.tileLayer('https://tiles.stadiamaps.com/tiles/stamen_terrain/{z}/{x}/{y}{r}.jpg:', {
        maxNativeZoom: 15,
        maxZoom: 15
     })
     return L.map('baseMap', {
              center:[23.445, 120.35],
              zoomControl:true,
              zoom: 13,
              minZoom: 0,
              maxZoom: 15,
              attributionControl: false,
              layers: [osm],
              maxBounds: bounds
        })
}

这样就可以返回一个地图实例;但是既然封装了当然要能复用

  1. 地图dom的id不能每次都一样,所以作为参数传入,地图的瓦片图和初始中心点可能会有所改变同样作为参数传入
  2. 每次都要在onMounted生命周期中调用,onBeforeUnmount中销毁,何不在工具中完成,在工具中调用创建地图实例并返回一个ref对象
  3. 最终代码如下
import * as L from 'leaflet'
import 'leaflet/dist/leaflet.css'
import {onMounted,onBeforeUnmount,ref} from 'vue'
export const useLeaflet = (mapId: string,url: string,center: [number, number],)=>{
     const mapRef = ref() //地图实例
     const bounds = L.latLngBounds(L.latLng(-90, -180), L.latLng(90, 180))
     const osm = L.tileLayer(url, {
        maxNativeZoom: 15,
        maxZoom: 15
     })
     onMounted(() => {
        mapRef.value =  L.map(mapId, {
              center,
              zoomControl:true,
              zoom: 13,
              minZoom: 0,
              maxZoom: 15,
              attributionControl: false,
              layers: [osm],
              maxBounds: bounds
        })
     }
     /** 卸载地图 */
     onBeforeUnmount(() => {
        mapRef.value.remove()
     })
     return { mapRef}
}

在vue组件中调用

<template>
  <div id="baseMap" class="w-full h-full"></div>
</template>

<script setup lang="ts">
  import { useLeaflet } from '@/hooks'
  const { mapRef } = useLeaflet(
    'baseMap',
    'https://tiles.stadiamaps.com/tiles/stamen_terrain/{z}/{x}/{y}{r}.jpg',
    [23.445, 120.35],
    {
      miniMap: {
        show: true,
        position: 'topright'
      }
    }
  )
</script>

地图正常显示,且可以使用mapRef对地图进行操作

image.png

4.扩展

可以根据需求在初始化时对地图的配置进行修改,在useLeaflet函数添加第四个参数options,例如

/** options的类型约束 */
export type LeafletOptionsType = {
  showZoom?: boolean
  showScale?: boolean
  miniMap?: {
    show?: boolean
    position?: 'bottomleft' | 'bottomright' | 'topleft' | 'topright'
  }
}

export const useLeaflet = (
  mapId: string,
  url: string,
  center: [number, number],
  options?: LeafletOptionsType
) => {}

本次给大家带来的内容就这么多,我的文章对您有用的话可以给笔者一个小小的赞,我会为大家带来更多的使用技巧,谢谢支持