| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 |
- <template>
- <view class="container">
- <!-- 地图容器 - 必须设置明确高度 -->
- <view id="mapContainer" class="map-container"></view>
- <!-- 坐标显示区域 -->
- <view class="coordinates" v-if="showCoordinates">
- <view class="coordinate-item">
- <text class="coordinate-label">经度:</text>
- <text class="coordinate-value">{{ longitude }}</text>
- </view>
- <view class="coordinate-item">
- <text class="coordinate-label">纬度:</text>
- <text class="coordinate-value">{{ latitude }}</text>
- </view>
- <view class="coordinate-item">
- <text class="coordinate-label">地址:</text>
- <text class="coordinate-value">{{ address }}</text>
- </view>
- </view>
- </view>
- </template>
- <script>
- export default {
- props: {
- initialPosition: {
- type: Object,
- default: () => ({
- lnglat: null,
- address: ''
- })
- },
- allowSelection: {
- type: Boolean,
- default: true
- },
- showCoordinates: {
- type: Boolean,
- default: true
- }
- },
- data() {
- return {
- map: null,
- geocoder: null,
- tk: '92c4ddd919f4e41a30e765680e3a29b7', // 替换为实际密钥
- longitude: '未选择',
- latitude: '未选择',
- address: '未获取',
- markers: [],
- labels: [], // 存储文本标签
- mapInitialized: false
- };
- },
- watch: {
- initialPosition: {
- immediate: true,
- handler(newVal) {
- if (this.mapInitialized && newVal && this.isValidPosition(newVal)) {
- this.processPosition(newVal);
- }
- }
- },
- allowSelection(newVal) {
- if (this.map) {
- if (newVal) {
- this.enableMapSelection();
- } else {
- this.disableMapSelection();
- }
- }
- }
- },
- mounted() {
- // 确保在H5环境下运行
- // #ifdef H5
- this.$nextTick(() => {
- setTimeout(() => {
- this.initMap();
- }, 500);
- });
- // #endif
- // 非H5环境提示
- // #ifndef H5
- console.warn("天地图组件仅支持H5环境");
- uni.showToast({
- title: '地图功能仅在H5环境可用',
- icon: 'none'
- });
- // #endif
- },
- methods: {
- // 验证坐标是否有效
- isValidPosition(position) {
- const lng = position.lng ||
- (position.lnglat && (position.lnglat.lng || position.lnglat.longitude));
- const lat = position.lat ||
- (position.lnglat && (position.lnglat.lat || position.lnglat.latitude));
- return lng && lat && !isNaN(parseFloat(lng)) && !isNaN(parseFloat(lat));
- },
- // 处理坐标数据
- processPosition(position) {
- const lng = position.lng ||
- (position.lnglat && (position.lnglat.lng || position.lnglat.longitude));
- const lat = position.lat ||
- (position.lnglat && (position.lnglat.lat || position.lnglat.latitude));
- if (lng && lat) {
- this.setMapCenter(parseFloat(lng), parseFloat(lat));
- this.reverseGeocode(parseFloat(lng), parseFloat(lat));
- }
- },
- initMap() {
- if (typeof T === 'undefined') {
- this.loadTiandituAPI().then(() => {
- this.createMap();
- }).catch(err => {
- console.error("天地图加载失败:", err);
- uni.showToast({
- title: '地图加载失败',
- icon: 'none'
- });
- });
- } else {
- this.createMap();
- }
- },
- loadTiandituAPI() {
- return new Promise((resolve, reject) => {
- if (window.T) return resolve();
- const script = document.createElement('script');
- script.src = `https://api.tianditu.gov.cn/api?v=4.0&tk=${this.tk}`;
- script.onload = resolve;
- script.onerror = () => reject(new Error('天地图脚本加载失败'));
- document.head.appendChild(script);
- });
- },
- createMap() {
- try {
- // 创建地图实例
- this.map = new T.Map('mapContainer');
- // 设置默认中心点(太原)
- let centerLng = 112.55;
- let centerLat = 37.87;
- let name = ''
- // 使用初始坐标(如果存在)
- if (this.initialPosition && this.isValidPosition(this.initialPosition)) {
- const lng = this.initialPosition.lng ||
- (this.initialPosition.lnglat && (this.initialPosition.lnglat.lng || this.initialPosition.lnglat
- .longitude));
- const lat = this.initialPosition.lat ||
- (this.initialPosition.lnglat && (this.initialPosition.lnglat.lat || this.initialPosition.lnglat.latitude));
- centerLng = parseFloat(lng);
- centerLat = parseFloat(lat);
- name = this.initialPosition.address
- // 更新坐标显示
- this.longitude = centerLng.toFixed(6);
- this.latitude = centerLat.toFixed(6);
- this.address = name;
- }
- // 设置地图中心和缩放级别
- this.map.centerAndZoom(new T.LngLat(centerLng, centerLat), 12);
- // 创建逆地理编码对象
- this.geocoder = new T.Geocoder();
- // 添加正确的地图图层(使用经纬度投影)
- const vecLayer = new T.TileLayer(
- `https://t{s}.tianditu.gov.cn/vec_c/wmts?tk=${this.tk}`, {
- subdomains: ['0', '1', '2', '3', '4', '5', '6', '7']
- }
- );
- const cvaLayer = new T.TileLayer(
- `https://t{s}.tianditu.gov.cn/cva_c/wmts?tk=${this.tk}`, {
- subdomains: ['0', '1', '2', '3', '4', '5', '6', '7']
- }
- );
- this.map.addLayer(vecLayer);
- this.map.addLayer(cvaLayer);
- // 添加缩放控件
- this.map.addControl(new T.Control.Zoom());
- // 启用选点功能
- if (this.allowSelection) this.enableMapSelection();
- // 添加初始标记
- if (this.initialPosition && this.isValidPosition(this.initialPosition)) {
- const lng = this.initialPosition.lng ||
- (this.initialPosition.lnglat && (this.initialPosition.lnglat.lng || this.initialPosition.lnglat
- .longitude));
- const lat = this.initialPosition.lat ||
- (this.initialPosition.lnglat && (this.initialPosition.lnglat.lat || this.initialPosition.lnglat.latitude));
- this.addMarker(parseFloat(lng), parseFloat(lat));
- this.reverseGeocode(parseFloat(lng), parseFloat(lat));
- }
- this.mapInitialized = true;
- } catch (e) {
- console.error('地图初始化错误:', e);
- }
- },
- // 启用地图选点
- enableMapSelection() {
- this.map.on('click', this.handleMapClick);
- },
- // 禁用地图选点
- disableMapSelection() {
- this.map.off('click', this.handleMapClick);
- },
- // 设置地图中心点并更新坐标显示
- setMapCenter(lng, lat) {
- this.longitude = parseFloat(lng).toFixed(6);
- this.latitude = parseFloat(lat).toFixed(6);
- // 清除现有标记
- this.clearMarkers();
- // 添加新标记
- this.addMarker(lng, lat);
- // 移动地图视图
- this.map.panTo(new T.LngLat(lng, lat));
-
- // 通知父组件
- this.notifyParent();
- },
- // 逆地理编码
- reverseGeocode(lng, lat) {
- if (!this.geocoder) return;
- this.address = '正在查询...';
- const point = new T.LngLat(lng, lat);
- this.geocoder.getLocation(point, (result) => {
- if (result.getStatus() === 0) {
- this.address = result.getAddress();
- } else {
- this.address = '查询失败';
- }
-
- // 更新标签内容
- this.updateLabelContent();
- this.notifyParent();
- });
- },
- // 地图点击事件
- handleMapClick(e) {
- if (!this.allowSelection) return;
- this.setMapCenter(e.lnglat.lng, e.lnglat.lat);
- this.reverseGeocode(e.lnglat.lng, e.lnglat.lat);
- },
- // 通知父组件位置信息
- notifyParent() {
- this.$emit('update-location', {
- longitude: this.longitude,
- latitude: this.latitude,
- address: this.address
- });
- },
- // 添加标记
- addMarker(lng, lat) {
- try {
- const point = new T.LngLat(lng, lat);
-
- // 添加标记
- const marker = new T.Marker(point);
- this.map.addOverLay(marker);
- this.markers.push(marker);
-
- // 添加文本标签
- this.addLabel(lng, lat, this.address);
-
- console.log('标记添加成功:', lng, lat);
- } catch (error) {
- console.error('添加标记失败:', error);
- }
- },
- // 添加文本标签
- addLabel(lng, lat, content) {
- try {
- const point = new T.LngLat(lng, lat);
-
- // 创建文本标签
- const label = new T.Label({
- text: content || '未知地址',
- position: point,
- offset: new T.Point(-50, -40) // 调整标签位置使其在标记点上方
- });
-
- // 设置标签样式
- // label.setStyle({
- // color: '#333',
- // backgroundColor: 'rgba(255, 255, 255, 0.9)',
- // border: '1px solid #ddd',
- // borderRadius: '4px',
- // padding: '5px 10px',
- // fontSize: '12px',
- // fontWeight: 'bold',
- // boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
- // maxWidth: '150px',
- // textAlign: 'center'
- // });
-
- this.map.addOverLay(label);
- // this.labels.push(label);
- } catch (error) {
- console.error('添加标签失败:', error);
- }
- },
-
- // 更新标签内容
- updateLabelContent() {
- if (this.labels.length > 0) {
- const lastLabel = this.labels[this.labels.length - 1];
- lastLabel.setText(this.address);
- }
- },
- // 清除标记和标签
- clearMarkers() {
- // 清除标记
- this.markers.forEach(marker => {
- try {
- this.map.removeOverLay(marker);
- } catch (error) {
- console.error('移除标记失败:', error);
- }
- });
- this.markers = [];
-
- // 清除标签
- this.labels.forEach(label => {
- try {
- this.map.removeOverLay(label);
- } catch (error) {
- console.error('移除标签失败:', error);
- }
- });
- this.labels = [];
- }
- }
- };
- </script>
- <style scoped>
- /* 容器样式 */
- .container {
- width: 100%;
- display: flex;
- flex-direction: column;
- position: relative; /* 为绝对定位的信息窗口提供参考 */
- z-index: 0;
- }
- /* 地图容器 - 关键:必须设置高度 */
- .map-container {
- width: 100%;
- height: 300rpx;
- /* 使用rpx单位适应不同屏幕 */
- border: 1px solid #eee;
- background-color: #f8f8f8;
- }
- /* 坐标显示区域 */
- .coordinates {
- margin-top: 20rpx;
- padding: 20rpx;
- background-color: #f8f9fa;
- border-radius: 8rpx;
- }
- .coordinate-item {
- display: flex;
- margin: 15rpx 0;
- padding: 15rpx 0;
- border-bottom: 1rpx dashed #dee2e6;
- }
- .coordinate-item:last-child {
- border-bottom: none;
- }
- .coordinate-label {
- font-weight: bold;
- color: #495057;
- min-width: 120rpx;
- }
- .coordinate-value {
- color: #333333;
- font-weight: 500;
- flex: 1;
- }
- /* 天地图控件层级调整 */
- ::v-deep .tdt-bottom {
- z-index: 0;
- }
- ::v-deep .tdt-top {
- z-index: 0;
- }
- ::v-deep .tdt-bottom, .tdt-control {
- z-index: 0;
- }
- </style>
|