องค์ประกอบของเว็บ HTML ไม่ใช้สไตล์ DOM เงา

Aug 15 2020

ฉันได้สร้างองค์ประกอบเว็บวานิลลาหรือองค์ประกอบ HTML แล้ว เพียงแค่แสดงลิงก์สองลิงก์

ในการห่อหุ้มสิ่งนั้นฉันใช้ shadow DOM อย่างไรก็ตามดูเหมือนว่าจะไม่มีการห่อหุ้ม ในต้นไม้ DOM มันอยู่ใน # shadow-root ซึ่งเป็นสิ่งที่ดี

เหตุใดส่วนประกอบของเว็บจึงใช้สไตล์ส่วนกลางแทนสไตล์ที่ฉันให้ไว้ในเทมเพลตสำหรับส่วนประกอบเว็บของฉัน

ข้อความเป็นสีแดงและคาดว่าจะเป็นสีเขียว

class MyEl extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: "open" });
  }

  connectedCallback() {
    const template = `
      <style>
        a {
          color: green;
        }
      </style>
      <slot></slot>`;
    this.shadow.innerHTML = template;
  }
}

window.customElements.define("my-el", MyEl);
a {
  color: red
}
  <my-el>
    <a href="example.com">Item1</a>
    <a href="example.com">Item2</a>
  </my-el>

คำตอบ

1 AlanDávalos Aug 17 2020 at 15:12

แม้ว่าคำถามนี้จะมีคำตอบที่ยอมรับแล้ว แต่การย้ายลูกของสล็อตไปที่ shadowRoot นั้นไม่เป็นที่ต้องการสำหรับกรณีการใช้งานส่วนใหญ่

สิ่งที่คุณอาจต้องทำคือใช้::slotted()ตัวเลือก

เพียงจำไว้ว่าสไตล์ที่ใช้กับลูกของสล็อตผ่าน::slotted()ตัวเลือกจะทำหน้าที่เป็นสไตล์ "ค่าเริ่มต้น" เท่านั้นและยังสามารถแทนที่ได้โดยใช้สไตล์ใน DOM ที่มีแสง

ตัวอย่างเช่นตรวจสอบเวอร์ชันแก้ไขของข้อมูลโค้ดของคุณ:

อย่างที่คุณเห็นคราวนี้my-elพยายามใช้ทั้งสีและสไตล์การตกแต่งข้อความเพื่อยึด ( <a>) ลูก ๆ ในช่องใดก็ได้

อย่างไรก็ตามในไลท์ดอมเรามีa.specialตัวเลือกที่แทนที่สีดังนั้น<a class="special">จะเป็นสีแดงไม่ใช่สีเขียว

class MyEl extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: "open" });
  }

  connectedCallback() {
    const template = `
      <style>
        ::slotted(a) {
          color: green;
          text-decoration: none;
        }
      </style>
      <slot></slot>`;
    this.shadow.innerHTML = template;
  }
}

window.customElements.define("my-el", MyEl);
a.special {
  color: red
}
  <my-el>
    <a href="example.com">Item1</a>
    <a class="special" href="example.com">Item2</a>
  </my-el>

1 Danny'365CSI'Engelman Aug 15 2020 at 23:44

คำอธิบายโดยละเอียดทั้งหมดอยู่ใน:: ตัวเลือก CSS แบบ slotted สำหรับลูกที่ซ้อนกันในสล็อต shadowDOM

TL; ดร

ลิงก์ของคุณอยู่ใน lightDOM ดังนั้นจึงมีสไตล์โดย DOM (ในรหัสของคุณคือเอกสาร DOM)
การย้ายโหนดจาก lightDOM ไปยัง shadowDOM เป็น "โซลูชัน" อย่างหนึ่ง แต่คุณไม่ได้ใช้สล็อตแล้ว

FYI รหัสของคุณสามารถบีบอัดเป็น:

class MyEl extends HTMLElement {
  constructor() {
    super().attachShadow({ mode: "open" })
           .innerHTML = `<style>a{color:green}</style><slot></slot>`;

  }
}

window.customElements.define("my-el", MyEl);

คำตอบที่เกี่ยวข้องกับ SLOT เพิ่มเติมสามารถพบได้ใน StackOverflow Search: Custom Elements SLOTs

KresimirPendic Aug 15 2020 at 19:57

สังเกตบรรทัดนี้คุณต้องย้าย / คัดลอกองค์ประกอบไปที่เงาเช่น:

this.shadow.innerHTML = this.innerHTML + template;

ฉันได้เพิ่มสิ่งนี้เพื่อแสดงให้เห็นว่าสไตล์อินไลน์เท่านั้นที่จะถูกนำไปใช้กับองค์ประกอบ Shadow Dom .. ดังนั้นลิงก์ที่คัดลอกใน SD จึงใช้สไตล์ของคุณ :)

เพื่อให้สีแดงจะเป็นGLOBAL, สีเขียวจะเป็นSHADOWองค์ประกอบ

class MyEl extends HTMLElement {
  constructor() {
    super();
  }

  connectedCallback() {
    this.shadow = this.attachShadow({ mode: "open" });
    const template = `
      <style>
        a {
          color: green;
        }
      </style>
      <slot></slot>`;
    this.shadow.innerHTML = this.innerHTML + template;
  }
}

window.customElements.define("my-el", MyEl);
a {
  color: red
}
<my-el>
    <a href="example.com">Item1</a>
    <a href="example.com">Item2</a>
  </my-el>