com-amap.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <!-- 地图选择地址组件(高德版本) -->
  2. <template id="com-amap">
  3. <div id="amap-container">
  4. <el-input id="search-input" v-model="searchValue" class="input-with" placeholder="请输入地址" clearable @clear="handelclearInput" @keyup.native.enter="handelSearch">
  5. <el-button slot="append" size="small" type="primary" icon="el-icon-search" @click="handelSearch">搜索</el-button>
  6. </el-input>
  7. <el-row class="address-space">
  8. <div class="address-space-show">
  9. <el-input :value="getShowAddressText()" :disabled="true">
  10. <template slot="prepend">当前地址是:</template>
  11. </el-input>
  12. <el-button size="small" type="primary" class="confirm-btn" @click="handelSave">使用该地址</el-button>
  13. </div>
  14. </el-row>
  15. <el-row>
  16. <el-col :span="16">
  17. <div id="lan-amap"></div>
  18. </el-col>
  19. <el-col :span="8">
  20. <div id="searchResultPanel"></div>
  21. </el-col>
  22. </el-row>
  23. </div>
  24. </template>
  25. <!-- 使用前请先登录高德开发者平台,申请应用,使用真实的key和安全秘钥才能正常使用 -->
  26. <script type="text/javascript">
  27. let securityJsCode = "<?= \Yii::$app->services->setting->platform->get('map.amap_jsapi_secret') ?>"
  28. console.log('securityJsCode', securityJsCode)
  29. window._AMapSecurityConfig = {
  30. securityJsCode: securityJsCode,
  31. }
  32. </script>
  33. <script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.4&key=<?= \Yii::$app->services->setting->platform->get('map.amap_jsapi_key') ?>"></script>
  34. <script>
  35. const AMap = window.AMap;
  36. Vue.component('com-amap', {
  37. template: '#com-amap',
  38. props: {
  39. defaultValue: {
  40. type: String,
  41. default: function() {
  42. return ''
  43. }
  44. },
  45. longitude: {
  46. type: Number,
  47. default: function() {
  48. return 0.00
  49. }
  50. },
  51. latitude: {
  52. type: Number,
  53. default: function() {
  54. return 0.00
  55. }
  56. }
  57. },
  58. data() {
  59. return {
  60. defaultCity: "北京",
  61. // 地图对象
  62. map: null,
  63. // 定位默认地址 | 搜索后选择的地址
  64. formattedAddress: null,
  65. // 地址对应的经纬度信息
  66. position: {},
  67. // 检索关键字
  68. searchValue: "",
  69. // 检索函数对象
  70. placeSearch: null,
  71. // 检索结果数据数据
  72. searchInfoList: [],
  73. // 地图标记
  74. marker: "",
  75. // 地址解析(正向)
  76. geocoder: "",
  77. // 地址名称
  78. name: "",
  79. lat: '',
  80. lng: '',
  81. };
  82. },
  83. watch: {
  84. defaultValue: {
  85. immediate: true,
  86. handler(val) {
  87. this.searchValue = val
  88. },
  89. },
  90. latitude: {
  91. immediate: true,
  92. handler(val) {
  93. this.lat = val
  94. },
  95. },
  96. longitude: {
  97. immediate: true,
  98. handler(val) {
  99. this.lng = val
  100. },
  101. },
  102. },
  103. mounted() {
  104. // 初始化地图页面
  105. this.initMap();
  106. },
  107. beforeDestroy() {
  108. // 销毁地图
  109. this.map.destroy();
  110. },
  111. methods: {
  112. // 初始化地图页面
  113. initMap() {
  114. this.map = new AMap.Map("lan-amap", {
  115. resizeEnable: true,
  116. zoom: 50
  117. });
  118. // 添加工具栏
  119. this.map.plugin(["AMap.ToolBar", "AMap.Scale", "AMap.OverView"], () => {
  120. // 工具条
  121. const toolbar = new AMap.ToolBar();
  122. // 比例尺
  123. const scale = new AMap.Scale();
  124. // 显示鹰眼
  125. const overView = new AMap.OverView();
  126. this.map.addControl(toolbar);
  127. this.map.addControl(scale);
  128. this.map.addControl(overView);
  129. });
  130. // 添加maker
  131. this.setMaker();
  132. // 添加鼠标点选地图选择地址
  133. this.addAmapGeocoder();
  134. // 添加定位
  135. this.addAMapGeolocation();
  136. // 添加检索提示
  137. this.addAMapAutocompletePlaceSearch();
  138. if (this.defaultValue) {
  139. this.handelSearch()
  140. this.formattedAddress = this.defaultValue
  141. }
  142. },
  143. // 添加maker
  144. setMaker() {
  145. this.marker = new AMap.Marker();
  146. this.map.add(this.marker);
  147. // 添加解析地理位置插件
  148. this.map.plugin("AMap.Geocoder", () => {
  149. // 异步加载插件
  150. this.geocoder = new AMap.Geocoder({
  151. city: this.defaultCity, // 默认:“全国”
  152. radius: 1000 // 范围,默认:500
  153. });
  154. });
  155. },
  156. // 添加鼠标点选地图选择地址
  157. addAmapGeocoder() {
  158. // 添加maker
  159. this.setMaker();
  160. // 地图添加点击事件
  161. this.map.on("click", e => {
  162. const lnglat = [e.lnglat.lng, e.lnglat.lat];
  163. this.marker.setPosition(lnglat);
  164. this.geocoder.getAddress(lnglat, (status, result) => {
  165. if (status === "complete" && result.regeocode) {
  166. const res = result.regeocode;
  167. const data = {
  168. // 地址名称
  169. adress: res.formattedAddress,
  170. // 纬度lat
  171. lat: lnglat[1],
  172. // 经度lng
  173. lng: lnglat[0]
  174. };
  175. this.formattedAddress = res.formattedAddress;
  176. this.position = data;
  177. this.lng = lnglat[0]
  178. this.lat = lnglat[1]
  179. } else {
  180. alert(JSON.stringify(result));
  181. }
  182. });
  183. });
  184. },
  185. // 添加自动定位
  186. addAMapGeolocation() {
  187. this.map.plugin("AMap.Geolocation", () => {
  188. const geolocation = new AMap.Geolocation({
  189. // 是否使用高精度定位,默认:true
  190. enableHighAccuracy: true,
  191. // 设置定位超时时间,默认:无穷大
  192. timeout: 10000,
  193. // 定位按钮的停靠位置的偏移量,默认:Pixel(10, 20)
  194. buttonOffset: new AMap.Pixel(200, 200),
  195. // 定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
  196. zoomToAccuracy: true,
  197. // 定位按钮的排放位置, RB表示右下
  198. buttonPosition: "RB"
  199. });
  200. // 获取当前位置
  201. geolocation.getCurrentPosition();
  202. // 添加定位当前城市成功监听
  203. AMap.event.addListener(
  204. geolocation,
  205. "complete",
  206. this.onCurrentPositionComplete
  207. );
  208. // 添加定位当前城市发生错误监听
  209. AMap.event.addListener(
  210. geolocation,
  211. "error",
  212. this.onCurrentPositionError
  213. );
  214. });
  215. },
  216. // 添加检索提示检索
  217. addAMapAutocompletePlaceSearch() {
  218. // 自动提示
  219. this.map.plugin("AMap.Autocomplete", () => {
  220. const auto = new AMap.Autocomplete({
  221. city: this.defaultCity,
  222. input: "search-input"
  223. });
  224. // 添加检索监听
  225. AMap.event.addListener(auto, "select", this.onSelectAutocomplete);
  226. });
  227. // 检索服务
  228. AMap.service(["AMap.PlaceSearch"], () => {
  229. // 构造地点查询类
  230. this.placeSearch = new AMap.PlaceSearch({
  231. type: "", // 兴趣点类别
  232. pageSize: 5, // 单页显示结果条数
  233. pageIndex: 1, // 页码
  234. city: this.defaultCity, // 兴趣点城市
  235. citylimit: false, // 是否强制限制在设置的城市内搜索
  236. map: this.map, // 展现结果的地图实例
  237. panel: "searchResultPanel", // 结果列表将在此容器中进行展示。
  238. autoFitView: true // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
  239. });
  240. });
  241. // 添加检索监听
  242. AMap.event.addListener(
  243. this.placeSearch,
  244. "listElementClick",
  245. this.onSelectSearch
  246. );
  247. },
  248. // 定位当前城市成功回调
  249. onCurrentPositionComplete(res) {
  250. // 添加maker
  251. this.setMaker();
  252. const lnglat = [res.position.lng, res.position.lat];
  253. this.marker.setPosition(lnglat);
  254. console.log(res, "res");
  255. this.formattedAddress = res.formattedAddress;
  256. this.position = res.position;
  257. this.lng = res.position.lng
  258. this.lat = res.position.lat
  259. },
  260. // 定位当前城市发生错误回调
  261. onCurrentPositionError(err) {
  262. console.log(err);
  263. },
  264. // 按钮触发检索
  265. handelSearch() {
  266. this.placeSearch.search(this.searchValue, (status, info) => {
  267. this.searchInfoList = info.poiList.pois;
  268. });
  269. },
  270. // 选择自动提示数据事件回调
  271. onSelectAutocomplete(e) {
  272. this.searchValue = e.poi.name;
  273. this.handelSearch();
  274. },
  275. // 选择检索数据结果事件回调
  276. onSelectSearch(e) {
  277. const res = e.data;
  278. this.formattedAddress = res.cityname + res.adname + res.address;
  279. this.name = res.name;
  280. this.position = res.location;
  281. let lng = e.data.location.lng
  282. let lat = e.data.location.lat
  283. this.lng = lng
  284. this.lat = lat
  285. },
  286. // 清除input里的值,清除搜索结果,再次初始化map
  287. handelclearInput() {
  288. document.querySelector("#searchResultPanel").innerHTML = "";
  289. },
  290. // 保存当前选择的地址,分发事件
  291. handelSave() {
  292. this.searchValue = this.formattedAddress;
  293. const {
  294. lat,
  295. lng
  296. } = this.position;
  297. const data = {
  298. name: this.name,
  299. // 地址名称
  300. address: this.formattedAddress,
  301. // 纬度lat
  302. lat,
  303. // 经度lng
  304. lng
  305. };
  306. this.$emit("get-position", data);
  307. },
  308. getShowAddressText() {
  309. if (this.formattedAddress) {
  310. return `${this.formattedAddress} [${this.lng} , ${this.lat}]`
  311. }
  312. return ''
  313. }
  314. }
  315. })
  316. </script>
  317. <style lang="scss">
  318. #amap-container {
  319. width: 100%;
  320. }
  321. #searchResultPanel {
  322. margin-top: 10px;
  323. }
  324. #amap-container .el-input__clear {
  325. line-height: 34px;
  326. }
  327. #amap-container #lan-amap {
  328. height: 60vh;
  329. margin-top: 10px;
  330. border: 1px solid #ccc;
  331. }
  332. #amap-container .input-with {
  333. /* position: fixed; */
  334. /* top: 40px; */
  335. z-index: 1;
  336. }
  337. #amap-container .address {
  338. color: #373737;
  339. }
  340. .amap-sug-result {
  341. z-index: 99999;
  342. }
  343. .address-space {
  344. padding: 10px 0;
  345. }
  346. .address-space-show {
  347. display: flex;
  348. align-items: center;
  349. }
  350. .address-space div.el-input-group__append {
  351. background-color: #409eff;
  352. color: #fff;
  353. cursor: pointer;
  354. }
  355. .address-space .confirm-btn {
  356. height: 40px;
  357. line-height: 40px;
  358. display: flex;
  359. justify-content: center;
  360. align-items: center;
  361. }
  362. </style>