Web组件:<template>

时间:2019-08-10 17:15:48

标签: javascript web-component

我正在使用以下代码创建Web组件的实例:

<main></main>
<template id="my-template">
  <style>
    p { color: green; }
  </style>
  <p>I'm in Shadow DOM.</p>
</template>


<script>
  let tmpl = document.querySelector('#my-template');
  class AppDrawer extends HTMLElement {

    constructor() {
      super(); 
      this.root = this.attachShadow({mode: 'open'});
      //this.root.appendChild(tmpl.content.cloneNode(true));
    }

    set details(user) {
      this.root.innerHTML = `<h2> ${user.company.name}</h2>`
    }
  }
  window.customElements.define('app-drawer', AppDrawer);


  async function asyncCall() {
    const res = await fetch("https://jsonplaceholder.typicode.com/users");
    const json = await res.json();

    const main = document.querySelector("main");
    json.forEach(user=> {
      const el = document.createElement("app-drawer");
      el.details = user;
      main.appendChild(el);
    });
  }

  asyncCall();

</script>

通过运行上面的命令,我得到了一些名称作为输出。到目前为止,一切都很好。现在,尝试使用<template>而不是通过删除构造函数中的注释并同时删除el.details = user;来获得多个I'm in Shadow DOM. 我的问题是 如何使用第二种方法实现第一种情况的动态内容(不同的用户名)?

2 个答案:

答案 0 :(得分:1)

您只需要用一条将适当的HTML添加到影子DOM的语句替换el.details = user。 (这使设置员无关紧要,因此我已将其注释掉。)


编辑:
根据评论的要求,我已更新了代码段,以在构建期间将user.company.name作为属性传递给Web组件,而不是在此之后强制设置该值。

(请注意,我从模板中删除了<p>元素,而只包含了将显示<h2>的{​​{1}}元素。)

userCompanyName
let tmpl = document.querySelector('#my-template');
class AppDrawer extends HTMLElement {
  constructor() {
    super();
    this.root = this.attachShadow({ mode: 'open' });
 
    // Creates a copy of the `<template>` element's contents
    const copy = tmpl.content.cloneNode(true);

    // Selects a target element withinin the copy
    const header = copy.querySelector("H2");

    // Copies the component instance's `usernamecomp` attribute to its `userCompName` property
    this.userCompName = this.getAttribute("usercompname");

    // Sets the target element's contents equal to the`userCompName` property
    header.innerHTML = this.userCompName;

    // Appends the augmented copy to the shadowDOM
    this.root.appendChild(copy);
  }
}
window.customElements.define('app-drawer', AppDrawer);

async function asyncCall() {
  const res = await fetch("https://jsonplaceholder.typicode.com/users");
  const json = await res.json();
  const main = document.querySelector("main");

  json.forEach(user => {
 
    // Identifies the string to pass into the component instance as an attribute
    const userCompName = user.company.name;
 
    // Writes HTML to be used to instantiate an `<app-drawer>` element with a `usercompname` attribute
    const drawerInstance = `<app-drawer usercompname=${userCompName}></app-drawer>`;
 
    // Creates the new `<app-drawer>` element, appended to the `<main>` element     
    main.insertAdjacentHTML("beforeend", drawerInstance);
  });
}

asyncCall();

答案 1 :(得分:1)

您可以将加载的值作为参数传递给使用new创建的自定义元素:

json.forEach( user => main.appendChild( new AppDrawer( user ) ) )

您只需要使用参数定义自定义元素constructor()

constructor( user ) {
    ...
}

请参阅下面的完整示例:

class AppDrawer extends HTMLElement {
    constructor( user ) {
      super()
      this.attachShadow( {mode: 'open'} )
          .innerHTML = `<style> p { color: green } </style>
              <p> ${user.company.name} </p>`
    }
}
window.customElements.define( 'app-drawer', AppDrawer )

async function asyncCall() {
    const res = await fetch( "https://jsonplaceholder.typicode.com/users" )
    const json = await res.json()

    const main = document.querySelector( "main" )
    json.forEach( user => main.appendChild( new AppDrawer( user ) ) )
}

asyncCall()
<main></main>