提交 308e8d55 作者: 方治民

feat: 采用 Hook 方式重构 Mapbox 组件,测试通信方式

上级 9aeb4a39
import type { MapboxConfig, MapboxInstance } from './index'
import { isProdMode } from '@/utils/env'
// 组件名称
export const name = 'Mapbox'
/**
* 注册 Mapbox 实例
* @param config Mapbox 配置项
*/
export function useMapbox<T extends MapboxInstance, P extends MapboxConfig>(
config: P,
): [(instance: T) => void, MapboxInstance] {
const instanceRef = ref<T>()
function register(instance: T) {
if (isProdMode()) {
if (instance === unref(instanceRef)) {
return
}
onUnmounted(() => {
instanceRef.value = null
})
}
instanceRef.value = instance
config && instance?.setConfig(config)
}
function getInstance() {
const instance = unref(instanceRef)
if (!instance) {
console.warn('Mapbox instance is undefined!')
}
return instance as T
}
return [
register,
{
setConfig: (config: Partial<P>) => getInstance()?.setConfig(config),
isReady: computed(() => instanceRef?.value?.isReady) as unknown as ComputedRef<boolean>,
},
]
}
......@@ -810,4 +810,27 @@ export interface MapboxConfig {
*/
align?: 'bottom-left' | 'bottom-right'
}
// =============== 自定义事件 =================
/**
* 注意: 此处暴露的 map 对象的类型定义只是为了方便 IDE 提示, 实际上 map 对象上的方法和属性并不完整,依赖于 Mapbox 自定义组件的内部实现
* @param map 组件实例
* @param data 事件数据, 由视图层在 Map 加载完成后传入的可序列化 JSON 数据
*/
onLoaded?: (map: MapboxInstance, data: Recordable) => void
}
/**
* Mapbox 组件实例类型定义
*/
export interface MapboxInstance {
/**
* 设置地图组件配置
* @param config 地图配置
*/
setConfig: (config: Partial<MapboxConfig>) => void
/**
* 地图组件是否准备好了
*/
isReady: ComputedRef<boolean>
}
......@@ -11,34 +11,48 @@
// 1. 通过在逻辑层 data 中设置的属性向视图层传递数据
// 2. 通过在逻辑层 methods 定义方法,在视图层调用传递参数(注意:只能传递可进行 JSON 序列化的数据)
function nail() {}
export default {
props: {
config: {
type: Object,
default: () => ({}),
},
},
emits: ['register'],
data() {
return {
id: nanoid(),
onLoaded: nail,
options: {},
// FIXED: 定义为 undefined,避免在 Hook 中通过计算属性取值是出现两次变化的问题
loaded: undefined,
}
},
computed: {
isReady() {
return this.loaded
},
},
created() {
Message.loading()
},
mounted() {
this.options = {
container: this.id,
style: this.config?.style,
options: this.config?.options,
attribution: this.config?.attribution,
}
this.$emit('register', this)
},
methods: {
onMapLoad(data) {
this.loaded = true
Message.hideLoading()
console.log('✨ Map Loaded', data)
// 触发 onLoaded 事件
this.onLoaded?.(this, data)
},
setConfig(config) {
this.options = {
container: this.id,
style: config?.style,
options: config?.options,
attribution: config?.attribution,
}
this.onLoaded = config?.onLoaded || nail
},
},
}
......
......@@ -7,12 +7,13 @@
<script setup lang="ts">
import { defaultLegendConfig } from './config'
import { useShare } from '@/hooks/page/useShare'
import type { MapboxConfig } from '@/components/Map/Mapbox'
import { useMapbox } from '@/components/Map/Mapbox/hook'
import { LegendWidget, useLegendWidget } from '@/components/Map/Widgets/Legend'
import { SwitchWidget, useSwitchWidget } from '@/components/Map/Widgets/Switch'
import { TimeBarWidget, formatTime, useTimeBarWidget } from '@/components/Map/Widgets/TimeBar'
import { ToolBoxWidget, useToolBoxWidget } from '@/components/Map/Widgets/ToolBox'
import { BottomBarWidget, useBottomBarWidget } from '@/components/Map/Widgets/BottomBar'
import type { MapboxInstance } from '@/components/Map/Mapbox'
useShare()
......@@ -23,7 +24,7 @@
// })
// 地图配置
const config: MapboxConfig = {
const [registerMap, { isReady }] = useMapbox({
// 说明: 地图数据来源标注展示
attribution: {
text: '湖南省气象台',
......@@ -33,7 +34,18 @@
// 说明: 根据每个页面的 widget 布局情况,可能需要适当调整地图的中心位置,让界面显示效果更好
center: [111.6, 26.170844],
},
}
onLoaded: (map: MapboxInstance, data: Recordable) => {
console.log('✨✨✨ Map Loaded', map, data)
Message.alert(JSON.stringify(data), '地图加载完成')
},
})
watch(
() => isReady.value,
(ready) => {
console.log('[useMapbox] isReady', ready)
},
)
// 顶部时间轴小部件
const [registerTimeBarWidget, { setTime, getTimeBarValue }] = useTimeBarWidget({
......@@ -251,7 +263,7 @@
<template>
<view class="page h-100vh bg-white">
<!-- 地图组件 -->
<Mapbox :config="config" />
<Mapbox @register="registerMap" />
<!-- 地图上方所有小部件 -->
<view class="widgets">
......
......@@ -144,7 +144,6 @@ declare module 'vue' {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Switch: typeof import('./../src/components/Map/Widgets/Switch/src/Switch.vue')['default']
SwitchControl: typeof import('./../src/components/Map/Widgets/SwitchControl/src/SwitchControl.vue')['default']
ThumbnailPreview: typeof import('./../src/components/ThumbnailPreview/index.vue')['default']
TimeBar: typeof import('./../src/components/Map/Widgets/TimeBar/src/TimeBar.vue')['default']
ToolBox: typeof import('./../src/components/Map/Widgets/ToolBox/src/ToolBox.vue')['default']
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论