map.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <template>
  2. <div>
  3. <el-dialog title="地图选点" v-model="isShowDialog" width="900px" append-to-body>
  4. <div class="map-container">
  5. <div class="coordinate-search">
  6. <el-tooltip class="box-item" effect="dark" content="点击放大镜或回车按键检索地址" placement="top-start">
  7. <el-input v-model="searchKeyword" placeholder="搜索地名" @keyup.enter.native="searchByKeyword(searchKeyword)">
  8. <template #append>
  9. <el-button :icon="Search" @click="searchByKeyword(searchKeyword)" />
  10. </template>
  11. </el-input>
  12. </el-tooltip>
  13. <el-input v-model="lng" placeholder="经度" />
  14. <div>-</div>
  15. <el-input v-model="lat" placeholder="纬度" />
  16. <el-button @click="searchByCoordinate" type="primary">搜索</el-button>
  17. </div>
  18. <div class="map" ref="mapContainer"></div>
  19. <!-- 地址解析结果 -->
  20. <div class="address-result" v-if="address">
  21. <!-- 解析到地址:{{ address }}-->
  22. <el-form-item label="经度" class="input-item">
  23. <el-input v-model="lng" />
  24. </el-form-item>
  25. <el-form-item label="纬度" class="input-item">
  26. <el-input v-model="lat" />
  27. </el-form-item>
  28. <el-form-item label="详细地址" class="input-item">
  29. <el-input v-model="address" />
  30. </el-form-item>
  31. <el-button @click="confirmAddress" style="margin-left: 10px;" type="success">确认</el-button>
  32. </div>
  33. </div>
  34. </el-dialog>
  35. </div>
  36. </template>
  37. <script lang="ts" setup>
  38. import { defineEmits, defineExpose, nextTick, ref } from 'vue';
  39. import { Search } from '@element-plus/icons-vue';
  40. import { initMap } from '/@/utils/map';
  41. const mapContainer = ref<HTMLElement | null>(null);
  42. const address = ref('');
  43. const lng = ref('');
  44. const lat = ref('');
  45. const oldAddress = ref('');
  46. const searchKeyword = ref(''); // 搜索输入框的值
  47. const isShowDialog = ref(false);
  48. const marker = ref<any>(null);
  49. let BMapGL: any = null;
  50. let map: any = null;
  51. const openDialog = (row: any) => {
  52. oldAddress.value = '';
  53. isShowDialog.value = true;
  54. nextTick(async () => {
  55. const { BMapGL: theBMapGL, centerPoint } = await initMap()
  56. BMapGL = theBMapGL
  57. map = new BMapGL.Map(mapContainer.value!);
  58. // 如果添加了经纬度则进入地图后还原上次地址
  59. if (row.lng && row.lat) {
  60. lng.value = row.lng;
  61. lat.value = row.lat;
  62. searchByCoordinate();
  63. } else {
  64. map.centerAndZoom(centerPoint, 10);
  65. }
  66. map.enableScrollWheelZoom(true);
  67. const scaleCtrl = new BMapGL.ScaleControl(); // 添加比例尺控件
  68. map.addControl(scaleCtrl);
  69. const zoomCtrl = new BMapGL.ZoomControl(); // 添加缩放控件
  70. map.addControl(zoomCtrl);
  71. map.addEventListener('click', (e: any) => {
  72. lng.value = e.latlng.lng.toFixed(5);
  73. lat.value = e.latlng.lat.toFixed(5);
  74. setMarker(e.latlng.lng.toFixed(5), e.latlng.lat.toFixed(5));
  75. setAddressByCoordinate(e.latlng.lng.toFixed(5), e.latlng.lat.toFixed(5));
  76. return false; // 阻止事件的冒泡和默认行为
  77. });
  78. map.addEventListener('zoomend', () => {
  79. const point = new BMapGL.Point(lng.value, lat.value);
  80. const marker = new BMapGL.Marker(point);
  81. // 获取标记位置
  82. const position = marker.getPosition();
  83. map?.setCenter(position); // 将标点设置为地图中心
  84. });
  85. if (row.address) {
  86. oldAddress.value = row.address;
  87. }
  88. });
  89. lng.value = "";
  90. lat.value = "";
  91. searchKeyword.value = "";
  92. };
  93. const confirmAddress = () => {
  94. isShowDialog.value = false;
  95. emit('updateMap', { lng: lng.value, lat: lat.value, address: address.value });
  96. };
  97. const setMarker = (lng: string, lat: string) => {
  98. // 删除之前的标记
  99. if (marker.value) {
  100. map?.removeOverlay(marker.value);
  101. }
  102. // 创建新的标记
  103. const point = new BMapGL.Point(lng, lat);
  104. marker.value = new BMapGL.Marker(point);
  105. map?.addOverlay(new BMapGL.Marker(point));
  106. // 移动地图中心到选点位置
  107. map?.setCenter(point);
  108. map?.centerAndZoom(point, 10);
  109. };
  110. const setAddressByCoordinate = (lng: string | number, lat: string | number) => {
  111. // 新查询经纬度方法
  112. map?.centerAndZoom(new BMapGL.Point(lng, lat), 18);
  113. // 创建地理编码实例, 并配置参数获取乡镇级数据
  114. const myGeo = new BMapGL.Geocoder({ extensions_town: true });
  115. // 根据坐标得到地址描述
  116. myGeo.getLocation(new BMapGL.Point(lng, lat), function (result: any) {
  117. if (result) {
  118. address.value = result.content.poi_desc;
  119. if (oldAddress.value) {
  120. address.value = oldAddress.value;
  121. }
  122. }
  123. });
  124. // 旧查询经纬度方法
  125. // const point = new BMapGL.Point(lng, lat);
  126. // const geocoder = new BMapGL.Geocoder();
  127. // geocoder.getPoint(point, (pointResult: any) => {
  128. // if (pointResult) {
  129. // const locationPoint = new BMapGL.Point(pointResult.lng, pointResult.lat);
  130. // geocoder.getLocation(locationPoint, (result: any) => {
  131. // if (result) {
  132. // // console.log(result);
  133. // // const formattedAddress = result.address;
  134. // // address.value = formattedAddress;
  135. // if (oldAddress.value) {
  136. // address.value = oldAddress.value;
  137. // }
  138. // }
  139. // });
  140. // }
  141. // });
  142. };
  143. const searchByCoordinate = () => {
  144. if (lng.value && lat.value) {
  145. setMarker(lng.value, lat.value);
  146. setAddressByCoordinate(lng.value, lat.value);
  147. } else if (searchKeyword.value) {
  148. lng.value = "";
  149. lat.value = "";
  150. searchByKeyword(searchKeyword.value);
  151. }
  152. };
  153. const searchByKeyword = (keyword?: string) => {
  154. if (keyword) {
  155. const localSearch = new BMapGL.LocalSearch(map);
  156. localSearch.setSearchCompleteCallback((searchResult: any) => {
  157. if (searchResult) {
  158. const poi = searchResult.getPoi(0);
  159. if (poi) {
  160. lng.value = poi.point.lng.toFixed(5);
  161. lat.value = poi.point.lat.toFixed(5);
  162. setMarker(poi.point.lng.toFixed(5), poi.point.lat.toFixed(5));
  163. setAddressByCoordinate(poi.point.lng.toFixed(5), poi.point.lat.toFixed(5));
  164. }
  165. }
  166. });
  167. address.value = keyword;
  168. localSearch.search(keyword ? keyword : searchKeyword.value);
  169. }
  170. };
  171. const emit = defineEmits(['updateMap']);
  172. defineExpose({ openDialog });
  173. </script>
  174. <style scoped>
  175. .map-container {
  176. display: flex;
  177. flex-direction: column;
  178. align-items: center;
  179. }
  180. .map {
  181. width: 100%;
  182. height: 50vh;
  183. }
  184. .coordinate-search {
  185. display: flex;
  186. margin-bottom: 20px;
  187. }
  188. .coordinate-search>div {
  189. margin-right: 10px;
  190. }
  191. .coordinate-search input {
  192. margin-right: 10px;
  193. width: 100px;
  194. }
  195. .input-item {
  196. margin-right: 10px;
  197. }
  198. .address-result {
  199. display: flex;
  200. flex-direction: row;
  201. margin-top: 20px;
  202. }
  203. </style>