admin管理员组文章数量:1332865
We have this custom element defined like so...
<my-button>
Submit
</my-button>
and the standard customElements
definitions
class MyButton extends HTMLElement{
constructor(){
super();
// our custom code...
this.innerHTML = ''; // ??? where did the 'Submit' go?
}
}
...
customElements.define('my-button',MyButton);
The problem, when trying to get the innerHTML, we know we can do something like DOMContentLoaded
or window.onload
.
but sometimes we would like to create the 'my-button' dynamically, using code. and have it "render" upon being appended...
Is there a standard way to do this? does it have something to do with the connectedcallback()
and the rest of the 'connected' features?
Thanks!
Please note - I have tried using connectedCallback()
as a possible solution, and this does not solve the problem.
We have this custom element defined like so...
<my-button>
Submit
</my-button>
and the standard customElements
definitions
class MyButton extends HTMLElement{
constructor(){
super();
// our custom code...
this.innerHTML = ''; // ??? where did the 'Submit' go?
}
}
...
customElements.define('my-button',MyButton);
The problem, when trying to get the innerHTML, we know we can do something like DOMContentLoaded
or window.onload
.
but sometimes we would like to create the 'my-button' dynamically, using code. and have it "render" upon being appended...
Is there a standard way to do this? does it have something to do with the connectedcallback()
and the rest of the 'connected' features?
Thanks!
Please note - I have tried using connectedCallback()
as a possible solution, and this does not solve the problem.
- Possible duplicate of Cannot access attributes of a custom element from its constructor – Supersharp Commented Mar 18, 2019 at 9:43
- 1 Here is a lifecycle diagram: andyogo.github.io/custom-element-reactions-diagram – Danny '365CSI' Engelman Commented Mar 18, 2019 at 11:39
- 1 You can't access your custom element's DOM in the constructor because it has no DOM until it is connected. – Thad Commented Mar 18, 2019 at 14:58
4 Answers
Reset to default 3There are a set of rules on what you can and can not do in the constructor of a Web Component. They are below.
But think of this:
A ponent can be created one of three ways:
- Part of initial page/using innerHTML: When the browser loads the page or when using
innerHTML
you can add attributes and children to a ponent as part of the page load or part ofinnerHTML
.
parent.innerHTML = '<super-hero name="Thor"><super-weapon value="Mjolnir"></super-weapon></super-hero>'.
- You can call
document.createELement
to create an element. You can not add attributes or children until after the element is created.
let superHero = document.createElement('super-hero');
let superWeapon = document.createElement('super-weapon');
superHero.setAttribute('name', 'Thor');
superWeapon.setAttribute('value', 'Mjolnir');
superHero.appendChild(superWeapon);
parent.appendChild(superHero)
- You can instantiate an object using
new
. Just likedocument.createElement
you must wait until after the element is created before adding attributes and children.
let superHero = new SuperHero();
let superWeapon = new SuperWeapon();
superHero.setAttribute('name', 'Thor');
superWeapon.setAttribute('value', 'Mjolnir');
superHero.appendChild(superWeapon);
parent.appendChild(superHero)
Once the ponent is created it is added to the DOM and this is when your ponent's connectedCallback
is called.
And all three of these ways really e down to instantiating with new
. document.createElement
calls CustomElementRegistry.get
to get the constructor for that element and then uses new
to create the object.
And innerHTML
parses the HTML and then either calls document.createElement
or uses new
to create the object.
But, in doing so, there are NO attributes or children when the constructor for your element is called. In fact, there may not be any children or attributes when connectedCallback
is called. This is one reason that observedAttributes
and attributeChangedCallback
were added in the spec.
The one thing missing from the spec is knowing is someone has added or changed children either before or after the ponent was added to the DOM. But, if you really want to know when the children change you can use MutationObserver
.
This is why no children or attributes exists in your constructor. They have not bee added yet.
Now on to the rules:
When authoring custom element constructors, authors are bound by the following conformance requirements:
A parameter-less call to super() must be the first statement in the constructor body, to establish the correct prototype chain and this value before any further code is run.
A return statement must not appear anywhere inside the constructor body, unless it is a simple early-return (return or return this).
The constructor must not use the document.write() or document.open() methods.
The element's attributes and children must not be inspected, as in the non-upgrade case none will be present, and relying on upgrades makes the element less usable.
The element must not gain any attributes or children, as this violates the expectations of consumers who use the createElement or createElementNS methods.
In general, work should be deferred to connectedCallback as much as possible—especially work involving fetching resources or rendering. However, note that connectedCallback can be called more than once, so any initialization work that is truly one-time will need a guard to prevent it from running twice.
In general, the constructor should be used to set up initial state and default values, and to set up event listeners and possibly a shadow root.
Several of these requirements are checked during element creation, either directly or indirectly, and failing to follow them will result in a custom element that cannot be instantiated by the parser or DOM APIs.
There're 2 ways.
- You can define custom element after
window.onload
and everything should work fine.
window.addEventListener('load', () => {
customElement.define('my-button', MyButton);
});
- set
defer
attribute in<script>
<script defer src="my-button.js"></script>
If you need to reliably access the children of your custom element, no matter how your custom element script is placed in the document, this is for you: https://github./WebReflection/html-parsed-element
It's surprisingly difficult to detect when the parser has parsed the children of a custom element; the HTMLParsedElement
does this by repeatedly checking whether there is a nextSibling
(which would mean parsing of the current element is done). The current implementation replaced this check with a mutation observer that checks for childList
and subtree
changes in the custom element's parent element.
I've found out that when 'connectedCallback()' is being called, the '.innerHTML' is not yet set. BUT it'll be in the 'next tick..
In my custom ponent(s) it was enough to use 'setTimeout()', just with 0 als 2nd argument (after a function which can access the '.innerHTML').
connectedCallback(... _args)
{
// obviously, you could also use 'setImmediate()', if available in your browser(!)
window.setTimeout(() => {
this._innerHTML = this.innerHTML;
}, 0);
}
Just for your info. The solution above, with 'requestAnimationFrame', is maybe not that optimal, even if it's 'ok'.. our both's solution is not synchronous, but async should do it in most cases, too. If it's not even better.
本文标签: javascriptJS Custom Element get inner HTMLStack Overflow
版权声明:本文标题:javascript - JS Custom Element get inner HTML - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742292106a2447999.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论