af-mobile-client-vue3 1.1.2 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "af-mobile-client-vue3",
3
3
  "type": "module",
4
- "version": "1.1.2",
4
+ "version": "1.1.4",
5
5
  "description": "Vue + Vite component lib",
6
6
  "license": "MIT",
7
7
  "engines": {
@@ -1,220 +1,229 @@
1
- # XOlMap 地图组件使用说明
2
-
3
- ## 组件简介
4
-
5
- XOlMap 是一个基于 OpenLayers 的地图组件,支持多种底图切换、WMS 图层加载、点位渲染等功能。组件使用 Vue 3 + TypeScript 开发,采用 Composition API 和 `<script setup>` 语法。
6
-
7
- ## 功能特性
8
-
9
- - 支持多种底图切换(高德地图、高德卫星图、天地图、天地图卫星图)
10
- - 支持 WMS 图层加载和控制
11
- - 支持点位渲染(普通点位、分类点位、海量点)
12
- - 支持地图基本操作(缩放、平移、中心点设置等)
13
- - 支持移动端适配
14
-
15
- ## 安装依赖
1
+ # OpenLayers 地图组件 (XOlMap)
2
+
3
+ 基于 OpenLayers 封装的 Vue 3 地图组件,支持多种底图切换、图层管理、点位标注等功能。
4
+
5
+ ## 特性
6
+
7
+ - 支持多种底图切换
8
+ - 高德地图(矢量)
9
+ - 高德卫星图
10
+ - 天地图(矢量)
11
+ - 天地图卫星图
12
+ - 图层管理
13
+ - WMS 图层支持
14
+ - 矢量点位图层
15
+ - 图层显示/隐藏控制
16
+ - 点位标注
17
+ - 支持自定义图标
18
+ - 支持点位标题显示
19
+ - 支持点击回调
20
+ - 定位功能
21
+ - 支持手机 GPS 定位
22
+ - 支持地址解析
23
+ - 交互控制
24
+ - 缩放控制
25
+ - 比例尺显示
26
+ - 地图拖动
27
+
28
+ ## 安装
16
29
 
17
30
  ```bash
31
+ # 项目依赖
18
32
  npm install ol vant
19
33
  ```
20
34
 
21
- ## 基本用法
35
+ ## 使用示例
22
36
 
23
37
  ```vue
24
38
  <template>
25
- <XOlMap ref="mapRef" />
39
+ <XOlMap ref="mapRef" @centerChange="handleCenterChange" />
26
40
  </template>
27
41
 
28
42
  <script setup lang="ts">
29
- import { onMounted, ref } from 'vue'
30
- import XOlMap from './index.vue'
43
+ import { ref } from 'vue'
44
+ import type { InitParams } from './types'
45
+ import XOlMap from '@/components/data/XOlMap/index.vue'
31
46
 
32
47
  const mapRef = ref()
33
48
 
34
- onMounted(() => {
35
- // 初始化地图
36
- mapRef.value.init({
37
- center: [116.404, 39.915], // 北京坐标
38
- zoom: 12,
39
- maxZoom: 18,
40
- minZoom: 4,
41
- tianDiTuKey: 'your-tianditu-key', // 天地图密钥
49
+ // 初始化参数
50
+ const initParams: InitParams = {
51
+ center: [116.404, 39.915], // 初始中心点
52
+ zoom: 12, // 初始缩放级别
53
+ maxZoom: 18, // 最大缩放级别
54
+ minZoom: 4, // 最小缩放级别
55
+ tianDiTuKey: 'your_key', // 天地图密钥
56
+ amapKey: 'your_key', // 高德地图密钥
57
+ }
58
+
59
+ // 中心点变化回调
60
+ const handleCenterChange = (center: [number, number]) => {
61
+ console.log('地图中心点变化:', center)
62
+ }
63
+
64
+ // 添加点位示例
65
+ const addPoints = () => {
66
+ mapRef.value?.addVectorPoints({
67
+ id: 1,
68
+ value: '测试点位',
69
+ show: true,
70
+ icon: 'path/to/icon.png',
71
+ data: [{
72
+ longitude: 116.404,
73
+ latitude: 39.915,
74
+ title: '测试点位1'
75
+ }],
76
+ onClick: (point) => {
77
+ console.log('点击了点位:', point)
78
+ }
42
79
  })
43
- })
80
+ }
44
81
  </script>
45
82
  ```
46
83
 
47
- ## 组件属性
84
+ ## API
48
85
 
49
- ### 初始化参数 (InitParams)
86
+ ### Props
50
87
 
51
- | 参数名 | 类型 | 默认值 | 说明 |
52
- |--------|------|--------|------|
53
- | center | [number, number] | [116.404, 39.915] | 地图中心点坐标 [经度, 纬度] |
54
- | zoom | number | 10 | 地图缩放级别 |
55
- | maxZoom | number | 18 | 最大缩放级别 |
56
- | minZoom | number | 4 | 最小缩放级别 |
57
- | tianDiTuKey | string | '' | 天地图密钥 |
88
+ | 参数 | 说明 | 类型 | 默认值 |
89
+ | --- | --- | --- | --- |
90
+ | initParams | 初始化参数 | InitParams | - |
58
91
 
59
- ## 组件方法
92
+ ### InitParams 类型定义
60
93
 
61
- ### 地图控制
94
+ ```typescript
95
+ interface InitParams {
96
+ center?: [number, number] // 地图中心点坐标 [经度, 纬度]
97
+ zoom?: number // 地图缩放级别
98
+ maxZoom?: number // 最大缩放级别
99
+ minZoom?: number // 最小缩放级别
100
+ tianDiTuKey?: string // 天地图密钥
101
+ amapKey?: string // 高德地图 API key
102
+ }
103
+ ```
62
104
 
63
- | 方法名 | 参数 | 返回值 | 说明 |
64
- |--------|------|--------|------|
65
- | init | InitParams | void | 初始化地图 |
66
- | getMap | - | Map \| null | 获取地图实例 |
67
- | setCenter | center: [number, number], animate?: boolean | void | 设置地图中心点 |
68
- | setZoom | zoom: number, animate?: boolean | void | 设置地图缩放级别 |
69
- | getZoom | - | number | 获取当前缩放级别 |
70
- | setCenterAndZoom | center: [number, number], zoom: number, animate?: boolean | void | 设置地图中心点和缩放级别 |
105
+ ### 事件
71
106
 
72
- ### 图层控制
107
+ | 事件名 | 说明 | 回调参数 |
108
+ | --- | --- | --- |
109
+ | centerChange | 地图中心点变化时触发 | (center: [number, number]) |
73
110
 
74
- | 方法名 | 参数 | 返回值 | 说明 |
75
- |--------|------|--------|------|
76
- | addWMSLayers | options: WMSOptions | void | 添加 WMS 图层 |
77
- | setWMSLayerVisible | layerName: string, visible: boolean | void | 控制 WMS 图层显示/隐藏 |
78
- | handleToggleWMSLayer | layer: WMSLayerConfig | void | 切换 WMS 图层显示状态 |
79
- | addPointLayer | config: PointLayerConfig, points: PointData[] | number | 添加点位图层 |
80
- | setPointLayerVisible | layerId: number, visible: boolean | void | 控制点位图层显示/隐藏 |
111
+ ### 方法
81
112
 
82
- ### 点位渲染
113
+ | 方法名 | 说明 | 参数 | 返回值 |
114
+ | --- | --- | --- | --- |
115
+ | init | 初始化地图 | (params: InitParams) | void |
116
+ | setCenter | 设置地图中心点 | (center: [number, number], animate?: boolean) | void |
117
+ | setZoom | 设置缩放级别 | (zoom: number, animate?: boolean) | void |
118
+ | getZoom | 获取当前缩放级别 | - | number |
119
+ | setCenterAndZoom | 同时设置中心点和缩放级别 | (center: [number, number], zoom: number, animate?: boolean) | void |
120
+ | addVectorPoints | 添加矢量点位 | (config: PointLayerConfig) | VectorLayer |
121
+ | addWMSLayers | 添加 WMS 图层 | (options: WMSOptions) | void |
122
+ | handleLocation | 触发定位功能 | - | Promise<void> |
83
123
 
84
- | 方法名 | 参数 | 返回值 | 说明 |
85
- |--------|------|--------|------|
86
- | addVectorPoints | config: PointLayerConfig | VectorLayer<VectorSource> \| null | 渲染普通点位 |
87
- | addWebGLPoints | options: WebGLPointOptions | void | 渲染海量点 |
124
+ ## 注意事项
88
125
 
89
- ## 类型定义
126
+ 1. 使用天地图和高德地图需要配置对应的密钥
127
+ 2. 组件默认高度为 100%,需要在父容器中设置具体高度
128
+ 3. 手机定位功能需要设备支持并授予定位权限
129
+ 4. WMS 图层需要配置正确的服务地址和图层参数
90
130
 
91
- ### PointData 点位数据
131
+ # 地址选择器 (XLocationPicker)
92
132
 
93
- ```typescript
94
- interface PointData {
95
- longitude: number // 经度
96
- latitude: number // 纬度
97
- title?: string // 点标题
98
- extData?: Record<string, any> // 自定义数据
99
- }
100
- ```
133
+ 基于 XOlMap 封装的地址选择器组件,支持地图选点和地址解析功能。
101
134
 
102
- ### PointLayerConfig 点位图层配置
135
+ ### 使用示例
103
136
 
104
- ```typescript
105
- interface PointLayerConfig {
106
- id: number // 图层ID
107
- value: string // 图层名称
108
- show: boolean // 是否显示
109
- icon: string // 图标URL
110
- iconAnchor?: [number, number] // 图标锚点
111
- onClick?: (point: PointData, event: any) => void // 点击回调函数
112
- data?: PointData[] // 点位数据
137
+ ```vue
138
+ <template>
139
+ <XLocationPicker
140
+ v-model:visible="showPicker"
141
+ :init-location="initLocation"
142
+ @confirm="handleConfirm"
143
+ @cancel="handleCancel"
144
+ />
145
+ </template>
146
+
147
+ <script setup lang="ts">
148
+ import { ref } from 'vue'
149
+ import type { LocationResult } from './types'
150
+ import { XLocationPicker } from '@/components/data/XOlMap'
151
+
152
+ // 控制选择器显示
153
+ const showPicker = ref(false)
154
+
155
+ // 初始位置
156
+ const initLocation = {
157
+ longitude: 116.404,
158
+ latitude: 39.915,
159
+ address: '北京市天安门'
113
160
  }
114
- ```
115
161
 
116
- ### WebGLPointOptions WebGL渲染配置
162
+ // 确认选择回调
163
+ const handleConfirm = (location: LocationResult) => {
164
+ console.log('选择的位置:', location)
165
+ // location 包含:
166
+ // - longitude: 经度
167
+ // - latitude: 纬度
168
+ // - address: 地址描述
169
+ showPicker.value = false
170
+ }
117
171
 
118
- ```typescript
119
- interface WebGLPointOptions extends PointLayerConfig {
120
- iconSize?: [number, number] // 图标大小
121
- enableCluster?: boolean // 是否开启聚合
122
- clusterDistance?: number // 聚合距离
123
- performance?: { // 性能配置
124
- enableChunk?: boolean // 是否开启分块加载
125
- chunkSize?: number // 每块数据量
126
- enableThrottle?: boolean // 是否开启节流
127
- throttleWait?: number // 节流时间间隔
128
- }
172
+ // 取消选择回调
173
+ const handleCancel = () => {
174
+ showPicker.value = false
175
+ }
176
+
177
+ // 打开选择器
178
+ const openPicker = () => {
179
+ showPicker.value = true
129
180
  }
181
+ </script>
130
182
  ```
131
183
 
132
- ## 示例代码
184
+ ### Props
133
185
 
134
- ### 添加普通点位
186
+ | 参数 | 说明 | 类型 | 默认值 |
187
+ | --- | --- | --- | --- |
188
+ | visible | 是否显示选择器 | boolean | false |
189
+ | initLocation | 初始位置 | LocationResult | - |
190
+ | title | 选择器标题 | string | '选择位置' |
191
+ | confirmText | 确认按钮文字 | string | '确定' |
192
+ | cancelText | 取消按钮文字 | string | '取消' |
135
193
 
136
- ```typescript
137
- mapRef.value.addVectorPoints({
138
- icon: 'path/to/icon.png',
139
- iconAnchor: [0.5, 1],
140
- data: [
141
- {
142
- longitude: 116.404,
143
- latitude: 39.915,
144
- title: '测试点位',
145
- extData: { type: 'test' }
146
- }
147
- ],
148
- onClick: (point) => {
149
- console.log('点击了点位:', point)
150
- }
151
- })
152
- ```
194
+ ### 事件
153
195
 
154
- ### 添加分类点位
196
+ | 事件名 | 说明 | 回调参数 |
197
+ | --- | --- | --- |
198
+ | confirm | 点击确认按钮时触发 | (location: LocationResult) |
199
+ | cancel | 点击取消按钮时触发 | - |
200
+ | update:visible | 更新 visible 值 | (visible: boolean) |
155
201
 
156
- ```typescript
157
- mapRef.value.addPointLayer(
158
- {
159
- id: 1,
160
- value: '学校',
161
- show: true,
162
- icon: 'path/to/icon.png',
163
- iconAnchor: [0.5, 1],
164
- onClick: (point) => {
165
- console.log('点击了学校:', point)
166
- }
167
- },
168
- [
169
- {
170
- longitude: 116.404,
171
- latitude: 39.915,
172
- title: '北京大学',
173
- extData: { type: 'school' }
174
- }
175
- ]
176
- )
177
- ```
178
-
179
- ### 添加海量点
202
+ ### LocationResult 类型定义
180
203
 
181
204
  ```typescript
182
- mapRef.value.addWebGLPoints({
183
- icon: 'path/to/icon.png',
184
- iconSize: [6, 6],
185
- data: Array.from({ length: 10000 }, (_, i) => ({
186
- longitude: 116.404 + Math.random() * 0.1,
187
- latitude: 39.915 + Math.random() * 0.1,
188
- title: `点位${i + 1}`,
189
- extData: { type: 'mass' }
190
- })),
191
- performance: {
192
- enableChunk: true,
193
- chunkSize: 1000
194
- }
195
- })
205
+ interface LocationResult {
206
+ longitude: number // 经度
207
+ latitude: number // 纬度
208
+ address: string // 地址描述
209
+ }
196
210
  ```
197
211
 
198
- ## 注意事项
212
+ ### 特性
199
213
 
200
- 1. 使用天地图时需要提供有效的天地图密钥
201
- 2. 海量点渲染建议使用 WebGL 方式,性能更好
202
- 3. 点位图层的 zIndex 会根据是否有 ID 自动设置
203
- 4. 移动端适配已内置,无需额外配置
214
+ - 支持地图拖动选点
215
+ - 实时解析地址信息
216
+ - 支持初始位置设置
217
+ - 支持自定义标题和按钮文字
218
+ - 移动端友好的交互体验
204
219
 
205
- ## 常见问题
220
+ ### 注意事项
206
221
 
207
- 1. 地图不显示
208
- - 检查容器高度是否设置
209
- - 检查网络连接是否正常
210
- - 检查天地图密钥是否有效
222
+ 1. 需要配置高德地图 API Key 用于地址解析
223
+ 2. 建议在移动端使用时增加必要的权限检查
224
+ 3. 可以通过 CSS 变量自定义样式
225
+ 4. 选择器会自动适配屏幕高度
211
226
 
212
- 2. 点位不显示
213
- - 检查点位数据格式是否正确
214
- - 检查图标 URL 是否可访问
215
- - 检查图层是否设置为显示状态
227
+ ## 贡献
216
228
 
217
- 3. 性能问题
218
- - 大量点位建议使用 WebGL 渲染
219
- - 开启分块加载和节流功能
220
- - 合理设置聚合参数
229
+ 如果你有任何问题或建议,欢迎提出 Issue 或 Pull Request。
@@ -0,0 +1,191 @@
1
+ <script setup lang="ts">
2
+ import type { LocationResult } from '../types'
3
+ import { Button } from 'vant'
4
+ import { nextTick, onMounted, ref, watch } from 'vue'
5
+ import XOlMap from '../index.vue'
6
+
7
+ interface Props {
8
+ modelValue?: LocationResult
9
+ tianDiTuKey: string
10
+ amapKey: string
11
+ defaultCenter?: [number, number]
12
+ defaultZoom?: number
13
+ }
14
+
15
+ const props = withDefaults(defineProps<Props>(), {
16
+ defaultCenter: () => [116.404, 39.915],
17
+ defaultZoom: 10,
18
+ tianDiTuKey: '',
19
+ amapKey: '',
20
+ })
21
+
22
+ const emit = defineEmits<{
23
+ (e: 'update:modelValue', value: LocationResult): void
24
+ (e: 'confirm', value: LocationResult): void
25
+ }>()
26
+
27
+ const mapRef = ref<InstanceType<typeof XOlMap>>()
28
+ const currentAddress = ref('')
29
+ const currentLocation = ref<[number, number]>(props.defaultCenter)
30
+
31
+ // 处理地图中心点变化
32
+ async function handleCenterChange(center: [number, number]) {
33
+ currentLocation.value = center
34
+ // 获取地址信息
35
+ if (mapRef.value) {
36
+ currentAddress.value = await mapRef.value.getAddressInfo(center)
37
+ }
38
+ }
39
+
40
+ // 处理确定按钮点击
41
+ function handleConfirm() {
42
+ const result: LocationResult = {
43
+ longitude: currentLocation.value[0],
44
+ latitude: currentLocation.value[1],
45
+ address: currentAddress.value,
46
+ }
47
+ emit('update:modelValue', result)
48
+ emit('confirm', result)
49
+ }
50
+
51
+ // 组件挂载时初始化地图
52
+ onMounted(() => {
53
+ // 使用 nextTick 确保 DOM 已更新
54
+ nextTick(() => {
55
+ mapRef.value.init({
56
+ center: props.defaultCenter,
57
+ zoom: props.defaultZoom,
58
+ tianDiTuKey: props.tianDiTuKey,
59
+ amapKey: props.amapKey,
60
+ })
61
+
62
+ // 初始化后尝试获取地址信息
63
+ handleCenterChange(props.defaultCenter)
64
+ })
65
+ })
66
+
67
+ // 监听弹窗状态变化
68
+ watch(() => props.modelValue, (newVal) => {
69
+ // 当绑定值变化时,可能需要重新调整地图
70
+ nextTick(() => {
71
+ if (mapRef.value && mapRef.value.getMap()) {
72
+ mapRef.value.getMap().updateSize()
73
+ }
74
+ })
75
+ }, { immediate: true })
76
+ </script>
77
+
78
+ <template>
79
+ <div class="location-picker">
80
+ <div class="map-container">
81
+ <XOlMap
82
+ ref="mapRef"
83
+ class="map"
84
+ @center-change="handleCenterChange"
85
+ />
86
+ <!-- 中心点标记 -->
87
+ <div class="location-picker-marker">
88
+ <div class="marker-icon" />
89
+ </div>
90
+ </div>
91
+
92
+ <!-- 底部地址信息面板 -->
93
+ <div class="location-picker-panel">
94
+ <div class="address-info">
95
+ <div class="address-label">
96
+ 位置信息
97
+ </div>
98
+ <div class="address-text">
99
+ {{ currentAddress }}
100
+ </div>
101
+ <div class="coordinates-text">
102
+ 经度: {{ currentLocation[0] }}, 纬度: {{ currentLocation[1] }}
103
+ </div>
104
+ </div>
105
+ <Button type="primary" block @click="handleConfirm">
106
+ 确定
107
+ </Button>
108
+ </div>
109
+ </div>
110
+ </template>
111
+
112
+ <style scoped lang="less">
113
+ .location-picker {
114
+ position: relative;
115
+ width: 100%;
116
+ height: 100%;
117
+ display: flex;
118
+ flex-direction: column;
119
+ border-radius: 8px;
120
+ overflow: hidden;
121
+ }
122
+
123
+ .map-container {
124
+ position: relative;
125
+ flex: 1;
126
+ min-height: 0;
127
+ }
128
+
129
+ .map {
130
+ width: 100%;
131
+ height: 100%;
132
+ min-height: 300px;
133
+ }
134
+
135
+ .location-picker-marker {
136
+ position: absolute;
137
+ left: 50%;
138
+ top: 50%;
139
+ transform: translate(-50%, -50%);
140
+ z-index: 1000;
141
+ pointer-events: none;
142
+
143
+ .marker-icon {
144
+ width: 24px;
145
+ height: 24px;
146
+ background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iIzE5ODlmYSIgZD0iTTEyIDJDOC4xMyAyIDUgNS4xMyA1IDljMCA1LjI1IDcgMTMgNyAxM3M3LTcuNzUgNy0xM2MwLTMuODctMy4xMy03LTctN3ptMCA5LjVjLTEuMzggMC0yLjUtMS4xMi0yLjUtMi41czEuMTItMi41IDIuNS0yLjUgMi41IDEuMTIgMi41IDIuNS0xLjEyIDIuNS0yLjUgMi41eiIvPjwvc3ZnPg==') no-repeat center;
147
+ background-size: contain;
148
+ }
149
+ }
150
+
151
+ .location-picker-panel {
152
+ background: white;
153
+ padding: 12px 16px;
154
+ box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.1);
155
+ border-radius: 8px 8px 0 0;
156
+ z-index: 1000;
157
+
158
+ .address-info {
159
+ margin-bottom: 12px;
160
+
161
+ .address-label {
162
+ font-size: 14px;
163
+ color: #666;
164
+ margin-bottom: 4px;
165
+ }
166
+
167
+ .address-text {
168
+ font-size: 15px;
169
+ color: #333;
170
+ margin-bottom: 4px;
171
+ word-break: break-all;
172
+ }
173
+
174
+ .coordinates-text {
175
+ font-size: 12px;
176
+ color: #999;
177
+ }
178
+ }
179
+ }
180
+
181
+ // 移动端适配
182
+ @media screen and (max-width: 768px) {
183
+ .location-picker-panel {
184
+ padding: 10px 12px;
185
+
186
+ .address-info {
187
+ margin-bottom: 10px;
188
+ }
189
+ }
190
+ }
191
+ </style>