amap.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. <template>
  2. <div class="container">
  3. <div id="mapContainer" class="mapContainer" ref="mapContainer"></div>
  4. <div class="search-container" v-if="isPoiSearch">
  5. <div class="input-wrapper">
  6. <span class="search-label">搜索</span>
  7. <input id="searchText" type="text" class="search-text" placeholder="请输入搜索词"/>
  8. </div>
  9. </div>
  10. </div>
  11. </template>
  12. <script>
  13. /* eslint-disable */
  14. import {lazyAMapApiLoaderInstance} from "vue-amap";
  15. // import { setTimeout } from "timers";
  16. import {locationMixin} from "@/assets/js/mixin";
  17. export default {
  18. mixins: [locationMixin],
  19. data() {
  20. return {
  21. searchText: ""
  22. };
  23. },
  24. props: {
  25. // 经纬度坐标 [118.31, 37.27]
  26. position: {
  27. type: Array,
  28. default: () => []
  29. },
  30. // 圆形半径 (公里)
  31. radius: {
  32. type: Number,
  33. default: 0
  34. },
  35. // 缩放级别
  36. zoom: {
  37. type: Number,
  38. default: 16
  39. },
  40. // 模式:可选'normal'(显示商店定位)、'positionPicker'(商店位置拖拽选择)
  41. mode: {
  42. type: String,
  43. default: "normal"
  44. },
  45. // 是否根据选点搜索周边
  46. isPlaceSearch: {
  47. type: Boolean,
  48. default: false
  49. },
  50. // 搜索半径 (公里)
  51. searchRadius: {
  52. type: Number,
  53. default: 2
  54. },
  55. // 是否加载POI搜索
  56. isPoiSearch: {
  57. type: Boolean,
  58. default: false
  59. }
  60. },
  61. async mounted() {
  62. // 初始化加载地图
  63. console.time("map");
  64. await lazyAMapApiLoaderInstance.load();
  65. console.timeEnd("map");
  66. const option = {};
  67. if (this.position.length && this.position[0] && this.position[1]) {
  68. option.center = this.position;
  69. }
  70. if (this.zoom) {
  71. option.zoom = this.zoom;
  72. }
  73. option.scrollWheel = true;
  74. this.map = new AMap.Map(this.$refs.mapContainer, option);
  75. this.AMap = AMap;
  76. // 加载poi搜索组件
  77. if (this.isPoiSearch) {
  78. this._initPoiPicker(AMapUI);
  79. }
  80. if (this.mode === "positionPicker") {
  81. this._initPositionPicker(AMapUI);
  82. } else {
  83. // normal模式 只显示position位置或者设备当前定位位置
  84. if (!this.position.length) {
  85. // 未传location定位当前设备位置
  86. this.getCurrentPositon();
  87. } else {
  88. this.addMarker(this.position);
  89. if (this.radius > 0) {
  90. this.addCircle(this.position);
  91. }
  92. }
  93. }
  94. },
  95. methods: {
  96. addMarker(position, message) {
  97. const AMap = this.AMap;
  98. const map = this.map;
  99. // 先移除旧的点标记
  100. if (this.marker) {
  101. map.remove(this.marker);
  102. }
  103. // 创建一个 Marker 实例
  104. this.marker = new AMap.Marker({
  105. position: new AMap.LngLat(...position), // 经纬度构成的一维数组[116.39, 39.9]
  106. title: ""
  107. });
  108. // 将创建的点标记添加到已有的地图实例
  109. map.add(this.marker);
  110. // 处理InfoWindow
  111. if (message) {
  112. const infoWindow = new AMap.InfoWindow({
  113. position: position,
  114. offset: new AMap.Pixel(0, -20), // 纵向偏移
  115. showShadow: true, // 显示阴影
  116. content: message // 文字内容
  117. });
  118. infoWindow.open();
  119. }
  120. this.map.setCenter(this.marker.getPosition());
  121. },
  122. addCircle(position, radius) {
  123. const AMap = this.AMap;
  124. const map = this.map;
  125. this.circle = new AMap.Circle({
  126. center: new AMap.LngLat(...position), // 圆心位置
  127. radius: 1000 * radius, // 圆半径
  128. fillOpacity: 0.4,
  129. fillColor: "#1791fc",
  130. strokeWeight: 0
  131. });
  132. this.circle.setMap(map);
  133. // 缩放地图到合适的视野级别
  134. map.setFitView([this.circle]);
  135. // map.add(circleMarker);
  136. },
  137. // 初始化拖拽选择
  138. _initPositionPicker(AMapUI) {
  139. // 加载拖拽选择插件 positionPicker
  140. AMapUI.loadUI(["misc/PositionPicker"], PositionPicker => {
  141. var positionPicker = new PositionPicker({
  142. mode: "dragMap", // 设定为拖拽地图模式,可选'dragMap'、'dragMarker',默认为'dragMap'
  143. map: this.map // 依赖地图对象
  144. });
  145. positionPicker.on("success", positionResult => {
  146. // 抛出选取点信息
  147. this.$emit("selectLocation", positionResult);
  148. //
  149. if (this.isPlaceSearch) {
  150. this.searchPlace([
  151. positionResult.position.lng,
  152. positionResult.position.lat
  153. ]);
  154. }
  155. });
  156. positionPicker.on("fail", positionResult => {
  157. console.error(positionResult);
  158. });
  159. // 开始拖拽选择
  160. positionPicker.start();
  161. });
  162. },
  163. // 初始化poi搜索
  164. _initPoiPicker(AMapUI) {
  165. // 加载拖拽选择插件 PoiPicker
  166. AMapUI.loadUI(["misc/PoiPicker"], PoiPicker => {
  167. var poiPicker = new PoiPicker({
  168. input: "searchText" // 输入框id
  169. });
  170. // 监听poi选中信息
  171. poiPicker.on("poiPicked", poiResult => {
  172. // 用户选中的poi点信息
  173. const poi = poiResult.item;
  174. this.addMarker(
  175. [poi.location.lng, poi.location.lat],
  176. poi.name
  177. );
  178. });
  179. });
  180. },
  181. searchPlace([lng, lat]) {
  182. const placeSearch = new this.AMap.PlaceSearch({
  183. pageSize: 20, // 单页显示结果条数
  184. pageIndex: 1, // 页码
  185. city: this.city.adcode || "全国", // 兴趣点城市
  186. citylimit: true, // 是否强制限制在设置的城市内搜索
  187. extensions: "all"
  188. // map: this.map, // 展现结果的地图实例
  189. // autoFitView: true // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
  190. });
  191. var cpoint = [lng, lat]; // 中心点坐标
  192. placeSearch.searchNearBy(
  193. "",
  194. cpoint,
  195. 1000 * this.searchRadius,
  196. (status, result) => {
  197. if (status === "complete") {
  198. this.$emit("searchPlace", result.poiList.pois);
  199. }
  200. }
  201. );
  202. },
  203. searchByText(text, center) {
  204. const placeSearch = new this.AMap.PlaceSearch({
  205. // type:
  206. // "商务住宅|政府机构及社会团体|科教文化服务|公共设施|交通设施服务", // 兴趣点类别
  207. pageSize: 20, // 单页显示结果条数
  208. pageIndex: 1, // 页码
  209. city: this.city.adcode || "全国", // 兴趣点城市
  210. citylimit: true, // 是否强制限制在设置的城市内搜索
  211. extensions: "all"
  212. // map: this.map, // 展现结果的地图实例
  213. // autoFitView: true // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
  214. });
  215. let lng, lat;
  216. if (center && center.length > 0) {
  217. lng = center[0];
  218. lat = center[1];
  219. } else {
  220. lng = this.location[0];
  221. lat = this.location[1];
  222. }
  223. placeSearch.search(text, (status, result) => {
  224. if (status === "complete") {
  225. // console.log(result.poiList.pois);
  226. this.$emit("searchByText", result.poiList.pois);
  227. }
  228. });
  229. // if (lng && lat) {
  230. // var cpoint = [lng, lat]; // 中心点坐标
  231. // placeSearch.searchNearBy(
  232. // text,
  233. // cpoint,
  234. // 1000 * 50, // 搜索半价50公里 已经是最大值
  235. // (status, result) => {
  236. // console.log(result);
  237. // if (status === "complete") {
  238. // this.$emit("searchByText", result.poiList.pois);
  239. // }
  240. // }
  241. // );
  242. // } else {
  243. // this.$toast("请授权定位权限后搜索");
  244. // }
  245. }
  246. },
  247. watch: {
  248. radius(val) {
  249. if (this.circle) {
  250. this.circle.hide();
  251. }
  252. if (val > 0) {
  253. this.addCircle(this.position, this.radius);
  254. }
  255. },
  256. position(val) {
  257. if (val[0] && val[1] && this.map) {
  258. this.map.setCenter(val);
  259. this.addMarker(this.position);
  260. }
  261. }
  262. }
  263. };
  264. </script>
  265. <style lang="stylus" scoped>
  266. @import '~assets/main.styl';
  267. .container {
  268. position: relative;
  269. height: 100%;
  270. width: 100%;
  271. .mapContainer {
  272. position: relative;
  273. /* height 100vh */
  274. /* width 100vw */
  275. height: 100%;
  276. width: 100%;
  277. }
  278. .search-container {
  279. position: fixed;
  280. top: vw(20);
  281. left: vw(20);
  282. width: vw(250);
  283. background-color: grayF;
  284. padding: smallMargin smallMargin;
  285. border-radius: radius;
  286. min-width: vw(20);
  287. border-width: 0;
  288. box-shadow: 0 2px 6px 0 rgba(114, 124, 245, 0.5);
  289. .input-wrapper {
  290. display: flex;
  291. justify-content: center;
  292. .search-label {
  293. line-height: vw(15);
  294. flex: 0 0 vw(40);
  295. padding: titleMargin titleMargin;
  296. display: inline-block;
  297. font-size: word12;
  298. font-weight: bold;
  299. color: grayF;
  300. background-color: main-color;
  301. border: 1px solid main-color;
  302. text-align: center;
  303. }
  304. .search-text {
  305. flex: 0 1 vw(200);
  306. border: 1px solid main-color;
  307. padding: titleMargin titleMargin;
  308. font-size: word12;
  309. line-height: vw(15);
  310. }
  311. }
  312. }
  313. }
  314. </style>