#javascript #typescript #class #properties
Вопрос:
Я сталкиваюсь с проблемой, когда свойство моего класса непреднамеренно преобразуется.
import { Draggable, DragTarget } from '../Models/eventlisteners';
import { HeroValues } from '../Models/responseModels';
import { Util } from './Util';
export class Heroes implements Draggable, DragTarget {
static instance: Heroes;
hostElement: HTMLDivElement = document.getElementById(
'app'
)! as HTMLDivElement;
templateElement: HTMLTemplateElement = document.getElementById(
'tmpl-hero-overview'
) as HTMLTemplateElement;
element: HTMLCollection;
heroes!: HeroValues;
imagesLoaded: number = 0;
constructor() {
const importedNode = document.importNode(
this.templateElement.content,
true
);
this.element = importedNode.children as HTMLCollection;
}
async retrieveHeroes() {
const data = await Util.getData(
'https://api.opendota.com/api',
'/constants/heroes'
);
this.heroes = data;
for (const key in this.heroes) {
this.heroes[data[key]['id']] = {
img: 'https://api.opendota.com' data[key]['img'],
agi_gain: data[key]['agi_gain'],
attack_range: data[key]['attack_range'],
attack_rate: data[key]['attack_rate'],
attack_type: data[key]['attack_type'],
base_agi: data[key]['base_agi'],
base_armor: data[key]['base_armor'],
base_attack_max: data[key]['base_attack_max'],
base_attack_min: data[key]['base_attack_min'],
base_health: data[key]['base_health'],
base_health_regen: data[key]['base_health_regen'],
base_int: data[key]['base_int'],
base_mana: data[key]['base_mana'],
base_mana_regen: data[key]['base_mana_regen'],
base_mr: data[key]['base_mr'],
base_str: data[key]['base_str'],
int_gain: data[key]['int_gain'],
localized_name: data[key]['localized_name'],
move_speed: data[key]['move_speed'],
primary_attr: data[key]['primary_attr'],
projectile_speed: data[key]['projectile_speed'],
str_gain: data[key]['str_gain'],
id: data[key]['id'],
};
}
}
render() {
for (const key in this.heroes) {
const img = document.createElement('img');
img.id = this.heroes[key].id.toString();
img.classList.add('hero');
img.onerror = () => this.updateDOM();
img.onload = () => this.updateDOM();
img.src = this.heroes[key].img;
this.element[0].appendChild(img);
}
this.configure();
}
dragStartHandler(event: DragEvent) {
event.dataTransfer!.setData('text/plain', (<HTMLElement>event.target).id);
event.dataTransfer!.effectAllowed = 'copy';
}
dragEndHandler(_: DragEvent) {
console.log('dragend');
}
dragOverHandler(event: DragEvent) {
event.preventDefault();
(<HTMLElement>event.target).classList.add('droppable');
}
dragLeaveHandler(event: DragEvent) {
(<HTMLElement>event.target).classList.remove('droppable');
}
dropHandler(event: DragEvent) {
event.preventDefault();
const heroId = event.dataTransfer!.getData('text/plain');
const img = document.createElement('img');
img.id = this.heroes[event.dataTransfer!.getData('text/plain')]['id'];
img.src = this.heroes[event.dataTransfer!.getData('text/plain')]['img'];
console.log(this.element);
if ((<HTMLElement>event.target).firstElementChild) {
(<HTMLElement>event.target).firstElementChild?.remove();
}
(<HTMLElement>event.target).appendChild(img);
}
configure() {
(<HTMLInputElement>this.element[0]).addEventListener(
'dragstart',
this.dragStartHandler.bind(this)
);
(<HTMLInputElement>this.element[0]).addEventListener(
'dragend',
this.dragEndHandler.bind(this)
);
(<HTMLInputElement>this.element[1].children[0]).addEventListener(
'dragover',
this.dragOverHandler.bind(this)
);
(<HTMLInputElement>this.element[1].children[0]).addEventListener(
'dragleave',
this.dragLeaveHandler.bind(this)
);
(<HTMLInputElement>this.element[1].children[0]).addEventListener(
'drop',
this.dropHandler.bind(this)
);
}
private updateDOM() {
this.imagesLoaded = 1;
if (this.imagesLoaded === 121) {
console.log(this.element);
Array.from(this.hostElement.children).forEach((el) => {
el.remove();
});
console.log(this.element);
Array.from(this.element).forEach((el) => {
this.hostElement.insertAdjacentElement('beforeend', el);
});
console.log(this.element);
}
}
// private function attach drag/drop listeners
static getInstance() {
if (this.instance) {
return this.instance;
}
this.instance = new Heroes();
return this.instance;
}
}
Я сузил проблему до этого кода. this.element
это HTMLCollection
то, что мне нужно снова использовать на более поздних этапах. В первых 2 console.logs он имеет ожидаемые свойства, определенные в конструкторе заранее. Но после второго цикла forEach он теряет все свои свойства и имеет длину 0.
Я подумал , что, возможно, мне нужно сделать копию this.element
, прежде чем передавать ее в цикл forEach. Но это не сработало, или я сделал это хуже. Для этого у меня была переменная со значением Array.from(this.element).slice()
Затем я подумал, что, возможно, Array.from() преобразуется this.element
непреднамеренно. Но по состоянию на документы он создает копию начальной цели и не преобразует ее.
Кто-нибудь может мне здесь помочь?
Правка: Я думал, что не копирую весь свой код, так как проблема, похоже, довольно сильно сузилась. Но я могу предоставить больше, если в этом нет ничего плохого.
Комментарии:
1. Простое перемещение элемента в DOM (что вы делаете) может привести к его удалению из коллекции — покажите код, в котором
this.element = I want to see what is here
2. @Bravo спасибо за ответ. Я вставил весь код целиком. этот.элемент определен в конструкторе. В нем хранится коллекция HTMLCollection с 2 разделами, которые изначально взяты из шаблона. Я использую его для заполнения изображениями из запроса Apire
3. хорошо…
importedNode.children
изменится, когда вы будете перемещать детей — попробуйтеthis.element = Array.from(importedNode.children)
сделать снимок детей4. @Браво Отлично, это сработало. Спасибо! 🙂 если вы не возражаете, не могли бы вы сказать мне, почему это меняется на основе этого? Я думал, что с тех пор, как я определил эти вещи в конструкторе, все остается статичным. Я еще не очень хорошо разбираюсь в классах машинописи..
5. Я объяснил это в своем ответе
Ответ №1:
Воспользуйся
this.element = Array.from(importedNode.children)
таким образом, этот элемент.является моментальным importedNode.children
снимком — не имеет значения, куда перемещаются дочерние узлы
Ваша проблема в том, что вы делаете
Array.from(this.element).forEach....
не перестает this.element
importedNode.children
существовать на самом деле — поэтому любые изменения, такие как перемещение элемента из importedNode.children
неподвижных средств this.element
, больше не будут иметь этого элемента, поскольку они оба относятся к одному и тому же объекту
элемент.дети динамичны … если вы добавляете или удаляете дочерний элемент, то element.children отражает изменения — очевидно, это полезно
установка this.element=importedNode.children не создает копию, это ссылка на один и тот же объект
И последнее замечание
this.hostElement.insertAdjacentElement('beforeend', el);
удаляет el
оттуда, где он есть ( importedNode.children
), и перемещает его в новое локальное местоположение, которое было бы ( this.hostElement.children
) — таким образом, эта операция удаляет элемент из importedNode.children
и, следовательно this.element