test.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Vue2 百度地图位置搜索</title>
  7. <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js"></script>
  8. <script src="https://unpkg.com/vue-baidu-map"></script>
  9. <style>
  10. * {
  11. margin: 0;
  12. padding: 0;
  13. box-sizing: border-box;
  14. font-family: 'Microsoft YaHei', sans-serif;
  15. }
  16. body {
  17. background-color: #f5f7fa;
  18. color: #333;
  19. line-height: 1.6;
  20. }
  21. .container {
  22. max-width: 1200px;
  23. margin: 0 auto;
  24. padding: 20px;
  25. }
  26. header {
  27. text-align: center;
  28. margin-bottom: 30px;
  29. padding: 20px;
  30. background: linear-gradient(135deg, #3385ff 0%, #2d6cfa 100%);
  31. color: white;
  32. border-radius: 10px;
  33. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  34. }
  35. h1 {
  36. font-size: 2.2rem;
  37. margin-bottom: 10px;
  38. }
  39. .subtitle {
  40. font-size: 1.1rem;
  41. opacity: 0.9;
  42. }
  43. .app-container {
  44. display: flex;
  45. flex-wrap: wrap;
  46. gap: 20px;
  47. }
  48. .map-section {
  49. flex: 2;
  50. min-width: 300px;
  51. }
  52. .info-section {
  53. flex: 1;
  54. min-width: 300px;
  55. background: white;
  56. border-radius: 10px;
  57. padding: 20px;
  58. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
  59. }
  60. .map-container {
  61. width: 100%;
  62. height: 500px;
  63. border-radius: 10px;
  64. overflow: hidden;
  65. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  66. }
  67. .search-box {
  68. display: flex;
  69. margin-bottom: 20px;
  70. }
  71. .search-input {
  72. flex: 1;
  73. padding: 12px 15px;
  74. border: 1px solid #ddd;
  75. border-radius: 5px 0 0 5px;
  76. font-size: 16px;
  77. outline: none;
  78. transition: border 0.3s;
  79. }
  80. .search-input:focus {
  81. border-color: #3385ff;
  82. }
  83. .search-btn {
  84. padding: 0 20px;
  85. background: #3385ff;
  86. color: white;
  87. border: none;
  88. border-radius: 0 5px 5px 0;
  89. cursor: pointer;
  90. font-size: 16px;
  91. transition: background 0.3s;
  92. }
  93. .search-btn:hover {
  94. background: #2d6cfa;
  95. }
  96. .location-info {
  97. margin-top: 20px;
  98. padding: 15px;
  99. background: #f8f9fa;
  100. border-radius: 8px;
  101. border-left: 4px solid #3385ff;
  102. }
  103. .info-title {
  104. font-weight: bold;
  105. margin-bottom: 10px;
  106. color: #3385ff;
  107. display: flex;
  108. align-items: center;
  109. }
  110. .info-title i {
  111. margin-right: 8px;
  112. }
  113. .coordinates, .address {
  114. margin: 8px 0;
  115. padding: 8px 0;
  116. border-bottom: 1px dashed #e0e0e0;
  117. }
  118. .coordinates span, .address span {
  119. font-weight: bold;
  120. color: #555;
  121. }
  122. .coordinate-row {
  123. display: flex;
  124. justify-content: space-between;
  125. margin-bottom: 8px;
  126. }
  127. .coordinate-system {
  128. font-weight: bold;
  129. color: #3385ff;
  130. }
  131. .coordinate-value {
  132. font-family: monospace;
  133. background: #eef5ff;
  134. padding: 2px 6px;
  135. border-radius: 4px;
  136. }
  137. .instruction {
  138. margin-top: 20px;
  139. padding: 15px;
  140. background: #e8f4ff;
  141. border-radius: 8px;
  142. font-size: 14px;
  143. color: #2c3e50;
  144. }
  145. .search-results {
  146. margin-top: 20px;
  147. max-height: 300px;
  148. overflow-y: auto;
  149. border: 1px solid #e0e0e0;
  150. border-radius: 8px;
  151. }
  152. .result-item {
  153. padding: 10px 15px;
  154. border-bottom: 1px solid #eee;
  155. cursor: pointer;
  156. transition: background 0.2s;
  157. }
  158. .result-item:hover {
  159. background: #f0f7ff;
  160. }
  161. .result-item:last-child {
  162. border-bottom: none;
  163. }
  164. .result-name {
  165. font-weight: bold;
  166. margin-bottom: 5px;
  167. color: #3385ff;
  168. }
  169. .result-address {
  170. font-size: 14px;
  171. color: #666;
  172. }
  173. .result-distance {
  174. font-size: 12px;
  175. color: #888;
  176. margin-top: 4px;
  177. }
  178. footer {
  179. text-align: center;
  180. margin-top: 30px;
  181. padding: 20px;
  182. color: #666;
  183. font-size: 14px;
  184. }
  185. .status-message {
  186. padding: 10px;
  187. margin: 10px 0;
  188. border-radius: 5px;
  189. text-align: center;
  190. }
  191. .status-success {
  192. background-color: #e8f5e9;
  193. color: #2e7d32;
  194. }
  195. .status-error {
  196. background-color: #ffebee;
  197. color: #c62828;
  198. }
  199. .loading {
  200. display: inline-block;
  201. width: 20px;
  202. height: 20px;
  203. border: 3px solid #f3f3f3;
  204. border-top: 3px solid #3385ff;
  205. border-radius: 50%;
  206. animation: spin 1s linear infinite;
  207. margin-right: 10px;
  208. }
  209. @keyframes spin {
  210. 0% { transform: rotate(0deg); }
  211. 100% { transform: rotate(360deg); }
  212. }
  213. @media (max-width: 768px) {
  214. .app-container {
  215. flex-direction: column;
  216. }
  217. .map-container {
  218. height: 300px;
  219. }
  220. }
  221. </style>
  222. </head>
  223. <body>
  224. <div id="app" class="container">
  225. <header>
  226. <h1>Vue2 百度地图位置搜索</h1>
  227. <p class="subtitle">使用 vue-baidu-map 插件实现位置搜索功能</p>
  228. </header>
  229. <div class="app-container">
  230. <div class="map-section">
  231. <div class="search-box">
  232. <input type="text" v-model="searchKeyword" class="search-input" placeholder="输入地点名称进行搜索..." @keyup.enter="searchPlace">
  233. <button @click="searchPlace" class="search-btn">搜索</button>
  234. </div>
  235. <div v-if="statusMessage" class="status-message" :class="statusClass">
  236. {{ statusMessage }}
  237. </div>
  238. <!-- 百度地图容器 -->
  239. <baidu-map class="map-container"
  240. :center="mapCenter"
  241. :zoom="zoom"
  242. :scroll-wheel-zoom="true"
  243. @ready="mapReady"
  244. @click="mapClick">
  245. <!-- 地图标记 -->
  246. <bm-marker :position="markerPosition"
  247. :dragging="true"
  248. @dragend="markerDragEnd"
  249. v-if="markerPosition.lng">
  250. </bm-marker>
  251. <!-- 本地搜索 -->
  252. <bm-local-search :keyword="searchKeyword"
  253. :auto-viewport="true"
  254. :location="searchLocation"
  255. @searchcomplete="searchComplete"
  256. @infohtmlset="infoHtmlSet"
  257. v-if="searchKeyword && isMapReady">
  258. </bm-local-search>
  259. </baidu-map>
  260. </div>
  261. <div class="info-section">
  262. <h2 class="info-title"><i>📍</i> 位置信息</h2>
  263. <div v-if="selectedLocation" class="location-info">
  264. <div class="coordinates">
  265. <div class="coordinate-row">
  266. <span class="coordinate-system">经纬度:</span>
  267. <span class="coordinate-value">{{ selectedLocation.lng.toFixed(6) }}, {{ selectedLocation.lat.toFixed(6) }}</span>
  268. </div>
  269. </div>
  270. <div class="address">
  271. <span>详细地址:</span>
  272. {{ selectedLocation.address || '正在获取中...' }}
  273. </div>
  274. </div>
  275. <div v-else class="instruction">
  276. 请点击地图上的任意位置,或使用搜索功能选择地点,此处将显示该位置的坐标信息和详细地址。
  277. </div>
  278. <div v-if="searchResults.length > 0" class="search-results">
  279. <h3>搜索结果 ({{ searchResults.length }})</h3>
  280. <div v-for="(result, index) in searchResults" :key="index"
  281. class="result-item" @click="selectSearchResult(result)">
  282. <div class="result-name">{{ result.title }}</div>
  283. <div class="result-address">{{ result.address }}</div>
  284. <div class="result-distance" v-if="result.distance">距离: {{ result.distance }}米</div>
  285. </div>
  286. </div>
  287. </div>
  288. </div>
  289. <footer>
  290. <p>Vue2 + 百度地图位置搜索示例 | 使用 vue-baidu-map 插件</p>
  291. </footer>
  292. </div>
  293. <script>
  294. // 配置百度地图AK(实际使用时请替换为您的AK)
  295. Vue.use(window.VueBaiduMap.default, {
  296. ak: '您的百度地图AK'
  297. });
  298. new Vue({
  299. el: '#app',
  300. data: {
  301. map: null,
  302. BMap: null,
  303. isMapReady: false,
  304. mapCenter: {lng: 116.404, lat: 39.915}, // 默认中心点(北京)
  305. zoom: 12,
  306. searchKeyword: '',
  307. searchLocation: '北京',
  308. selectedLocation: null,
  309. markerPosition: {},
  310. searchResults: [],
  311. statusMessage: '',
  312. statusClass: ''
  313. },
  314. mounted() {
  315. // 组件挂载后,地图会在ready回调中初始化
  316. },
  317. methods: {
  318. // 地图初始化完成回调
  319. mapReady({BMap, map}) {
  320. this.BMap = BMap;
  321. this.map = map;
  322. this.isMapReady = true;
  323. this.showStatus('地图加载完成', 'status-success');
  324. // 添加地图控件
  325. map.addControl(new BMap.NavigationControl());
  326. map.addControl(new BMap.ScaleControl());
  327. map.addControl(new BMap.OverviewMapControl());
  328. console.log('百度地图初始化完成');
  329. },
  330. // 地图点击事件
  331. mapClick(e) {
  332. if (!this.isMapReady) return;
  333. const point = e.point;
  334. this.markerPosition = {lng: point.lng, lat: point.lat};
  335. // 使用逆地理编码获取地址
  336. const geocoder = new this.BMap.Geocoder();
  337. geocoder.getLocation(point, (result) => {
  338. if (result) {
  339. this.selectedLocation = {
  340. lng: point.lng,
  341. lat: point.lat,
  342. address: result.address
  343. };
  344. this.showStatus('位置选择成功', 'status-success');
  345. }
  346. });
  347. },
  348. // 标记点拖拽结束
  349. markerDragEnd(e) {
  350. const point = e.point;
  351. this.markerPosition = {lng: point.lng, lat: point.lat};
  352. // 使用逆地理编码获取地址
  353. const geocoder = new this.BMap.Geocoder();
  354. geocoder.getLocation(point, (result) => {
  355. if (result) {
  356. this.selectedLocation = {
  357. lng: point.lng,
  358. lat: point.lat,
  359. address: result.address
  360. };
  361. this.showStatus('位置已更新', 'status-success');
  362. }
  363. });
  364. },
  365. // 执行地点搜索
  366. searchPlace() {
  367. if (!this.searchKeyword.trim()) {
  368. this.showStatus('请输入搜索关键词', 'status-error');
  369. return;
  370. }
  371. if (!this.isMapReady) {
  372. this.showStatus('地图尚未加载完成,请稍后再试', 'status-error');
  373. return;
  374. }
  375. this.showStatus('搜索中...', '');
  376. console.log('搜索关键词:', this.searchKeyword);
  377. // 清空之前的结果
  378. this.searchResults = [];
  379. },
  380. // 搜索完成回调
  381. searchComplete(results) {
  382. if (!results) return;
  383. // 将搜索结果转换为简单格式
  384. this.searchResults = results.Kr && results.Kr.map(item => {
  385. return {
  386. title: item.title,
  387. address: item.address,
  388. point: item.point,
  389. distance: item.distance || null
  390. };
  391. }) || [];
  392. if (this.searchResults.length > 0) {
  393. this.showStatus(`找到 ${this.searchResults.length} 个结果`, 'status-success');
  394. } else {
  395. this.showStatus('未找到相关地点', 'status-error');
  396. }
  397. console.log('搜索结果:', this.searchResults);
  398. },
  399. // 信息窗口内容设置回调
  400. infoHtmlSet(e) {
  401. // 可以在这里处理信息窗口内容
  402. console.log('信息窗口内容:', e);
  403. },
  404. // 选择搜索结果
  405. selectSearchResult(result) {
  406. this.markerPosition = {lng: result.point.lng, lat: result.point.lat};
  407. this.mapCenter = this.markerPosition;
  408. this.zoom = 16;
  409. this.selectedLocation = {
  410. lng: result.point.lng,
  411. lat: result.point.lat,
  412. address: result.address
  413. };
  414. this.showStatus(`已选择: ${result.title}`, 'status-success');
  415. },
  416. // 显示状态消息
  417. showStatus(message, className) {
  418. this.statusMessage = message;
  419. this.statusClass = className;
  420. // 3秒后自动清除消息
  421. if (className !== '') {
  422. setTimeout(() => {
  423. this.statusMessage = '';
  424. }, 3000);
  425. }
  426. }
  427. }
  428. });
  429. </script>
  430. </body>
  431. </html>