重构项目架构

前言

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

javascript 复制代码
class App {
  //加载页面
  constructor() {}

  //获取位置
  _getPosition() {}

  //接受位置
  _loadMap() {}

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

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

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

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

javascript 复制代码
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() {}
}

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

javascript 复制代码
const app = new App();

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

javascript 复制代码
  //加载页面
  constructor() {
    this._getPosition();
  }

● 这样不出意外的话,我们的功能应该能正常的运行

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

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

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

javascript 复制代码
 //接受位置
  _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

//提交表单之后生成新的运动

javascript 复制代码
  _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();
  }
}

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

javascript 复制代码
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

javascript 复制代码
//加载页面
  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');
    });
  }

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

javascript 复制代码
  //接受位置
  _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();
  }

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

javascript 复制代码
  //加载页面
  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');
  }

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

javascript 复制代码
'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国内访问不了,如果想要访问的话,需要用特殊的上网方法,不过这里不显示地图瓦片也没事,我们主要去注意一下我们的功能;

相关推荐
xxy-mm15 小时前
Javascript 中的继承
开发语言·javascript·ecmascript
1024肥宅17 小时前
手写 EventEmitter:深入理解发布订阅模式
前端·javascript·eventbus
3秒一个大19 小时前
HTML5 与 JavaScript 中的二进制数据处理:ArrayBuffer 与 TextEncoder/Decoder 实践
javascript
purpleseashell_Lili19 小时前
如何学习 AG-UI 和 CopilotKit
javascript·typescript·react
LSL666_20 小时前
4 jQuery、JavaScript 作用域、闭包与 DOM 事件绑定
前端·javascript·html
小飞侠在吗20 小时前
vue computed 和 watch
前端·javascript·vue.js
诸葛老刘21 小时前
next.js 框架中的约定的特殊参数名称
开发语言·javascript·ecmascript
coding随想21 小时前
掌控选区的终极武器:getSelection API的深度解析与实战应用
java·前端·javascript
沐风。561 天前
Object方法
开发语言·前端·javascript
JS_GGbond1 天前
JavaScript入门学习路线图
开发语言·javascript·学习