重构项目架构

发布于:2024-11-28 ⋅ 阅读:(10) ⋅ 点赞:(0)

前言
我们上篇文章对整个项目进行一个整体的规划,其中对于APP类规划了类,本篇文章我们就来实现这个规划;

class App {
  //加载页面
  constructor() {}

  //获取位置
  _getPosition() {}

  //接受位置
  _loadMap() {}

  //在地图上点击展现表单
  _showForm() {}

  //切换表单的输入选项
  _toggleElevationField() {}

  //提交表单之后生成新的运动
  _newWorkout() {}
}

● 这个就是初步的架构代码,现在我们只需要把功能代码放进去即可

class App {
  //加载页面
  constructor() {}

  //获取位置
  _getPosition() {
    if (navigator.geolocation)
      navigator.geolocation.getCurrentPosition(this._loadMap, function () {
        alert('无法获取你的位置!');
      });
  }

  //接受位置
  _loadMap(position) {
    const { latitude } = position.coords;
    const { longitude } = position.coords;
    const coords = [latitude, longitude];
    map = L.map('map').setView(coords, 13);

    L.tileLayer('https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', {
      attribution:
        '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
    }).addTo(map);

    map.on('click', function (mapE) {
      mapEvent = mapE;
      form.classList.remove('hidden');
      inputDistance.focus();
    });
  }

  //在地图上点击展现表单
  _showForm() {}

  //切换表单的输入选项
  _toggleElevationField() {}

  //提交表单之后生成新的运动
  _newWorkout() {}
}

● 现在我们来将计划实例化出来,并在构造函数中渲染

const app = new App();

● 目前我们再创建App类之后无法立即获取用户的问题,所以我们需要在构造函数中调用_getPosition方法来立即获取用户的地理位置。这是一个常见的设计模式,通常用来确保在应用加载后尽快执行某些初始化操作。

  //加载页面
  constructor() {
    this._getPosition();
  }

● 这样不出意外的话,我们的功能应该能正常的运行
在这里插入图片描述

● 所以现在在类中将map和mapEvent进行宣告,但是像地图及地图事件肯定是一次性的,后面不不需要对其进行修改,所以当成私有字段;

class App {
  #map;
  #mapEvent;
  //加载页面
  constructor() {
    this._getPosition();
  }
  。。。。。。
}

● 之后,我们在调用map的时候记住改一下私有字段的宣告方式即可;

 //接受位置
  _loadMap(position) {
    const { latitude } = position.coords;
    const { longitude } = position.coords;
    const coords = [latitude, longitude];
    this.#map = L.map('map').setView(coords, 13);

    L.tileLayer('https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', {
      attribution:
        '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
    }).addTo(this.#map);

    this.#map.on('click', function (mapE) {
      this.#mapEvent = mapE;
      form.classList.remove('hidden');
      inputDistance.focus();
    });
  }

● 下一步我们将生成运动表单的函数进行重构,我们直接将我们展现标记的函数放入我们之前做规划的函数体当中,也就是_newWorkout
//提交表单之后生成新的运动

  _newWorkout(e) {
    e.preventDefault(); //组织表单默认行为

    //将表格输入内容置空
    inputDistance.value =
      inputDuration.value =
      inputCadence.value =
      inputElevation.value =
        '';

    //展现标记
    const { lat, lng } = mapEvent.latlng;
    L.marker([lat, lng])
      .addTo(map)
      .bindPopup(
        L.popup({
          maxWidth: 250,
          minWidth: 100,
          autoClose: false,
          closeOnClick: false,
          className: 'running-popup',
        })
      )
      .setPopupContent('跑步')
      .openPopup();
  }
}

● 然后还是在构造函数中宣告

constructor() {
    this._getPosition();
    form.addEventListener('submit', this._newWorkout);

    inputType.addEventListener('change', function () {
      //改变的时候判断是否存在隐藏类,有就去除,没有就添加
      inputElevation
        .closest('.form__row')
        .classList.toggle('form__row--hidden');
      inputCadence.closest('.form__row').classList.toggle('form__row--hidden');
    });
  }

● 但是,注意事件监听器中的 this 关键字通常指向触发事件的元素,也就是事件绑定的元素本身。所以在调用新建运动项目时候,我们需要手动绑定一下this

//加载页面
  constructor() {
    this._getPosition();
    form.addEventListener('submit', this._newWorkout.bind(this));

    inputType.addEventListener('change', function () {
      //改变的时候判断是否存在隐藏类,有就去除,没有就添加
      inputElevation
        .closest('.form__row')
        .classList.toggle('form__row--hidden');
      inputCadence.closest('.form__row').classList.toggle('form__row--hidden');
    });
  }

● 接着我们对在地图上面展示表单进行一个重构,注意监听事件和绑定事件一样,记着调用时候手动绑定一下

  //接受位置
  _loadMap(position) {
    const { latitude } = position.coords;
    const { longitude } = position.coords;
    const coords = [latitude, longitude];
    console.log(this);
    this.#map = L.map('map').setView(coords, 13);

    L.tileLayer('https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', {
      attribution:
        '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
    }).addTo(this.#map);

    this.#map.on('click', this._showForm.bind(this));
  }

  //在地图上点击展现表单
  _showForm(mapE) {
    this.#mapEvent = mapE;
    form.classList.remove('hidden');
    inputDistance.focus();
  }

在这里插入图片描述

● 接下来我们来处理关于隐藏类的函数

  //加载页面
  constructor() {
    this._getPosition();
    form.addEventListener('submit', this._newWorkout.bind(this));
    inputType.addEventListener('change', this._toggleElevationField);
  }
。。。。。。
 //切换表单的输入选项
  _toggleElevationField() {
    //改变的时候判断是否存在隐藏类,有就去除,没有就添加
    inputElevation.closest('.form__row').classList.toggle('form__row--hidden');
    inputCadence.closest('.form__row').classList.toggle('form__row--hidden');
  }

在这里插入图片描述

之后我们基本的架构也就调整完了,看看是不是整洁了很多

'use strict';

// prettier-ignore
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

const form = document.querySelector('.form');
const containerWorkouts = document.querySelector('.workouts');
const inputType = document.querySelector('.form__input--type');
const inputDistance = document.querySelector('.form__input--distance');
const inputDuration = document.querySelector('.form__input--duration');
const inputCadence = document.querySelector('.form__input--cadence');
const inputElevation = document.querySelector('.form__input--elevation');
class App {
  #map;
  #mapEvent;
  //加载页面
  constructor() {
    this._getPosition();
    form.addEventListener('submit', this._newWorkout.bind(this));
    inputType.addEventListener('change', this._toggleElevationField);
  }

  //获取位置
  _getPosition() {
    if (navigator.geolocation)
      navigator.geolocation.getCurrentPosition(
        this._loadMap.bind(this),
        function () {
          alert('无法获取你的位置!');
        }
      );
  }

  //接受位置
  _loadMap(position) {
    const { latitude } = position.coords;
    const { longitude } = position.coords;
    const coords = [latitude, longitude];
    this.#map = L.map('map').setView(coords, 13);

    L.tileLayer('https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', {
      attribution:
        '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
    }).addTo(this.#map);

    this.#map.on('click', this._showForm.bind(this));
  }

  //在地图上点击展现表单
  _showForm(mapE) {
    this.#mapEvent = mapE;
    form.classList.remove('hidden');
    inputDistance.focus();
  }

  //切换表单的输入选项
  _toggleElevationField() {
    //改变的时候判断是否存在隐藏类,有就去除,没有就添加
    inputElevation.closest('.form__row').classList.toggle('form__row--hidden');
    inputCadence.closest('.form__row').classList.toggle('form__row--hidden');
  }

  //提交表单之后生成新的运动
  _newWorkout(e) {
    e.preventDefault(); //组织表单默认行为

    //将表格输入内容置空
    inputDistance.value =
      inputDuration.value =
      inputCadence.value =
      inputElevation.value =
        '';

    //展现标记
    const { lat, lng } = this.#mapEvent.latlng;
    L.marker([lat, lng])
      .addTo(this.#map)
      .bindPopup(
        L.popup({
          maxWidth: 250,
          minWidth: 100,
          autoClose: false,
          closeOnClick: false,
          className: 'running-popup',
        })
      )
      .setPopupContent('跑步')
      .openPopup();
  }
}

const app = new App();

注意:现在OpenStreetMap国内访问不了,如果想要访问的话,需要用特殊的上网方法,不过这里不显示地图瓦片也没事,我们主要去注意一下我们的功能;