Taro 小程序自定义地图并接入高德sdk

小程序项目有用到需要自定义地图的需求,于是记录下操作流程

1、引入高德地图sdk包 下载地址:https://lbs.amap.com/api/wx/download
2、项目中导入并初始化

//导入
import amapFile from '../../../utils/libs/amap-wx.js'  //高德地图sdk
let myAmapFun
//初始化
  componentWillMount = () => {
    /// 初始化高德地图
    myAmapFun = new amapFile.AMapWX({ key: ThirdPartKey.amapKey })
  }

3、获取当前定位 并初始化气泡 并刷新地图底部poi商家显示

  componentDidMount() {
    /// 获取精准定位
    let that = this
    myAmapFun.getRegeo({
      success: (data) => {
        // markersData = data.markers;
        console.log(data)
        var {
          latitude,
          longitude
        } = that.state
        let { pois, addressComponent } = data[0].regeocodeData
        latitude = data[0].latitude
        longitude = data[0].longitude
        let marker
        if (pois.length > 0) {
          marker = this.getMarker(pois[0])
          /// 默认选中第0组数据
          pois[0].checked = true
        }
        /// 加上省市区 让地址变得长一些
        pois.map(item => {
          item.realaddress = addressComponent.province + addressComponent.city + addressComponent.district + item.address
        })
        var markers: any = []
        if (marker) {
          markers.push(marker)
        }
        this.setState({ latitude, longitude, pois, markers })
      },
      fail: (err) => {
        console.log(err)
      }
    })
  }

3、点击搜索进入到键盘输入实时获取周边商家的页面

  onInputValueChange = (e) => {
    const { value } = e.detail
    // console.log(value)
    if (value.length == 0) {

      this.setState({
        searchResults: [],
        // showSearch: false,
        keyword: '',
      }, () => {
        // Taro.hideKeyboard()
      });
      return
    }
    /// 搜索POI功能
    myAmapFun.getInputtips({
      keywords: value,
      // city: '杭州',
      // location: '120.299221,30.419153',
      success: (data) => {
        console.log(data)
        if (data && data.tips) {
          this.setState({
            keyword: value,
            searchResults: data.tips
          });
        }
      }
    })
  }

4、搜索结果点击后重新获取该点击定位的周边的POI并刷新显示

  onResultItemClick = (item) => {
    /// 根据搜索结果 重新定位
    /// 将经纬度字符串转换出来
    try {
      let locations = item.location.split(',')
      let longitude = locations[0]
      let latitude = locations[1]

      let marker = {
        id: item.id,
        latitude,
        longitude,
        name: item.name,
        width: 20,
        height: 30,
      }

      /// 根据经纬度 获取周边的poi
      myAmapFun.getPoiAround({
        location: item.location,
        success: (data) => {
          console.log(data)
          let pois = data.poisData || []
          if (pois.length > 0) {
            pois[0].checked = true
          }
          pois.map(res => {
            res.realaddress = res.pname + res.cityname + res.adname + res.address
          })

          this.setState({
            keyword: '',
            showSearch: false,
            markers: [marker],
            latitude, longitude,
            searchResults: [],
            pois
          })
        },
        fail: (err) => {
          this.setState({
            keyword: '',
            showSearch: false,
            markers: [marker],
            searchResults: [],
            latitude, longitude
          })
        }
      })
    } catch (error) {
      let e = {
        detail: {
          value: item.name,
        }
      }
      this.onInputValueChange(e)
    }
  }

5、点击地图底部POI实时更新气泡角标

  onPoiItemClick = (item: any, index: number) => {
    /// 点击重新设置气泡
    let marker = this.getMarker(item)
    let { pois } = this.state
    /// 清空所有的显示 
    pois.map(data => {
      data.checked = false
      return item
    })
    pois[index].checked = true
    this.setState({
      markers: [marker],
      pois
    })
  }

全部源码
tsx

import React, { Component } from 'react'
import { ThirdPartKey } from '@/utils/const.js'
import { View, Map, Input, Icon } from '@tarojs/components'
import amapFile from '../../../utils/libs/amap-wx.js'  //高德地图sdk
import './index.scss'

let myAmapFun

interface State {
  latitude: number,
  longitude: number,
  markers: any[],
  searchResults: any[],
  pois: any[],
  showSearch: boolean,
  keyword: string,
}

/// 修改和选择已有修理厂
export default class SelectFactoryAddress extends Component<{}, State> {
  state: State = {
    latitude: 23.099994,
    longitude: 113.324520,
    searchResults: [],
    showSearch: false,
    keyword: '',
    pois: [],
    markers: []
  }

  componentWillMount = () => {
    /// 初始化高德地图
    myAmapFun = new amapFile.AMapWX({ key: ThirdPartKey.amapKey })
  }

  componentDidMount() {
    /// 获取精准定位
    let that = this
    myAmapFun.getRegeo({
      success: (data) => {
        // markersData = data.markers;
        console.log(data)
        var {
          latitude,
          longitude
        } = that.state
        let { pois, addressComponent } = data[0].regeocodeData
        latitude = data[0].latitude
        longitude = data[0].longitude
        let marker
        if (pois.length > 0) {
          marker = this.getMarker(pois[0])
          /// 默认选中第0组数据
          pois[0].checked = true
        }
        /// 加上省市区 让地址变得长一些
        pois.map(item => {
          item.realaddress = addressComponent.province + addressComponent.city + addressComponent.district + item.address
        })
        var markers: any = []
        if (marker) {
          markers.push(marker)
        }
        this.setState({ latitude, longitude, pois, markers })
      },
      fail: (err) => {
        console.log(err)
      }
    })
  }

  onInputValueChange = (e) => {
    const { value } = e.detail
    // console.log(value)
    if (value.length == 0) {

      this.setState({
        searchResults: [],
        // showSearch: false,
        keyword: '',
      }, () => {
        // Taro.hideKeyboard()
      });
      return
    }
    /// 搜索POI功能
    myAmapFun.getInputtips({
      keywords: value,
      // city: '杭州',
      // location: '120.299221,30.419153',
      success: (data) => {
        console.log(data)
        if (data && data.tips) {
          this.setState({
            keyword: value,
            searchResults: data.tips
          });
        }
      }
    })
  }

  getMarker = (item: any) => {
    /// 点击重新设置气泡
    let locations = item.location.split(',')
    let longitude = locations[0]
    let latitude = locations[1]

    let marker = {
      id: item.id,
      latitude,
      longitude,
      name: item.name,
      width: 20,
      height: 30,
    }
    return marker
  }

  /// 点击搜索结果
  onResultItemClick = (item) => {
    /// 根据搜索结果 重新定位
    /// 将经纬度字符串转换出来
    try {
      let locations = item.location.split(',')
      let longitude = locations[0]
      let latitude = locations[1]

      let marker = {
        id: item.id,
        latitude,
        longitude,
        name: item.name,
        width: 20,
        height: 30,
      }

      /// 根据经纬度 获取周边的poi
      myAmapFun.getPoiAround({
        location: item.location,
        success: (data) => {
          console.log(data)
          let pois = data.poisData || []
          if (pois.length > 0) {
            pois[0].checked = true
          }
          pois.map(res => {
            res.realaddress = res.pname + res.cityname + res.adname + res.address
          })

          this.setState({
            keyword: '',
            showSearch: false,
            markers: [marker],
            latitude, longitude,
            searchResults: [],
            pois
          })
        },
        fail: (err) => {
          this.setState({
            keyword: '',
            showSearch: false,
            markers: [marker],
            searchResults: [],
            latitude, longitude

          })
        }
      })
    } catch (error) {
      let e = {
        detail: {
          value: item.name,
        }
      }
      this.onInputValueChange(e)
    }
  }

  onPoiItemClick = (item: any, index: number) => {
    /// 点击重新设置气泡
    let marker = this.getMarker(item)
    let { pois } = this.state
    /// 清空所有的显示 
    pois.map(data => {
      data.checked = false
      return item
    })
    pois[index].checked = true
    this.setState({
      markers: [marker],
      pois
    })

    // console.log(item.realaddress)
    // Taro.eventCenter.trigger('selectAddress', {
    //   type: 'factory',
    //   address: item.realaddress,
    // })
    // Taro.navigateBack({})
  }

  cancleSearch = () => {
    this.setState({
      showSearch: false,
      keyword: '',
      searchResults: [],
    })
  }

  onClear = () => {
    this.setState({
      keyword: '',
      searchResults: [],
    })
  }


  render() {

    let { latitude, longitude, markers, searchResults, showSearch, keyword, pois } = this.state
    return (
      <View className='selectFactoryAddress'>
        <View className='container'>
          {/* 地图 */}
          <View className='map-wrap'>
            <Map
              id="mapId"
              className="map"
              latitude={latitude || 0}
              longitude={longitude}
              showLocation={true}
              markers={markers}
            ></Map>
          </View>
          {/* 搜索 */}
          <View className='search-wrap'>
            <View className='input-wrap'>
              <Icon className='searchIcon' type='search' size='12' />
              <Input className='input'
                placeholder='请输入关键字搜索'
                value={keyword}
                onInput={this.onInputValueChange.bind(this)}
                onFocus={() => this.setState({ showSearch: true })}
              ></Input>
              {
                keyword.length > 0 && <View className='clear-img' onClick={() => this.onClear()}>
                  <Icon type='clear' size='12' />
                </View>
              }
            </View>
            {
              showSearch && <View className='search' onClick={() => this.cancleSearch()}>取消</View>
            }
          </View>

          {/* poi内容 */}
          <View className='poi-wrap' >
            {
              pois.map((item, index) => {
                return (
                  <View className={`poi-item ${item.checked ? 'active' : ''}`} key={index} onClick={() => this.onPoiItemClick(item, index)}>
                    <View className='content'>
                      <View className='name'>{item.name}</View>
                      <View className='address'>{item.realaddress}</View>
                    </View>
                  </View>
                )
              })
            }
          </View>

          {
            showSearch && <View className='search-result-wrap'>
              {
                searchResults.map((item, index) => {
                  return (<View className='result-item' key={index} onClick={() => this.onResultItemClick(item)}>
                    <View className='name'>{item.name}</View>
                    <View className='detail'>{item.district + item.address}</View>
                  </View>)
                })
              }
              {
                searchResults.length == 0 && <View className='nodata-wrap'>
                  <View>暂无数据</View>
                </View>
              }
            </View>
          }
        </View >
      </View >
    )
  }
}

scss

.selectFactoryAddress {
  .container {
    position: relative;
    .search-wrap {
      height: 120px;
      background-color: white;
      position: fixed;
      padding: 0 20px;
      left: 0;
      top: 0;
      right: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      border-top: 1px solid #eee;
      border-bottom: 1px solid #eee;

      .input-wrap {
        flex: 1;
        height: 50%;
        border: 1px solid #eee;
        padding: 0 15px;
        border-radius: 36px;
        display: flex;
        align-items: center;
        .searchIcon {
          // position: absolute;
          // left: 20px;
          //   top: 50%;
          //   transform: translateY(-50%);
          //   z-index: 1;
          margin-left: 8px;
        }

        .input {
          flex: 1;
          height: 100%;
          font-size: 26px;
          color: #333;
          margin-left: 14px;
        }
        .clear-img {
          width: 30px;
          height: 30px;
          // background-color: #e63c3d;
          display: flex;
          align-items: center;
          justify-content: center;
          margin-left: 15px;
          .img {
            width: 100%;
            height: 100%;
          }
        }
      }
      .search {
        width: 80px;
        text-align: center;
        color: #999;
        font-size: 28px;
        font-weight: 400;
      }
    }
    .search-result-wrap {
      background-color: white;
      position: absolute;
      left: 0;
      top: 120px;
      right: 0;
      width: 100%;
      height: 100%;
      display: flex;
      flex-direction: column;
      .result-item {
        // height: 80px;
        border-bottom: 1px solid #eee;
        color: #333;
        font-size: 26px;
        display: flex;
        // align-items: center;
        padding: 10px 20px;
        flex-direction: column;
        .detail {
          font-size: 22px;
          margin-top: 5px;
          color: #999;
        }
      }
      .nodata-wrap {
        width: 100%;
        height: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
        color: #999;
        font-size: 30px;
      }
    }
    .map-wrap {
      width: 100vw;
      height: 100vh;
      .map {
        width: 100%;
        height: 100%;
      }
    }
    .item-wrap {
      background-color: white;
      position: fixed;
      left: 0;
      bottom: 0;
      right: 0;
      display: flex;
      flex-direction: column;
      color: #333;
      padding: 20px;
      .sname {
        font-size: 30px;
        font-weight: 500;
      }
      .address-wrap {
        margin-top: 10px;
        font-size: 25px;
        display: flex;

        .address {
          flex: 1;
        }
        .distance {
          min-width: 160px;
          text-align: right;
        }
      }

      .button-wrap {
        margin-top: 10px;
        display: flex;
        background-color: white;
        // border-top: 1px solid #eee;
        height: 100px;
        align-items: center;
        padding: 0 20px;
        .button {
          display: flex;
          justify-content: center;
          align-items: center;
          font-size: 26px;
          color: #333;
          height: 70%;
          border: 1px solid #ddd;
          border-radius: 10px;
        }
        .left {
          width: 50%;
        }
        .right {
          width: 50%;
          margin-left: 20px;
          color: white;
          background-color: #e63c3d;
          border: none;
        }
      }
    }

    .poi-wrap {
      background-color: white;
      position: fixed;
      left: 0;
      bottom: 0;
      right: 0;
      display: flex;
      flex-direction: column;
      color: #333;
      padding: 0 20px;
      max-height: 40%;
      overflow: scroll; //这个属性是重点,要不然内容无法滚动
      .poi-item {
        position: relative;
        padding: 15px;
        display: flex;
        align-items: center;
        font-size: 24px;
        color: #333;
        border-bottom: 1px solid #eee;
        .content {
          flex: 1;
          display: flex;
          flex-direction: column;
          margin-right: 100px;
          .name {
            font-weight: 500;
          }
          .address {
            margin-top: 10px;
            font-size: 20px;
            color: #999;
          }
        }
      }
      .poi-item.active {
        &::after {
          content: "";
          width: 8px;
          height: 20px;
          position: absolute;
          right: 20px;
          top: 30px;
          border: 6px solid red;
          border-top-color: transparent;
          border-left-color: transparent;
          transform: rotate(45deg);
        }
      }
    }
  }
}
posted @ 2023-01-31 15:47  qqcc1388  阅读(2661)  评论(0)    收藏  举报