Web 组件:访问自定义组件 class 中的阴影 DOM
Web Component: Accessing the shadow DOM within the Custom Component class
对于这个项目,我正在尝试创建一个将作为地图运行的自定义组件。我仍在通过 W3C 文档和几个 Youtube 视频学习 Web 组件的基础知识。
主要问题是,在组件 class 中有一个名为 attributeChangedCallback()
的函数,每当其中一个属性更改时都会触发该函数,这些属性包含在 observedAttributes()
函数并在设置它们之后(前面提到的函数)我尝试访问影子 DOM( 声明为 connectedCallback()
,一旦组件加载到 HTML 中就会触发body 元素)通过选择器。但是,如果我这样做,变量内容为空。
attributeChangedCallback()
应该加载 在 内容加载之后,所以我不明白为什么会这样,每次我都需要访问这个元素属性更改,因此我可以更新其内容。奇怪的事实:如果我每次执行 attributeChangedCallback()
时都记录它,它会记录两次(因为我有两个属性被监视)。
这是片段:
class GeoComponent extends HTMLElement {
constructor() {
super();
this.shadow = this.createShadowRoot();
this._latitude = 0;
this._longitude = 0;
}
get latitude(){
return this._latitude;
}
get longitude(){
return this._longitude;
}
set latitude(val){
this.setAttribute('latitude', val);
}
set longitude(val){
this.setAttribute('longitude', val);
}
static get observedAttributes(){
return ['latitude', 'longitude'];
}
attributeChangedCallback(name, oldVal, newVal){
let geoComp = this.shadow.getElementById('geo');
console.log(geoComp);
switch(name){
case 'latitude':
this._latitude = parseInt(newVal, 0) || 0;
// geoComp.innerHTML = `${this.latitude}, ${this.longitude}`;
break;
case 'longitude':
this._longitude = parseInt(newVal, 0) || 0;
// geoComp.innerHTML = `${this.latitude}, ${this.longitude}`;
break
}
}
connectedCallback(){
let template = `
<div class="geo-component" id="geo">
</div>
`;
this.shadow.innerHTML = template;
}
}
window.customElements.define('geo-component', GeoComponent);
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="geoComponent.js"></script>
</head>
<body>
<h1>Geo-Component</h1>
<geo-component latitude="12" longitude="-70"></geo-component>
</body>
</html>
更新
就像@acdcjunior 在将 this.createShadowRoot();
更改为 this.shadow = this.attachShadow({mode: 'open'});
(从 ShadowDOM v0 到 v1)后提到的那样解决了我的问题,因为执行了 connectedCallback()
函数幕后,只有一次。
attributeChangedCallback()
在(观察到的)属性被 初始化(声明式,这是您的情况)、添加、更改或删除时调用。这意味着它在 connectedCallback()
.
之前调用
通常我们使用 constructor() 来创建 DOM:
Name: constructor
Called when: An instance of the element is created
or upgraded. Useful for initializing state, settings up event
listeners, or creating shadow dom. See the spec for restrictions on
what you can do in the constructor.
我把你的逻辑移到里面了。
您也在使用 ShadowDOM v0。将其更新为 v1(attachShadow
而不是 createShadowRoot
)。
更新演示:
class GeoComponent extends HTMLElement {
constructor() {
super();
console.log('constructor called');
this.attachShadow({mode: 'open'});
this._latitude = 0;
this._longitude = 0;
let template = `
<div class="geo-component" id="geo">
</div>
`;
this.shadowRoot.innerHTML = template;
}
get latitude() {
return this._latitude;
}
get longitude() {
return this._longitude;
}
set latitude(val) {
this.setAttribute('latitude', val);
}
set longitude(val) {
this.setAttribute('longitude', val);
}
static get observedAttributes() {
return ['latitude', 'longitude'];
}
attributeChangedCallback(name, oldVal, newVal) {
console.log('attributeChangedCallback() called:', name, ':', oldVal, '->', newVal);
let geoComp = this.shadowRoot.getElementById('geo');
console.log(geoComp);
switch (name) {
case 'latitude':
this._latitude = parseInt(newVal, 0) || 0;
// geoComp.innerHTML = `${this.latitude}, ${this.longitude}`;
break;
case 'longitude':
this._longitude = parseInt(newVal, 0) || 0;
// geoComp.innerHTML = `${this.latitude}, ${this.longitude}`;
break
}
}
connectedCallback() {
console.log('connectedCallback() called');
}
}
window.customElements.define('geo-component', GeoComponent);
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="geoComponent.js"></script>
</head>
<body>
<h1>Geo-Component</h1>
<geo-component latitude="12" longitude="-70"></geo-component>
</body>
</html>
对于这个项目,我正在尝试创建一个将作为地图运行的自定义组件。我仍在通过 W3C 文档和几个 Youtube 视频学习 Web 组件的基础知识。
主要问题是,在组件 class 中有一个名为 attributeChangedCallback()
的函数,每当其中一个属性更改时都会触发该函数,这些属性包含在 observedAttributes()
函数并在设置它们之后(前面提到的函数)我尝试访问影子 DOM( 声明为 connectedCallback()
,一旦组件加载到 HTML 中就会触发body 元素)通过选择器。但是,如果我这样做,变量内容为空。
attributeChangedCallback()
应该加载 在 内容加载之后,所以我不明白为什么会这样,每次我都需要访问这个元素属性更改,因此我可以更新其内容。奇怪的事实:如果我每次执行 attributeChangedCallback()
时都记录它,它会记录两次(因为我有两个属性被监视)。
这是片段:
class GeoComponent extends HTMLElement {
constructor() {
super();
this.shadow = this.createShadowRoot();
this._latitude = 0;
this._longitude = 0;
}
get latitude(){
return this._latitude;
}
get longitude(){
return this._longitude;
}
set latitude(val){
this.setAttribute('latitude', val);
}
set longitude(val){
this.setAttribute('longitude', val);
}
static get observedAttributes(){
return ['latitude', 'longitude'];
}
attributeChangedCallback(name, oldVal, newVal){
let geoComp = this.shadow.getElementById('geo');
console.log(geoComp);
switch(name){
case 'latitude':
this._latitude = parseInt(newVal, 0) || 0;
// geoComp.innerHTML = `${this.latitude}, ${this.longitude}`;
break;
case 'longitude':
this._longitude = parseInt(newVal, 0) || 0;
// geoComp.innerHTML = `${this.latitude}, ${this.longitude}`;
break
}
}
connectedCallback(){
let template = `
<div class="geo-component" id="geo">
</div>
`;
this.shadow.innerHTML = template;
}
}
window.customElements.define('geo-component', GeoComponent);
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="geoComponent.js"></script>
</head>
<body>
<h1>Geo-Component</h1>
<geo-component latitude="12" longitude="-70"></geo-component>
</body>
</html>
更新
就像@acdcjunior 在将 this.createShadowRoot();
更改为 this.shadow = this.attachShadow({mode: 'open'});
(从 ShadowDOM v0 到 v1)后提到的那样解决了我的问题,因为执行了 connectedCallback()
函数幕后,只有一次。
attributeChangedCallback()
在(观察到的)属性被 初始化(声明式,这是您的情况)、添加、更改或删除时调用。这意味着它在 connectedCallback()
.
通常我们使用 constructor() 来创建 DOM:
Name: constructor
Called when: An instance of the element is created or upgraded. Useful for initializing state, settings up event listeners, or creating shadow dom. See the spec for restrictions on what you can do in the constructor.
我把你的逻辑移到里面了。
您也在使用 ShadowDOM v0。将其更新为 v1(attachShadow
而不是 createShadowRoot
)。
更新演示:
class GeoComponent extends HTMLElement {
constructor() {
super();
console.log('constructor called');
this.attachShadow({mode: 'open'});
this._latitude = 0;
this._longitude = 0;
let template = `
<div class="geo-component" id="geo">
</div>
`;
this.shadowRoot.innerHTML = template;
}
get latitude() {
return this._latitude;
}
get longitude() {
return this._longitude;
}
set latitude(val) {
this.setAttribute('latitude', val);
}
set longitude(val) {
this.setAttribute('longitude', val);
}
static get observedAttributes() {
return ['latitude', 'longitude'];
}
attributeChangedCallback(name, oldVal, newVal) {
console.log('attributeChangedCallback() called:', name, ':', oldVal, '->', newVal);
let geoComp = this.shadowRoot.getElementById('geo');
console.log(geoComp);
switch (name) {
case 'latitude':
this._latitude = parseInt(newVal, 0) || 0;
// geoComp.innerHTML = `${this.latitude}, ${this.longitude}`;
break;
case 'longitude':
this._longitude = parseInt(newVal, 0) || 0;
// geoComp.innerHTML = `${this.latitude}, ${this.longitude}`;
break
}
}
connectedCallback() {
console.log('connectedCallback() called');
}
}
window.customElements.define('geo-component', GeoComponent);
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="geoComponent.js"></script>
</head>
<body>
<h1>Geo-Component</h1>
<geo-component latitude="12" longitude="-70"></geo-component>
</body>
</html>