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