踩坑日记:在react(ant-design-pro)中使用BMap

写在前面

前两天接到了这样一个需求,在ant-design-pro模板项目中使用百度地图,实现关键字检索定位到某点,并在该点标注圆形围栏,且该围栏可编辑(自由改变圆形和半径)。最终效果如下

11.gif

下面说一下我在开发过程中遇到的坑,这里只说坑,至于申请密匙那些东西,自行百度。

react-bmap?

因项目对接要求,本需求必须使用百度地图(说是对接其他接口时不同地图之间有误差,我没试,暂且信了),于是我惯性的希望找到一个类似于 google-map-react的组件库,于是就有找到了react-bmap,安装使用没什么问题,可是当使用BMapLib时,发现还得用到其实例,然后写法上再依赖原百度地图API,个人感觉比较混乱,看issue时,发现同样有人在使用BMapLib是有一些其他问题,给出的解释大概为react-bmap只是对BMAP的基本封装,不涉及那些扩展方法,所以遇到扩展需求啥的还是得获取到map实例后做原生操作,于是个人感觉,好像react-bmap的封装比较基本。但本人本着不放弃的态度决定再尝试一下,于是有了下面这样的代码

import { Map, Marker, Circle, NavigationControl, InfoWindow, ScaleControl, OverviewMapControl } from 'react-bmap'

<Map center={{ lng: 116.402544, lat: 39.928216 }} zoom="11" enableScrollWheelZoom ref={this.getmap} >
{/*this.getmap用来其他操作地图实例用*/}
     <Marker position={{ lng: 116.402544, lat: 39.928216 }} />
     <NavigationControl />
      <ScaleControl />
      <Circle
       center={{ lng: 116.403119, lat: 39.929543 }}
       fillColor="blue"
       strokeColor="white"
       radius="3000"
       enableEditing
       />
      <OverviewMapControl />
      <InfoWindow position={{ lng: 116.402544, lat: 39.928216 }} text="内容" title="标题" />
</Map>

上面的代码是页面级的组件(我做demo用,实际项目是在弹层中渲染),但是我发现Circle控件在设置了enableEditing属性后,虽然出现了可编辑的原型,但组件卸载的时候,总会报出一堆错误,看文档发现enableEditing是一个方法,不是一个属性,也是需要拿到其实例来操作的。但在查阅文档时发现react-bmap的使用文档几乎没有,于是有点不耐烦了,其正确的使用方法也不想去探究了,于是决定,就使用未封装过的吧。这里不是吐槽哈,react-bmap对于基本需求还是很满足的。

JavaScript Api

  1. 第一个坑
const { BMap } = window

我们需要从window里面拿到BMap。再进行其他文档中的操作,看清楚字母大小写!!小编在使用的时候,写成了'BMAP',好几次怀疑自己是否引入了包或使用了正确的密匙,这是一个低级错误。另外就是注意要从window里面取。这里和官网上面的html demo写法不一样。

  1. 第二个坑,我的需求中不需要用到BMapLib.DrawingManager。这是做鼠标自由标注用的,而我的项目中是只做具体的某点的标注。因为对文档的不熟悉和对百度地图功能用途不够了解,导致了错误的方向,这里耽误了我半天的事件去研究,包括对其api的各种尝试,不过明白是怎么回事后才发现自己并不需要它。

3.第三个坑,antd Modal组件的挂载节点!!!经过前两个坑以后,基本文档已经翻了10多遍了。对文档基本熟悉后,采用了下面的方式实现关键字检索的操作。

componentDidMount(){
    const that = this
    // 初始化地图
    const map = new BMap.Map('container', { enableMapClick: false });
    map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); // 初始化地图,设置中心点坐标和地图级别
    const point = new BMap.Point(116.404, 39.915); // 设置中心点坐标
    map.centerAndZoom(point, 11);
    map.enableScrollWheelZoom(true)
    map.addControl(new BMap.NavigationControl());
    map.addControl(new BMap.ScaleControl());
    map.addControl(new BMap.OverviewMapControl());
    const ac = new BMap.Autocomplete( // 建立一个自动完成的对象
      {
        input: document.getElementById('suggestId'),
        location: map,
      });
    ac.addEventListener('onhighlight', e => { // 鼠标放在下拉列表上的事件
      let str = '';
      let DataValue = e.fromitem.value;
      let value = '';
      if (e.fromitem.index > -1) {
        value = DataValue.province + DataValue.city + DataValue.district + DataValue.street + DataValue.business;
      }
      str = `FromItem<br />index = ${e.fromitem.index}<br />value = ${value}`

      value = '';
      if (e.toitem.index > -1) {
        DataValue = e.toitem.value;
        value = DataValue.province + DataValue.city + DataValue.district + DataValue.street + DataValue.business;
      }
      str += `<br />ToItem<br />index = ${e.toitem.index}<br />value = ${value}`
      const searchResultPanel = document.getElementById('searchResultPanel')
      searchResultPanel.innerHTML = str
    });
    let myValue;
    ac.addEventListener('onconfirm', e => { // 鼠标点击下拉列表后的事件
      const _value = e.item.value;
      myValue = _value.province + _value.city + _value.district + _value.street + _value.business;
      document.getElementById('searchResultPanel').innerHTML = `onconfirm<br />index = ${e.item.index}<br />myValue = ${myValue}`;
      setPlace();
      that.formRef.current.setFieldsValue({ address: myValue })
    });

    function setPlace() {
      map.clearOverlays(); // 清除地图上所有覆盖物
      const local = new BMap.LocalSearch(map, { // 智能搜索
        onSearchComplete: myFun,
      });
      function myFun() {
        const pp = local.getResults().getPoi(0).point; // 获取第一个智能搜索的结果
        map.centerAndZoom(pp, 17);
        that.newCircle = new BMap.Circle(pp, 200, { strokeColor: "red", strokeWeight: 2, strokeOpacity: 0.5 }) // 添加标注
        map.addOverlay(that.newCircle)
        that.newCircle.enableEditing()
      }
      local.search(myValue);
    }
}

render() {
  return (
      <>
            <div id="r-result" style={{ width: '100%', marginBottom: '5px' }}><Input id="suggestId" style={{ width: '300px' }} allowClear placeholder="输入地点搜索..." /></div>
            <div id="searchResultPanel" style={{ border: '1px solid #C0C0C0', width: '150px', height: 'auto', display: 'none' }} />
            <div id="container" style={{ width: '100%', height: '600px' }} />
      </>
  )
}

上面的代码不需要详细看,和官网上面的一样,我主要想说的坑是上面的代码在页面组件中运行良好,在弹层组件中竟然会报错!大概是某个实例或者方法没有找到之类的。于是各种debug,各种验证,我发现,在生命周期中,本该通过document.getElementById('suggestId')获取到各种需要的dom节点,可是Modal组件里面的元素在DidMount生命周期中获取不到,于是思考、翻看API(这里又是俩小时的时间)。我忽然想到这可能和Modal组件默认挂载于document.body上有关。导致里面的元素不能在其挂载后立即拿到dom。(这是我猜的),于是,我看antd 文档里面的,getContainer设置为false让其挂载到当前节点。终于好了!!!不再报错了。很稳定。

  1. 第四个坑:自动补全弹层被遮挡!上面的地图加载没有问题后,我开始尝试关键字检索,可是发现搜索结果没有。一开始我是以为自动补全不生效呢(真是一步一个坑),于是对比了demo(页面级别组件)和我的项目(弹层组件),发现和demo中一样,我的项目也是出现了对应的‘检索结果Dom节点’,于是我想,这一定是弹层的z-index太大给遮挡了。于是百度后,发现果然有人遇到一样的问题,解决方案就是让搜索结果的弹层区域比Modal组件的z-index要高。于是我在react的全局样式文件中加这样一段css
.tangram-suggestion-main {z-index: 9999999999;}

因为z-index有最大值,干脆一顿9,超出最大值,直接让他取默认最大值了,这里偷懒了,没有取具体的最大值,感兴趣的可以自己看下。经过上面的样式修改,关键字检索算基本完事了。

这个时候对文档已经相当熟悉了,一路按照需求开发,可是又又又又遇到坑了。

  1. 第五坑。这个坑不知道该叫什么名字了,没兴趣的小伙伴可以撤了。因为和我的业务就有些相关了。我业务中要求编辑圆形,表单的值也得跟着变,表单中输入半径,圆的大小也会跟着变。当时思考了一会该监听什么样的事件去获取当前圆的信息,又是翻文档,http://lbsyun.baidu.com/cms/jsapi/reference/jsapi_reference_3_0.html#a3b16
    找到了对应的事件,到这里基本可以说没啥问题了,不过后面还是发现一个bug。在我输入表单半径利用Circle类的setRadius方法改变半径后,却发现,我的圆形的拖动点不好使了。点能拖动,可是圆缺不跟着变,这个时候代码手感真好,于是想到解决方案,在编辑表单设置圆的半径后禁用掉其编辑功能待我们鼠标划入到圆形中再开启,于是就有了下面的解决方案
//表单值改变触发
  radiusChange = (e) => {
    const arr = {...this.newCircle}
    const newArr = Object.keys(arr)
    if(newArr.length === 0){
     // 判断当前是否有具体地点
      message.warning('请先选择地点')
    }else {
      this.newCircle.disableEditing()
      this.newCircle.setRadius(e)
    }
  }

// didmount生命周期中的圆标记的处理方法中
        that.newCircle.addEventListener('lineupdate', debounce((target) => {
          that.CirclePoint = target.target.point
          that.formRef.current.setFieldsValue({ radius: parseInt(target.target.Ca, 10) })
        }, 200))
        that.newCircle.addEventListener('mouseover', debounce(() => {
          that.newCircle.enableEditing()
          that.inputnum.blur() //不知道为啥这里需要半径输入框脱标处理,是写的过程中发现的,脱标处理后就好了。算个小bug吧,注意一下
        }, 200))
  1. 第六坑,在搜索后,有很大几率出现圆的编辑圆形和地图地标详情重合的情况,如下图


    微信图片_20200515164702.png

    导致圆形没法拖动,这里的解决办法是,我们在初始化地图时设置

const map = new BMap.Map('container', { enableMapClick: false });

enableMapClick: false即可,这样就禁用掉了详情按钮。小坑一个。也记下来。

写在最后

经过上面一天多的踩坑,原本的需求基本也就实现了。核心代码也已经在上面了,有使用的同学,做好debug,把漏掉的代码补上,基本都是可以正常运行的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349