通过这个项目,我正在尝试创建一个表现为地图的自定义组件。我还在通过W3C文档和几个Youtube视频学习Web组件的基础知识。
主要问题是,在组件类中有一个名为attributeChangedCallback()
的函数,每当其中一个属性发生变化时,它们就会被触发,这些属性包含在observedAttributes()
函数中并且在设置之后它们(前面提到过的函数)我尝试通过选择器访问shadow DOM(声明为connectedCallback()
,一旦组件被加载到HTML body元素中就会被触发)。但是,如果我这样做,变量内容为null。
attributeChangedCallback()
应该加载 AFTER 加载内容,所以我不明白为什么会这样,每次属性改变时我都需要访问这个元素所以我可以更新其内容。奇怪的事实:如果我每次执行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()
函数在幕后执行而且只执行一次。 / p>
答案 0 :(得分:2)
attributeChangedCallback()
。这意味着在connectedCallback()
之前调用它。
通常我们使用构造函数()来创建DOM:
名称: 构造函数
在以下情况下调用:创建元素的实例 或升级。用于初始化状态,设置事件 听众,或创建阴影dom 。请参阅规范了解限制 你可以在构造函数中做什么。
我把你的逻辑移到了它。
您也在使用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>