Web组件:访问Custom Component类中的shadow DOM

时间:2018-04-01 22:33:19

标签: javascript web-component web-component-tester google-web-component native-web-component

通过这个项目,我正在尝试创建一个表现为地图的自定义组件。我还在通过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>

1 个答案:

答案 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>