Насколько я понимаю, пока вы держите ссылку на свой элемент на стороне JavaScript, сборщик мусора не сможет уничтожить ваш элемент, даже если он был удален из DOM.Ваш элемент все еще будет активен, и вы сможете вызывать методы для него.
Вам придется самостоятельно управлять ссылками.В disconnectedCallback
вашего пользовательского элемента установите свойство, чтобы пометить его как удаленный, например: this.destroyed = true
.
Затем вы можете использовать это свойство для защиты доступа, но элемент не будет мусоромсобрано:
class RemoveEl extends HTMLButtonElement {
constructor() {
super();
this.type= 'button';
this.addEventListener('click', () => {
this.parentElement.removeChild(this);
})
}
sayHello() {
console.log('hello');
}
disconnectedCallback() {
if (!document.body.contains(this)) {
this.destroyed = true;
console.log('removed');
}
}
}
customElements.define('remove-el', RemoveEl, { extends: 'button' });
const sayHello = document.getElementById('sayHello');
const removeEl = document.getElementById('removeEl');
sayHello.addEventListener('click', () => {
if (removeEl && !removeEl.destroyed) {
removeEl.sayHello();
}
})
<div>Test:
<button is="remove-el" id="removeEl">Click to remove</button>
<button id="sayHello" type="button">Say Hello</button>
</div>
Или создайте оболочку ссылок, к которой вы можете применять функции, только если внутренняя ссылка действительна, однако сборщик мусора не сможет уничтожить ссылку, так кактеперь есть закрытие из-за функции do
, использующей el
:
class RemoveEl extends HTMLButtonElement {
constructor() {
super();
this.type= 'button';
this.addEventListener('click', () => {
this.parentElement.removeChild(this);
})
}
sayHello() {
console.log('hello');
}
disconnectedCallback() {
if (!document.body.contains(this)) {
this.destroyed = true;
console.log('removed');
}
}
}
customElements.define('remove-el', RemoveEl, { extends: 'button' });
const ref = el => ({ do: fn => { if (el && !el.destroyed) fn(el); } })
const sayHello = document.getElementById('sayHello');
const removeEl = ref(document.getElementById('removeEl'));
sayHello.addEventListener('click', () => {
removeEl.do(el => el.sayHello());
})
<div>Test:
<button is="remove-el" id="removeEl">Click to remove</button>
<button id="sayHello" type="button">Say Hello</button>
</div>
Или вы можете использовать прокси для управления этой ссылкой.Пока destroyed
ложно, методы будут вызываться для объекта, но как только прокси обнаружит, что destroyed = true
, он вернет значение по умолчанию для свойств и уничтожит свою собственную ссылку на элемент, который, мы надеемся,позволит сборщику мусора избавиться от него.
Что-то вроде этого:
class RemoveEl extends HTMLButtonElement {
constructor() {
super();
this.type= 'button';
this.addEventListener('click', () => {
this.parentElement.removeChild(this);
})
}
sayHello() {
console.log('hello');
}
disconnectedCallback() {
if (!document.body.contains(this)) {
this.destroyed = true;
console.log('removed');
}
}
}
customElements.define('remove-el', RemoveEl, { extends: 'button' });
const ref = (el, defaultEl) => {
let destroyed = el.destroyed;
const checkEl = () => {
if (!destroyed && el && el.destroyed) {
destroyed = true;
el = null;
}
return destroyed;
}
return new Proxy({}, {
get: (obj, prop) => {
return checkEl() ? defaultEl[prop] : el[prop];
}
});
}
const sayHello = document.getElementById('sayHello');
const removeEl = ref(document.getElementById('removeEl'), { sayHello: () => console.log('bye') });
sayHello.addEventListener('click', () => {
removeEl.sayHello();
})
<div>Test:
<button is="remove-el" id="removeEl">Click to remove</button>
<button id="sayHello" type="button">Say Hello</button>
</div>