Reagieren Sie auf das aktuelle Kampfmiet-App-Projekt (5) Verpackung von Top-Navigationskomponenten und CSS-Modulen Lösungsstilabdeckung und Verpackung von Kartengehäusemodulen

Vorwort

1. Kapselung der oberen Navigationskomponente

1.1 Grundaufbau

Umsetzungsschritte:

1、封装NavHeader组件实现城市选择,地图找房页面的复用
2、在components目录中创建组件 NavHeader/index.js
3、在该组件中封装 antd-mobile 组件库中的 NavBar组件

Codebeispiel:
Fügen Sie den folgenden Code in src/components/NavHeader/index.js hinzu:

import React from 'react';
import {
    
    NavBar} from 'antd-mobile'

export default class extends React.Component {
    
    
    render() {
    
    
        return (
            <NavBar className="navbar"
                    // 模式 默认值是 dark
                    mode="light"
                    // 左侧小图片
                    icon={
    
    <i className='iconfont icon-back' />}
                    // 左侧按钮的点击事件
                    onLeftClick={
    
    () => this.props.history.go(-1)}
                // 标题内容不定的,所以我们通过外界来传入
                >{
    
    this.props.children}</NavBar>
        )
    }
}

1.2 Stilanpassungen

Erstellen Sie eine index.scss-Datei im NavHeader-Ordner unter src/components
und kopieren Sie den in der vorherigen Städteliste geschriebenen Stil in diese Datei

1.3 Funktionsverarbeitung

Hinweis: Standardmäßig können nur Komponenten, die direkt von der Route Route gerendert werden, Routing-Informationen abrufen.Wenn Sie Routing-Informationen in anderen Komponenten benötigen, können Sie diese über die High-Level-Komponente withRouter abrufen

Umsetzungsschritte:

1、从 react-router-dom 中导入 withRouter 高阶组件
2、使用 withRouter 高阶组件包装 NavHeader 组件
3、从 props 中就能获取history对象,调用history对象的 go() 方法就能实现返回上一页功能了
4、由于头部的左侧按钮不一定是返回上一个页面的功能,所以我们需要把左侧点击逻辑处理一下,改成需要通过父组件传递进来,如果说外界传递了,那么我们就直接使用外界的行为,如果没有传递,那么就用默认的行为

Codebeispiel:
Ändern Sie den folgenden Code in src/components/NavHeader/index.js:

import React from 'react';
import {
    
     NavBar } from 'antd-mobile'
import './index.scss'
import {
    
     withRouter } from 'react-router-dom'

class NavHeader extends React.Component {
    
    
    render() {
    
    
        let defaultHandler = () => {
    
    this.props.history.go(-1)}
        return (
            <NavBar
                className="navbar"
                // 模式 默认值是 dark
                mode="light"
                // 左侧小图片
                icon={
    
    <i className='iconfont icon-back' />}
                // 左侧按钮的点击事件
                onLeftClick={
    
    this.props.onLeftClick || defaultHandler}
            >{
    
    this.props.children}</NavBar>
        )
    }
}
// 通过withRouter 包装一层后,返回的还是一个组件
export default withRouter(NavHeader)

1.4 Requisitenprüfung hinzufügen

Wir können eine Requisiten-Überprüfung hinzufügen, um Benutzer daran zu erinnern, wie sie Requisiten
mithilfe der folgenden Schritte korrekt übergeben:

1、安装 yarn add prop-types
2、导入 PropTypes
3、给NavHeader组件的 children 和 onLeftClick添加props校验

Codebeispiel:
Fügen Sie den folgenden Code in src/components/NavHeader/index.js hinzu:

import PropTypes from 'prop-types'

NavHeader.propTypes = {
    
    
    children: PropTypes.string.isRequired,
    onLeftClick:PropTypes.func
}

1.5 Verwenden Sie die NavHeader-Komponente auf der Stadtsuchseite

Fügen Sie den folgenden Code in src/pages/Citylist/index.js hinzu:

// 导入 NavHeader 组件
import NavHeader from '../../components/NavHeader'
        
{
    
    /* 顶部导航栏 */}
<NavHeader>城市选择</NavHeader>

2. Verwenden Sie CSS-Module, um das Problem der Stilüberdeckung zwischen Komponenten zu lösen

2.1 Überblick über Stilüberschreibungsprobleme zwischen Komponenten

1、问题:CityList组件的样式,会影响Map组件的样式
2、原因:在配置路由的时候,CityList组件与Map组件都会被导入到路由中,组件被导入,相关的样式也会被导入进来,如果两个组件的样式名称相同,那么就会影响另外一个组件的样式
3、小结:默认情况下,只要导入了组件,不管组件有没有显示在页面中,组件的样式就会生效
4、解决方式:1、写不同的类名   2CSS IN JS
5CSS IN JS
CSS IN JS 是使用JavaScript 编写 CSS 的统称,用来解决CSS样式冲突,覆盖等问题;
CSS IN JS 的具体实现有50多种,比如:CSS Modules、styled-components等
推荐使用CSS Modules,因为React脚手架已经集成进来了,可以直接使用

2.2 CSS-Module

Konzept:

1CSS Modules 通过对CSS类名重命名,保证每一个类名的唯一性,从而避免样式冲突问题
2、实现方式:webpack的css-loader 插件
3、命名采用:BEM(Block块、Element元素、Modifier三部分组成)命名规范。比如: .list_item_active
4、在React脚手架中演化成:文件名、类名、hash(随机)三部分,只需要指定类名即可

Wie benutzt man:

1、创建名为[name].module.css 的样式文件(React脚手架中的约定,与普通CSS区分开)
      示例:
           在 CityList 组件中创建的样式文件名称:index.module.css

2、组件中导入样式文件(注意语法)
      示例:
           在 CityList 组件中导入样式文件: import styles from './index.module.css'

3、通过styles对象访问对象中的样式名来设置样式
      示例:
           className={
    
    styles.navBar}

2.3 Verwenden Sie CSS-Module, um den NavHeader-Stil zu ändern

Schritte zur Verwendung:

1、在NavHeader目录中创建 index.module.css 的样式文件
2、在样式文件中修改当前组件的样式
3、对于组件库中已经有的全局样式,需要使用:global() 来指定

Codebeispiel:
Fügen Sie den folgenden Code in src/components/NavHeader/index.module.css hinzu:

.navbar {
    
    
    color: #333;
    background-color: #f6f5f6;
}

.navbar :global(.am-navbar-title) {
    
    
    color: #333;
}

3. Wohnungsmodul auf der Karte - Zeigen Sie die aktuelle Stadt entsprechend dem Standort an

Umsetzungsschritte:

1、获取当前定位城市
2、使用 地址解析器 解析当前城市坐标
3、调用 centerAndZoom() 方法在地图中展示当前城市,并设置缩放级别为11
4、在地图中添加比例尺和平移缩放控件

Codebeispiel:
Fügen Sie den folgenden Code in src/pages/Map/index.js hinzu:

// 解决脚手架中全局变量访问的问题
const BMap = window.BMap

export default class Map extends React.Component {
    
    
  componentDidMount() {
    
    
    this.initMap()
  }

  // 初始化地图
  initMap() {
    
    
    // 获取当前定位城市
    const {
    
     label, value } = JSON.parse(localStorage.getItem('hkzf_city'))

    // 初始化地图实例
    // 注意:在 react 脚手架中全局对象需要使用 window 来访问,否则,会造成 ESLint 校验错误
    const map = new BMap.Map('container')

    // 创建地址解析器实例
    const myGeo = new BMap.Geocoder()
    // 将地址解析结果显示在地图上,并调整地图视野
    myGeo.getPoint(
      label,
      point => {
    
    
        if (point) {
    
    
          //  初始化地图
          map.centerAndZoom(point, 11)

          // 添加常用控件
          map.addControl(new BMap.NavigationControl())
          map.addControl(new BMap.ScaleControl())
        }
      },
      label
    )
  }

  render() {
    
    
    return (
      <div className={
    
    styles.map}>
        {
    
    /* 顶部导航栏组件 */}
        <NavHeader>地图找房</NavHeader>
        {
    
    /* 地图容器元素 */}
        <div id="container" className={
    
    styles.container} />
      </div>
    )
  }
}

4. Wohnungssuchmodul auf der Karte – Wohnungsinformationen werden auf der Karte angezeigt

4.1 Auf der Karte angezeigte Immobilieninformationen

Bildbeschreibung hier einfügen

Diese Auflistungen werden tatsächlich mit Textüberlagerungen implementiert. Sehen wir uns also zuerst die Entwicklungsdokumentation von Baidu Maps an, um zu erfahren, wie Textüberlagerungen erstellt werden

4.2 Erstellen von Textüberlagerungen

Schritte erstellen:

1、打开百度地图添加文字标签DEMO 
2、创建 Label 实例对象
3、调用 setStyle() 方法设置样式 
4、在 map 对象上调用 addOverlay() 方法,将文本覆盖物添加到地图中。

Codebeispiel:
Fügen Sie den folgenden Code in src/pages/Map/index.js hinzu:

  const opts = {
    position: point
  }

  const label = new BMap.Label('文本覆盖物', opts)

  // 设置样式
  label.setStyle({
    color: 'green'
  })

  // 添加覆盖物到地图中
  map.addOverlay(label)

4.3 Informationsüberlagerungen für Zeichnungslisten

Zeichnungsschritte:

1、由于默认提供的本文覆盖物与我们效果不符合,所以我们需要进行重新的绘制
2、调用Label的setContent方法,传入html结构,修改HTML的内容样式
3、调用setStyle方法修改覆盖物样式
4、给覆盖物添加点击事件

Codebeispiel:
Fügen Sie den folgenden Code in src/pages/Map/index.js hinzu:

// 覆盖物样式
const labelStyle = {
  cursor: 'pointer',
  border: '0px solid rgb(255, 0, 0)',
  padding: '0px',
  whiteSpace: 'nowrap',
  fontSize: '12px',
  color: 'rgb(255, 255, 255)',
  textAlign: 'center'
}

 const opts = {
    position: point,
    offset: new BMap.Size(-35, -35)
  }

  // 说明:设置 setContent 后,第一个参数中设置的文本内容就失效了,因此,直接清空即可
  const label = new BMap.Label('', opts)

  // 设置房源覆盖物内容
  label.setContent(`
    <div class="${styles.bubble}">
      <p class="${styles.name}">浦东</p>
      <p>99套</p>
    </div>
  `)

  // 设置覆盖物样式
  label.setStyle(labelStyle)

  // 添加单击事件
  label.addEventListener('click', () => {
    console.log('房源覆盖物被点击了')
  })

  // 添加覆盖物到地图中
  map.addOverlay(label)

5. Gehäusemodul abbilden – Implementierung der Geschäftslogik

5.1 Analyse der Geschäftslogik

Das Kartengehäusemodul muss die folgenden Funktionen implementieren:

1、获取房源数据,渲染覆盖物
2、点击覆盖物后放大地图,并获取数据,渲染下一级覆盖物
3、区、镇覆盖物点击后,清除现有的覆盖物,获取下一级数据,创建新的覆盖物
4、小区覆盖物点击后,不清除现有覆盖物,移动地图,展示该小区下的房源信息

5.2 Informationen aller Stadtteile einholen und auf der Karte darstellen
Umsetzungsschritte:

1、发送请求获取房源数据
2、遍历数据,创建覆盖物,给每一个覆盖物添加唯一标识
3、给覆盖物添加点击事件
4、在单击事件中,获取到当前单击项的唯一标识
5、放大地图(级别为13),调用clearOverlays()方法清除当前覆盖物

Codebeispiel:
Fügen Sie den folgenden Code in src/pages/Map/index.js hinzu:

// 请求接口,获取房源数据
let res = await axios.get(`http://localhost:8080/area/map?id=${
      
      value}`)
// 遍历房源信息,创建对应的覆盖物
res.data.body.map(item => {
    
    
    // 给每一条数据添加覆盖物
    // 得到返回的经纬度信息
    let {
    
     coord: {
    
     longitude, latitude }, label: areaName, count, value } = item
    // 创建覆盖物
    let label = new window.BMap.Label('', {
    
    
        position: new window.BMap.Point(longitude, latitude),
        offset: new window.BMap.Size(-35, -35)
    })
    // 设置覆盖物内容
    label.setContent(`<div class="${
      
      styles.bubble}">
    <p class="${
      
      styles.name}">${
      
      areaName}</p>
    <p>${
      
      count}套</p>
  </div>`)
    // 设置样式
    label.setStyle(labelStyle)
    // 添加点击事件
    label.addEventListener('click', function () {
    
    
        // 当点击了覆盖物,要以当前点击的覆盖物为中心来放大地图
        map.centerAndZoom(this.K.position, 13);
        // 解决清除覆盖物的时候,百度地图js报错问题
        setTimeout(function () {
    
    
            map.clearOverlays()
        }, 0)
    })
    // 给label添加唯一标识
    label.id = value
    // 添加到地图上
    map.addOverlay(label)
})

5.3 Kapselung der Geschäftslogik

Nach der Analyse der Geschäftslogik haben wir festgestellt, dass die von Landkreisen, Städten und Gemeinden zu implementierende Geschäftslogik ähnlich ist. Um die Wiederverwendbarkeit des Codes zu verbessern, kann eine Schicht der Kapselung durchgeführt werden. Das Flussdiagramm der Kapselung ist in dargestellt folgende Abbildung
:
Bildbeschreibung hier einfügen

1. renderOverlays() wird als Eintrag
* verwendet, um den Bereichs-ID-Parameter zu erhalten und die Wohnungsdaten unter diesem Bereich zu erhalten,
* um die Art der Überlagerung und die Zoomstufe der Karte auf niedrigerer Ebene zu erhalten

2. Methode createOverlays()
* Rufen Sie je nach übergebenem Typ die entsprechende Methode auf, um Overlays zu erstellen, egal ob Overlays für Bezirke und Städte oder Community-Overlays erstellt werden sollen

3. createCircle()-Methode
* Erstellen Sie ein Overlay basierend auf den eingehenden Daten und binden Sie Ereignisse (vergrößern Sie die Karte, löschen Sie das Overlay und rendern Sie die nächste Ebene der Wohnungsdaten).

4. createReact()-Methode
* Erstellen Sie ein Overlay basierend auf den eingehenden Daten, binden Sie Ereignisse (verschieben Sie die Karte, rendern Sie die Auflistungsliste)

5.4 Kapselung der Geschäftslogik – Kapselung der Methode renderOverlays

Umsetzungsschritte:

1、接收区域 id 参数,获取该区域下的房源数据
2、获取房源类型以及下级地图缩放级别

Codebeispiel:
Fügen Sie den folgenden Code in src/pages/Map/index.js hinzu:

/**
* 根据id获取对应的房源信息
*/
async renderOverlays(id) {
    
    
    // 请求,拿到对应房源数据
    let res = await axios.get(`http://localhost:8080/area/map?id=${
      
      id}`)
    let data = res.data.body

    let {
    
    type,nextZoom} = this.getTypeAndZoom()

    // 遍历,调用createOverlays创建覆盖物
    data.map(item => {
    
    
        this.createOverlays(item,type,nextZoom)
    })
}

/**
* 获取对应要绘制的类型和缩放的比例
*/
  getTypeAndZoom() {
    
    
    // 调用地图的 getZoom() 方法,来获取当前缩放级别
    const zoom = this.map.getZoom()
    let nextZoom, type

    if (zoom >= 10 && zoom < 12) {
    
    
      // 区
      // 下一个缩放级别
      nextZoom = 13
      // circle 表示绘制圆形覆盖物(区、镇)
      type = 'circle'
    } else if (zoom >= 12 && zoom < 14) {
    
    
      // 镇
      nextZoom = 15
      type = 'circle'
    } else if (zoom >= 14 && zoom < 16) {
    
    
      // 小区
      type = 'rect'
    }

    return {
    
    
      nextZoom,
      type
    }
  }
最后,在初始化地图方法initMap中调用:

  // 初始化地图
  initMap() {
    
    
    // 获取当前定位城市
    const {
    
     label, value } = JSON.parse(localStorage.getItem('hkzf_city'))
    // 初始化地图实例
    const map = new BMap.Map('container')
    // 作用:能够在其他方法中通过 this 来获取到地图对象
    this.map = map
    // 创建地址解析器实例
    const myGeo = new BMap.Geocoder()
    // 将地址解析结果显示在地图上,并调整地图视野
    myGeo.getPoint(
      label,
      async point => {
    
    
        if (point) {
    
    
          //  初始化地图
          map.centerAndZoom(point, 11)
          // 添加常用控件
          map.addControl(new BMap.NavigationControl())
          map.addControl(new BMap.ScaleControl())

          // 调用 renderOverlays 方法
          this.renderOverlays(value)
        }
      },
      label
    )
  }

5.5 Kapselung der Geschäftslogik – Kapselung der createOverlays-Methode

Implementierungsschritte:
1. Dieses Verfahren ist hauptsächlich eine logische Beurteilung und ruft dann verschiedene Aufbereitungsverfahren gemäß verschiedenen Bedingungen auf

Codebeispiel:
Fügen Sie den folgenden Code in src/pages/Map/index.js hinzu:

  // 创建覆盖物
  createOverlays(data, zoom, type) {
    
    
    const {
    
    
      coord: {
    
     longitude, latitude },
      label: areaName,
      count,
      value
    } = data

    // 创建坐标对象
    const areaPoint = new BMap.Point(longitude, latitude)

    if (type === 'circle') {
    
    
      // 区或镇
      this.createCircle(areaPoint, areaName, count, value, zoom)
    } else {
    
    
      // 小区
      this.createRect(areaPoint, areaName, count, value)
    }
  }

5.6 Kapselung der Geschäftslogik – Kapselung der createCircle-Methode

Implementierungsschritte:
1. Wiederverwenden der vorherigen Codelogik zum Erstellen von Overlays.
2. Rufen Sie im Click-Ereignis des Overlays die Methode renderOverlays(id) auf, um die Hausdaten in diesem Bereich neu zu rendern

Codebeispiel:
Fügen Sie den folgenden Code in src/pages/Map/index.js hinzu:

// 创建区、镇覆盖物
  createCircle(point, name, count, id, zoom) {
    
    
    // 创建覆盖物
    const label = new BMap.Label('', {
    
    
      position: point,
      offset: new BMap.Size(-35, -35)
    })

    // 给 label 对象添加一个唯一标识
    label.id = id

    // 设置房源覆盖物内容
    label.setContent(`
      <div class="${
      
      styles.bubble}">
        <p class="${
      
      styles.name}">${
      
      name}</p>
        <p>${
      
      count}套</p>
      </div>
    `)

    // 设置样式
    label.setStyle(labelStyle)

    // 添加单击事件
    label.addEventListener('click', () => {
    
    
      // 调用 renderOverlays 方法,获取该区域下的房源数据
      this.renderOverlays(id)

      // 放大地图,以当前点击的覆盖物为中心放大地图
      this.map.centerAndZoom(point, zoom)

      // 解决清除覆盖物时,百度地图API的JS文件自身报错的问题
      setTimeout(() => {
    
    
        // 清除当前覆盖物信息
        this.map.clearOverlays()
      }, 0)
    })

    // 添加覆盖物到地图中
    this.map.addOverlay(label)
  }

5.7 Kapselung der Geschäftslogik – Kapselung der createRect-Methode

Implementierungsschritte:
1. Erstellen Sie ein Label, legen Sie den Stil fest, legen Sie den HTML-Inhalt fest und binden Sie das Ereignis

Codebeispiel:
Fügen Sie den folgenden Code in src/pages/Map/index.js hinzu:

  // 创建小区覆盖物
  createRect(point, name, count, id) {
    
    
    // 创建覆盖物
    const label = new BMap.Label('', {
    
    
      position: point,
      offset: new BMap.Size(-50, -28)
    })

    // 给 label 对象添加一个唯一标识
    label.id = id

    // 设置房源覆盖物内容
    label.setContent(`
      <div class="${
      
      styles.rect}">
        <span class="${
      
      styles.housename}">${
      
      name}</span>
        <span class="${
      
      styles.housenum}">${
      
      count}套</span>
        <i class="${
      
      styles.arrow}"></i>
      </div>
    `)

    // 设置样式
    label.setStyle(labelStyle)

    // 添加单击事件
    label.addEventListener('click', () => {
    
    
      console.log('小区被点击了')
    })

    // 添加覆盖物到地图中
    this.map.addOverlay(label)
  }

Jetzt stellt es nur die Methode zum Erstellen einer Community-Abdeckung dar. Das Klicken, um alle Auflistungsdaten abzurufen, und das Rendern von Auflistungen unter der Community wurde noch nicht implementiert.

Zusammenfassen

Acho que você gosta

Origin blog.csdn.net/qq_40652101/article/details/127958359
Recomendado
Clasificación