重构项目架构

前言

我们上篇文章对整个项目进行一个整体的规划,其中对于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国内访问不了,如果想要访问的话,需要用特殊的上网方法,不过这里不显示地图瓦片也没事,我们主要去注意一下我们的功能;

相关推荐
Mintopia9 分钟前
Node.js 对前端技术有利的知识点
前端·javascript·node.js
一道雷12 分钟前
🛠️ Unindex:推荐一款自动化索引文件生成工具
前端·javascript·node.js
键指江湖32 分钟前
React 更新 state 中的数组
javascript·react.js·ecmascript
Mintopia44 分钟前
Three.js 着色器使用教程:进阶指南
前端·javascript·three.js
卸任1 小时前
next-auth是如何保持登录状态的?回顾一下Session、Cookie、Token
前端·javascript·next.js
BillKu1 小时前
vue3中,element-plus中el-input的v-model和value的用法示例
javascript·vue.js·elementui
小韩本韩!1 小时前
electron+vue项目 设置全屏
javascript·vue.js·electron
神秘红光可达鸭2 小时前
react UI=f(state) 的演进之路
javascript·react.js
静思己过2 小时前
AutoDecimal:轻松解决 JavaScript 运算精度问题之toDecimal
前端·javascript
日升2 小时前
AbortController:让异步操作随时说停就停
前端·javascript·ajax