Общее свойство для всех экземпляоов
Я делаю свой первый проект с ООП делаю небольшую библиотеку, с помощью которой можно будет делать всплывающие окна, и в нужный момент их вызывать.
Есть класс WindowAction от него наследуется PopupWindow, а от него в свою очередь наследуются ErrorPopup, InfoPopup и тд.
В WindowAction есть метод alert() в нем я добавляю в html окно. И в this.currentElement заношу этот элемент
Потом когда я вызываю его второй раз из this.currentElement берется предыдущий элемент и удаляется из html
popup.alert() // new popup
popup.alert() // remove last element, insert new element
но я столкнулся с проблемой
если сделать два разных экземпляра (те получается два разных окна) и вызвать у них у обоих метод alert(), то ни один из них не закроется, и на странице получится два окна
popup.alert() // new popup
popup2.alert() // new popup
Как можно решить эту проблему?
Я придумал только сделать для всех экземпляров currentElement общим. Те если у popup1 currentElement = '12312', то и у popup2 currentElement будет равен '12312'. Но я не знаю как сделать его общим
Как сделать одно свойство общим для всех наследников (у всех будет одинаковое значение)??
Вот ссылка на jsFiddle. кому как удобно https://jsfiddle.net/9Lrf6oab/
код целиком (typeScript):
// проблема:
// на 25 строке объявление currentElement
// на 245 строке удаления элемента по currentElement
// на 262 277 строоках задаю значение currentElement
// на 299 строке класс ErrorPopup
// на 318 строке класс InfoPopup
// на 336 строке класс Popuper? который создает экземпляры классов (фабрика)
type AnimationAction = 'fade' | 'swipeRight' | 'swipeTop';
type Func = ()=>void;
/** Base class implementing window effects. */
class WindowAction
{
/** Stores opening action */
protected openAction: any = 'open_fade';
/** Stores closing action */
protected closeAction: any = 'close_fade';
/** Stores the action of clicking a button */
protected clickAction: any = 'open_fade';
// THERE MY PROBLEM!!!!!
// THERE MY PROBLEM!!!!!
// THERE MY PROBLEM!!!!!
// THERE MY PROBLEM!!!!!
/** Stores the current open window */
public currentElement: Element | null = null;
// THERE MY PROBLEM!!!!!
// THERE MY PROBLEM!!!!!
// THERE MY PROBLEM!!!!!
// THERE MY PROBLEM!!!!!
/** Automatic error output to the console */
public errorReporting: boolean = true;
/** Stores the id of the current window */
private popupID: number = 0;
/** Stores the last error */
private __lastError: string = '';
get lastError(): string {
if (this._lastError != '') {
return this.__lastError;
}
return 'no errors';
}
/** if error reporting is enabled, then displays errors to the console */
set _lastError(error: string) {
if (this.errorReporting) {
console.trace(error);
}
this.__lastError = error;
return;
}
/** fade animation on open */
protected open_fade(): void {
// console.log('стандартная функция открытия -- fade effect');
}
/** swipe right animation on open */
protected open_swipeRight(): void {
// console.log('стандартная функция открытия -- swipe right effect');
}
/** swipe top animation on open */
protected open_swipeTop(): void {
// console.log('стандартная функция открытия -- swipe top effect');
}
/** fade animation on close */
protected close_fade(): void {
// console.log('стандартная функция закрытия -- fade effect');
}
/** swipe right animation on close */
protected close_swipeRight(): void {
// console.log('стандартная функция закрытия -- swipe right effect');
}
/** swipe top animation on close */
protected close_swipeTop(): void {
// console.log('стандартная функция закрытия -- swipe top effect');
}
/**
* sets the effect or function when opened
* @param action function that will work when opened or the name of the built-in effect
*/
public onOpen(action: Func| AnimationAction): void {
// string passed
if (typeof action === 'string') {
// on open performs animation
this.openAction = 'open_' + action;
}
//function passed
else if (typeof action === 'function') {
// on open performs the user function
this.openAction = action;
}
}
/**
* runs when open (alert ()), performs the specified action
*/
protected open() {
// perform custom function
if (typeof this.closeAction === 'function') {
this.closeAction();
}
// perform standart animation
if (typeof this.closeAction === 'string' ) {
(this as any)[this.closeAction]();
}
}
/**
* runs when close (close ()), performs the specified action
*/
public onClose(action: Func | AnimationAction): void {
// perform custom function
if (typeof action === 'function') {
this.closeAction = action;
}
// perform standart animation
if (typeof action === 'string') {
this.closeAction = 'close_' + action;
}
}
/**
* closes an open window
*/
close(): boolean{
// if there is an open window
if (this.currentElement !== null) {
// perform custom function
if (typeof this.closeAction === 'function') {
this.closeAction();
}
// perform standart animation
if (typeof this.closeAction === 'string' ) {
(this as any)[this.closeAction]();
}
// close current window
this.currentElement.remove();
this.currentElement = null;
return true;
}
// if there is not an open window
this._lastError = 'no popups open';
return false
}
}
type insertMethod = 'add' | 'replace' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend';
class PopupWindow extends WindowAction{
/** type of popup */
public type: string = '';
/** are there any changes in layout */
private changes: boolean = true;
/** layout container */
private _layout: string = '';
/** layout template
* {key} : value
* @example popup.layout = '<div>{myValue}</div>'
*/
protected layoutPattern: string = '';
/** stores variables to be inserted into the popup
* @tutorial
* markup marked {key}
* the value with the key key is inserted
* @example popup.variables = {"myValue" : 'my message!!'}
*/
private _variables: {[key: string]: any} = {};
/** is the window open */
private openning: boolean = false;
set message(message: string) {
this._variables.message = message;
this.changes = true;
}
set button(button: string) {
this._variables.button = button;
this.changes = true;
}
set layout(layout: string) {
this.layoutPattern = layout;
this.changes = true;
}
set variables(vars: {[key: string]: any}) {
this._variables = vars;
this.changes = true;
}
/** inserts a window in html in the selected method
* @param out element to insert
* @param insertMethod insertion method
*/
insert (out: Element, insertMethod: insertMethod): void{
switch (insertMethod) {
case 'add':
out.innerHTML += this._layout;
break;
case 'replace':
out.innerHTML = this._layout;
break;
case 'beforebegin':
case 'afterbegin':
case 'beforeend':
case 'afterend':
out.insertAdjacentHTML(insertMethod, this._layout);
break;
}
// execute function when open
this.open();
}
/**
* displays a popup on a page
* @param outElement element to insert
* @param insertMethod insertion method
*/
alert (outElement: string | Element | null, insertMethod: insertMethod = 'add'): Boolean{
// close window if open
// НУЖНО ЧТОБЫ У POPUP1 и POPUP2 были одинаковые currentElement
// ЧТОЬЫ МОЖНО БЫЛО ЗАКРЫВАТЬ ИЗ POPUP1 POPUP2
// пример использования ниже
if (this.openning === true && this.currentElement !== null) {
this.currentElement.remove();
}
// if there is a change in layout, update the layout template
if (this.changes) {
this.buildLayout();
this.changes = false;
}
if (typeof outElement === 'string') {
// get element by string
const out: Element | null = document.querySelector(outElement);
if (out) {
// insert popup in html
this.insert(out, insertMethod);
// ТУТ ЗАПИСЫВАЮ В currentElement html ЭЛЕМЕНТ, КОТОРЫЙ ТОЛЬКО ЧТО ВСТАВИЛ
this.currentElement = document.querySelector(outElement +' .popup');
}
else {
this._lastError = `such an element does not exist (${outElement})`;
return false;
}
}
else if (outElement instanceof Element) {
// insert popup in html
this.insert(outElement, insertMethod);
// ТУТ ЗАПИСЫВАЮ В currentElement html ЭЛЕМЕНТ, КОТОРЫЙ ТОЛЬКО ЧТО ВСТАВИЛ
this.currentElement = outElement.querySelector('.popup');
}
// no element
else {
this._lastError = `such an element does not exist`;
return false;
}
this.openning = true;
return true;
}
// replace {key} in the layout with the values from variables
buildLayout(): void {
this._layout = this.layoutPattern;
for (let variable in this._variables){
this._layout = this._layout.replace(`{${variable}}`, this._variables[variable]);
}
}
}
class ErrorPopup extends PopupWindow
{
type = 'error';
constructor(standartMessage: string, standertButton: string | undefined){
super();
this.variables = {'message': standartMessage, 'button': standertButton};
this.layoutPattern = `<div class="popup popupError">
<div class="popupMessage">{message}</div>
<div class="popupFooter">
<button class="popupButton">{button}</button>
</div>
</div>`;
return this;
}
}
class InfoPopup extends PopupWindow
{
type = 'info';
constructor(standartMessage: string, standertButton: string | undefined){
super();
this.variables = {'message': standartMessage, 'button': standertButton};
this.layoutPattern = `<div class="popup popupInfo">
<div class="popupMessage">{message}</div>
<div class="popupFooter">
<button class="popupButton">{button}</button>
</div>
</div>`;
return this;
}
}
class Popuper
{
/**
* creates a popup object
*
* @param standartMessage standart message
* @param standartButton standart button text
*/
constructor(public standartMessage: string, public standartButton? : string){
this.standartMessage = standartMessage;
this.standartButton = standartButton;
}
/**
* creates a popup object
*
* @param type type of popup
* @returns popup window object
*/
create(type: 'error' | 'info' | 'succsses' | 'sure'): PopupWindow{
let typeWindow: any = null;
let popup: {[key: string]: any} = {};
switch (type) {
case 'error':
// СОЗДАЮ ЭКЗЕМПЛЯР ErrorPopup
return new ErrorPopup(this.standartMessage, this.standartButton);
case 'info':
// СОЗДАЮ ЭКЗЕМПЛЯР InfoPopup
return new InfoPopup(this.standartMessage, this.standartButton);
case 'succsses':
return new SuccssesPopup(this.standartMessage, this.standartButton);
case 'sure':
return new SurePopup();
}
}
}
/* ПРИМЕР */
let popuperError = popuper.create('error');
let popuperInfo = popuper.create('info');
console.log(popuperError.currentElement); // null
console.log(popuperInfo.currentElement); // null
popuperError.alert(document.body);
console.log(popuperError.currentElement); // error element
console.log(popuperInfo.currentElement); // null
popuperInfo.alert('body');
// НУЖНО ЧТОБЫ У НИХ БЫЛО ОБЩЕЕ СВОЙСТВО currentELement
// ТОГДА МОЖНО БУДЕТ В ЧЕРЕЗ ОДИН ЭКЗЕМПЛЯР КЛАССА, УДАЛЯТЬВСПЛЫВАЮЩЕЕ ОКНО ДРУГОГО ЭКЗЕМПЛЯРА
body{
position: absolute;
width: 100%;
height: 100%;
background: blue;
display: flex;
align-items: center;
justify-content: center;
}
.popup{
position: relative;
background: #fff;
width: 400px;
height: 200px;
overflow: hidden;
border-radius: 35px;
display: flex;
align-self: center;
}
.popup .popupFooter{
position: absolute;
width: 100%;
bottom: 0;
height: 30%;
background: linear-gradient(160deg, #39B9FF 10%, #003BE4);
padding: 5px;
}
.popup .popupFooter button{
position: absolute;
right: 50px;
top: 50%;
transform: translateY(-50%);
}
.popup .popupMessage{
width: 100%;
height: 100%;
padding: 15px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PopuperJS</title>
</head>
<body>
</body>
</html>
Ответы (1 шт):
Общее свойство для всех экземпляоов ©
"use strict";
let Parent = /** @class */ (() => {
class Parent {
get counter() { return Parent.counter; }
set counter(v) { Parent.counter = v; }
}
Parent.counter = 0;
return Parent;
})();
class A extends Parent {
increment() { this.counter = this.counter + 2; }
}
class B extends Parent {
increment() { this.counter = this.counter + 10; }
}
const _A = new A;
const _B = new B;
console.clear();
_A.increment();
console.log(_A.counter);
_B.increment();
console.log(_B.counter);