119 lines
3.8 KiB
JavaScript
119 lines
3.8 KiB
JavaScript
/**
|
||
* @typedef Listener
|
||
* @type {Object}
|
||
* @property {Node} element
|
||
* @property {string} eventName
|
||
* @property {function} listener
|
||
*/
|
||
|
||
/**
|
||
* @function EventListener
|
||
* @param {unknown[]} args - аргументы функции
|
||
*/
|
||
|
||
/**
|
||
* @typedef Events
|
||
* @type {Object<string, EventListener[]>}
|
||
*/
|
||
|
||
/**
|
||
* Класс для создания компонентов приложения. Необходим для нследования.
|
||
* @class
|
||
*/
|
||
class Component {
|
||
/**
|
||
* @private
|
||
* @type {Listener[]}
|
||
*/
|
||
_listeners;
|
||
|
||
/**
|
||
* @private
|
||
* @type {Events}
|
||
*/
|
||
_events;
|
||
|
||
/**
|
||
* @public
|
||
* @type {Node} - корневой элемент компонента
|
||
*/
|
||
mainNode;
|
||
|
||
/**
|
||
* @param {string} mainNodeSelector - селектор, с помощью которого извлекается шаблон компонента
|
||
* @param {Node} parentNode - родительский Node, в который следует положить созданный элемент
|
||
*/
|
||
constructor(mainNodeSelector, parentNode) {
|
||
/**
|
||
* @type {DocumentFragment}
|
||
*/
|
||
const content = document.querySelector(mainNodeSelector).content;
|
||
if (content.children.length > 1) {
|
||
const message = '<template> должен содержать только один элемент children';
|
||
alert(message);
|
||
throw new Error(message);
|
||
}
|
||
this.mainNode = content.firstElementChild.cloneNode(true);
|
||
parentNode.appendChild(this.mainNode);
|
||
this._listeners = [];
|
||
this._events = {};
|
||
}
|
||
|
||
/**
|
||
* Метод добавления обработчиков события на Node'ы компонента
|
||
* @public
|
||
*
|
||
* @param {Node} element - элемент, на который будет навешен обработчик
|
||
* @param {string} eventName - событие, на которое будет реагировать обработчик
|
||
* @param {function} listener - обработчик события
|
||
*/
|
||
addEventListener = (element, eventName, listener) => {
|
||
element.addEventListener(eventName, listener);
|
||
this._listeners.push({element, eventName, listener});
|
||
}
|
||
|
||
/**
|
||
* Метод подписки на события компонента
|
||
* @public
|
||
*
|
||
* @param {string} eventName - событие компонента, на которое будет реагировать обработчик
|
||
* @param {EventListener} listener - обработчик события
|
||
*/
|
||
subscribe = (eventName, listener) => {
|
||
const listeners = this._events[eventName] || [];
|
||
this._events[eventName] = [
|
||
...listeners,
|
||
listener,
|
||
];
|
||
}
|
||
|
||
/**
|
||
* Метод генерирует событие
|
||
* @public
|
||
*
|
||
* @param {string} eventName - событие, которое необходимо сгенерировать
|
||
* @param {unknown[]} args - аругемнты, который необходимо передать обработчикам события
|
||
*/
|
||
next = (eventName, ...args) => {
|
||
const listeners = this._events[eventName];
|
||
listeners.forEach(listener => {
|
||
listener(...args);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Метод уничтожения компонента. Удаляет элемент из верстки, снимает обработчики и очищает подписки
|
||
* @public
|
||
*/
|
||
destroy = () => {
|
||
this._listeners.forEach(({element, eventName, listener}) => {
|
||
element.removeEventListener(eventName, listener);
|
||
});
|
||
this.mainNode.remove();
|
||
this._listeners = [];
|
||
this._events = {};
|
||
}
|
||
}
|
||
|
||
export default Component;
|