Map.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. <template>
  2. <div :class="$attrs.class" :style="$attrs.style">
  3. <div v-if="!hasBmView" ref="view" style="width: 100%; height: 100%">
  4. </div>
  5. <slot></slot>
  6. </div>
  7. </template>
  8. <script>
  9. import bindEvents from '../base/bindEvent.js'
  10. import { checkType, setConfig, getConfig } from '../base/util.js'
  11. import EvenBus from '../base/eventBus.js'
  12. import getMapMethod from '../base/methodMap.js';
  13. import { mapLoadResolve } from '../utils';
  14. export default {
  15. name: 'bm-map',
  16. inheritAttrs: false,
  17. emits: ['ready', 'init', 'animationed'],
  18. props: {
  19. ak: {
  20. type: String
  21. },
  22. v: {
  23. type: String
  24. },
  25. type: {
  26. type: String
  27. },
  28. center: {
  29. type: [Object, String]
  30. },
  31. zoom: {
  32. type: Number
  33. },
  34. minZoom: {
  35. type: Number
  36. },
  37. maxZoom: {
  38. type: Number
  39. },
  40. highResolution: {
  41. type: Boolean,
  42. default: true
  43. },
  44. mapClick: {
  45. type: Boolean,
  46. default: true
  47. },
  48. mapType: {
  49. type: String
  50. },
  51. dragging: {
  52. type: Boolean,
  53. default: true
  54. },
  55. scrollWheelZoom: {
  56. type: Boolean,
  57. default: false
  58. },
  59. doubleClickZoom: {
  60. type: Boolean,
  61. default: true
  62. },
  63. keyboard: {
  64. type: Boolean,
  65. default: true
  66. },
  67. inertialDragging: {
  68. type: Boolean,
  69. default: true
  70. },
  71. continuousZoom: {
  72. type: Boolean,
  73. default: true
  74. },
  75. pinchToZoom: {
  76. type: Boolean,
  77. default: true
  78. },
  79. autoResize: {
  80. type: Boolean,
  81. default: true
  82. },
  83. theme: {
  84. type: Array
  85. },
  86. mapStyle: {
  87. type: Object
  88. },
  89. hasAnimation: {
  90. type: Boolean,
  91. default: true
  92. },
  93. defaultAnimation: {
  94. type: Boolean,
  95. default: true
  96. }
  97. },
  98. watch: {
  99. center(val, oldVal) {
  100. const { map, zoom } = this
  101. if (checkType(val) === 'String' && val !== oldVal) {
  102. this.setCenterZoom(map, val, zoom);
  103. }
  104. },
  105. 'center.lng'(val, oldVal) {
  106. const { BMap, map, zoom, center } = this
  107. if (val !== oldVal && val >= -180 && val <= 180) {
  108. this.setCenterZoom(map, new BMap.Point(val, center.lat), zoom);
  109. }
  110. },
  111. 'center.lat'(val, oldVal) {
  112. const { BMap, map, zoom, center } = this
  113. if (val !== oldVal && val >= -74 && val <= 74) {
  114. this.setCenterZoom(map, new BMap.Point(center.lng, val), zoom);
  115. }
  116. },
  117. zoom(val, oldVal) {
  118. const { map } = this
  119. if (val !== oldVal && val >= 3 && val <= 19) {
  120. map.setZoom(val)
  121. }
  122. },
  123. minZoom(val) {
  124. const { map } = this
  125. map.setMinZoom(val)
  126. },
  127. maxZoom(val) {
  128. const { map } = this
  129. map.setMaxZoom(val)
  130. },
  131. highResolution() {
  132. this.reset()
  133. },
  134. mapClick() {
  135. this.reset()
  136. },
  137. mapType(val) {
  138. const { map } = this
  139. map.setMapType(window[val])
  140. },
  141. dragging(val) {
  142. const { map } = this
  143. val ? map.enableDragging() : map.disableDragging()
  144. },
  145. scrollWheelZoom(val) {
  146. const { map } = this
  147. val ? map.enableScrollWheelZoom() : map.disableScrollWheelZoom()
  148. },
  149. doubleClickZoom(val) {
  150. const { map } = this
  151. val ? map.enableDoubleClickZoom() : map.disableDoubleClickZoom()
  152. },
  153. keyboard(val) {
  154. const { map } = this
  155. val ? map.enableKeyboard() : map.disableKeyboard()
  156. },
  157. inertialDragging(val) {
  158. const { map } = this
  159. val ? map.enableInertialDragging() : map.disableInertialDragging()
  160. },
  161. continuousZoom(val) {
  162. const { map } = this
  163. val ? map.enableContinuousZoom() : map.disableContinuousZoom()
  164. },
  165. pinchToZoom(val) {
  166. const { map } = this
  167. val ? map.enablePinchToZoom() : map.disablePinchToZoom()
  168. },
  169. autoResize(val) {
  170. const { map } = this
  171. val ? map.enableAutoResize() : map.disableAutoResize()
  172. },
  173. theme(val) {
  174. const { map } = this
  175. map[getMapMethod('setMapStyle')]({ styleJson: val })
  176. },
  177. mapStyle: {
  178. handler(val) {
  179. const { map, theme } = this
  180. !theme && map[getMapMethod('setMapStyle')](val)
  181. },
  182. deep: true
  183. }
  184. },
  185. methods: {
  186. setMapOptions() {
  187. const { map, minZoom, maxZoom, mapType, dragging, scrollWheelZoom, doubleClickZoom, keyboard, inertialDragging, continuousZoom, pinchToZoom, autoResize } = this
  188. minZoom && map.setMinZoom(minZoom)
  189. maxZoom && map.setMaxZoom(maxZoom)
  190. mapType && map.setMapType(window[mapType])
  191. dragging ? map.enableDragging() : map.disableDragging()
  192. scrollWheelZoom ? map.enableScrollWheelZoom() : map.disableScrollWheelZoom()
  193. doubleClickZoom ? map.enableDoubleClickZoom() : map.disableDoubleClickZoom()
  194. keyboard ? map.enableKeyboard() : map.disableKeyboard()
  195. inertialDragging ? map.enableInertialDragging() : map.disableInertialDragging()
  196. continuousZoom ? map.enableContinuousZoom() : map.disableContinuousZoom()
  197. pinchToZoom ? map.enablePinchToZoom() : map.disablePinchToZoom()
  198. autoResize ? map.enableAutoResize() : map.disableAutoResize()
  199. },
  200. init(BMap) {
  201. if (this.map) {
  202. return
  203. }
  204. let $el = this.$refs.view
  205. if (this.$slots.default) {
  206. // for (let $node of this.$slots.default() || []) {
  207. // if ($node.type && $node.type.name && 'bm-view' === $node.type.name) {
  208. // this.hasBmView = true
  209. // $el = $node.elm // 获取不到$el 暂时去掉
  210. // }
  211. // }
  212. }
  213. const map = new BMap.Map($el, { enableHighResolution: this.highResolution, enableMapClick: this.mapClick })
  214. this.map = map
  215. const { setMapOptions, zoom, getCenterPoint, theme, mapStyle } = this
  216. setMapOptions()
  217. bindEvents.call(this, map)
  218. // 此处强行初始化一次地图 回避一个由于错误的 center 字符串导致初始化失败抛出的错误
  219. map.reset()
  220. this.setCenterZoom(map, getCenterPoint(), zoom);
  221. theme ? map[getMapMethod('setMapStyle')]({ styleJson: theme }) : (mapStyle && map[getMapMethod('setMapStyle')](mapStyle))
  222. let loadNum = 0;
  223. this.$emit('init', { BMap, map });
  224. EvenBus.$emit('init', { BMap, map });
  225. map.addEventListener('tilesloaded', () => {
  226. if (!loadNum) {
  227. loadNum++;
  228. this.$emit('ready', { BMap, map })
  229. EvenBus.$emit('ready', { BMap, map });
  230. }
  231. });
  232. map.addEventListener('loaded', () => {
  233. this.$emit('loaded', { BMap, map });
  234. EvenBus.$emit('loaded', { BMap, map });
  235. });
  236. },
  237. setCenterZoom(map, center, zoom) {
  238. if (getConfig().type === 'WebGL') {
  239. if (!this.hasAnimation || !this.defaultAnimation) {
  240. map.setCenter(center, {
  241. noAnimation: !this.hasAnimation,
  242. callback: () => {
  243. map.setZoom(zoom, {
  244. noAnimation: !this.hasAnimation,
  245. zoomCenter: center,
  246. callback: () => {
  247. this.$emit('animationed', { BMap: this.BMap, map });
  248. }
  249. });
  250. }
  251. });
  252. } else {
  253. map.centerAndZoom(center, zoom);
  254. }
  255. } else {
  256. map.centerAndZoom(center, zoom);
  257. }
  258. },
  259. getCenterPoint() {
  260. const { center, BMap } = this
  261. switch (checkType(center)) {
  262. case 'String': return center
  263. case 'Object': return new BMap.Point(center.lng, center.lat)
  264. default: return new BMap.Point()
  265. }
  266. },
  267. initMap(BMap) {
  268. this.BMap = BMap
  269. this.init(BMap)
  270. mapLoadResolve(BMap);
  271. },
  272. getMapScript() {
  273. if (!window.BMap) {
  274. window.BMap = {}
  275. window.BMap._preloader = new Promise((resolve, reject) => {
  276. window._initBaiduMap = function () {
  277. window.BMap = getConfig().type == 'WebGL' ? window.BMapGL : window.BMap;
  278. resolve(window.BMap)
  279. window.document.body.removeChild($script)
  280. window.BMap._preloader = null
  281. window._initBaiduMap = null
  282. }
  283. const $script = document.createElement('script')
  284. window.document.body.appendChild($script)
  285. switch (getConfig().type) {
  286. case 'WebGL':
  287. $script.src = `https://api.map.baidu.com/api?v=1.0&type=webgl&ak=${getConfig().ak}&callback=_initBaiduMap`
  288. break;
  289. default:
  290. $script.src = `https://api.map.baidu.com/api?v=${getConfig().v}&ak=${getConfig().ak}&callback=_initBaiduMap`
  291. }
  292. })
  293. return window.BMap._preloader
  294. } else if (!window.BMap._preloader) {
  295. return Promise.resolve(window.BMap)
  296. } else {
  297. return window.BMap._preloader
  298. }
  299. },
  300. reset() {
  301. const { getMapScript, initMap } = this
  302. getMapScript()
  303. .then(initMap)
  304. }
  305. },
  306. created() {
  307. const options = {};
  308. this.ak && (options.ak = this.ak);
  309. this.v && (options.v = this.v);
  310. this.type && (options.type = this.type);
  311. setConfig(options);
  312. },
  313. mounted() {
  314. this.reset()
  315. },
  316. data() {
  317. return {
  318. hasBmView: false,
  319. map: null,
  320. BMap: null,
  321. name: 'bm-map'
  322. }
  323. }
  324. }
  325. </script>