Web组件中的插槽选择器限制 [英] slot selector limit in web component

查看:87
本文介绍了Web组件中的插槽选择器限制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

slot是制作可重用的Web组件的好方法,但是到目前为止,它有一个限制.我面临的是风格问题.即使您不知道注入内容的结构,也无法定义组件内部的样式.

slot is good to make a reusable web component, however, it has a limit so far. What I faced is the style problem. You just can't define the style inside a component, even you know what the inject content's structure would be.

在github 此处

我编写了一个组件,然后尝试从外部通过slot注入内容,并尝试为组件的影子根目录中的特定内容添加样式. 演示

I write a component, and try to inject content through slot from the outside and try to add style to the specific content in the component's shadow root. Demo

HTML文件

  <my-navbar>
    <ul>
      <li>link1</li>
      <li>link2</li>
      <li>link3</li>
      </ul>
  </my-navbar>

JS文件

customElements.define('my-navbar', class extends HTMLElement {
  constructor () {
    super();
    const sr = this.attachShadow({ mode: 'open' });
    sr.innerHTML = `
      <style>
      /*worked*/
      ::slotted(ul)
      {
        color:green;
      }
      /*
      Suppose I know the outside content is "ul li", and I directly define the 
      style after they injected into component's slot. However, it just doesn't 
      work because the slotted selector is just a compound selector. It can only 
      affect the first layer 'ul'. It can't affect the child dom 'li' */
      ::slotted(ul li)
      {
        color:red;
      }
      </style>
      <slot></slot>
    `;
  }
});

但是,它只是不能直接使用,因为您不能为 :: slot(simple_selector)使用复杂的选择器. 原因

However, it just doesn't work directly because you just can't use a complex selector for ::slot(simple_selector) Reason

我找到了一个间接解决方案,那就是将外部内容重新添加到组件的影子根内部的插槽中. 演示

I found an indirect solution, and that's to re-append the outside content into the slots inside the component's shadow root. Demo

HTML文件

  <my-navbar>
    <!--a dom defined a slot property-->
    <ul slot='t'>
      <li>link1</li>
      <li>link2</li>
      <li>link3</li>
      </ul>
    <!--A dom not define slot property-->
    <span>1234</span>
  </my-navbar>

JS文件

customElements.define('my-navbar', class extends HTMLElement {
  constructor () {
    super();
    const sr = this.attachShadow({ mode: 'open' });
    sr.innerHTML = `
      <style>
      ul li
      {
        color:red;
      }
      </style>
      <slot name='t'></slot>
      <slot ></slot>
    `;
    // Do something later...
    setTimeout(this.appendOutsideSlotContentIntoInsideSlot.bind(this), 1000)
  }

    appendOutsideSlotContentIntoInsideSlot()
  {

    // Insert outside dom element which has define slot property into the specify slot inside the shadow root
    debugger;
     for (let objIndex=0;objIndex<this.children.length;) 
     {
        var obj=this.children[objIndex];
        if(obj.slot){
          var slot=this.shadowRoot.querySelector('slot[name='+obj.slot+']');
          if(slot)
          {
              slot.appendChild(obj);
              continue;
           }
       }
       objIndex++;
    }


    // Insert the rest dom which has not define slot property values into the anonymous slot
    var defaultSlot=Array.prototype.slice.call(this.shadowRoot.querySelectorAll('slot')).filter(function(el){ return !el.name})[0];

    debugger;
    if(defaultSlot)
      {
         while (this.children.length>0) 
        {
          defaultSlot.appendChild(this.children[0])

        }

      }
  }
});

好吧,它适用于定义了slot属性的内容,但不适用于没有slot属性的内容.

Well, it works for the contents which have defined the slot property, but doesn't work again with content that has no slot property.

推荐答案

除了一些可继承的规则外,插槽的内容不应直接受到组件的影子CSS的影响.它们旨在允许对组件外部的CSS进行控制.

With the exception of a few inheritable rules the contents of the slot are not supposed to be directly affected by your component's shadow CSS. They are designed to allow the CSS outside of your component to be in control.

那是设计使然.

这类似于对影子DOM中的元素的保护不受外部CSS的影响.

This is similar to the protection given to elements within the shadow DOM not being affected by external CSS.

阅读以下部分的设置分布式节点的样式:仅允许您更改插槽内顶级元素的CSS规则.而且,您甚至受限于您可以做的事情.所有子元素均由影子DOM外部的CSS控制.

You are only allowed to change CSS rules for the top level elements inside the slot. And you are even limited to what you can do to that. All child elements are controlled by the CSS outside of the shadow DOM.

在下面的示例中,您将看到我们可以更改顶级元素或<ul>标签的颜色和背景颜色:

In the example below you will see that we can change the color and background color of the top level elements, or the <ul> tags:

customElements.define('my-navbar', class extends HTMLElement {
  constructor () {
    super();
    const sr = this.attachShadow({ mode: 'open' });
    sr.innerHTML = `
      <style>
      ::slotted(ul)
      {
        color: blue;
      }
      
      ::slotted(.bold) {
        font-weight: bold;
        background-color: #222;
        color: #FFF;
      }
      
      ::slotted(.italic) {
        font-style: italic;
        background-color: #AAA;
        color: #000;
      }

      ::slotted(*)
      {
        color: red;
      }
      </style>
      <slot></slot>
    `;
  }
});

<my-navbar>
  <ul class="bold">
    <li>link1</li>
    <li class="italic">link2</li>
    <li>link3</li>
  </ul>
  <ul class="italic">
    <li>link1</li>
    <li class="bold">link2</li>
    <li>link3</li>
  </ul>
</my-navbar>

在上面的示例中,文本为红色而不是蓝色的唯一原因是因为::slotted(*)仅影响两个<ul>,具有与::slotted(ul)相同的特异性,并且位于::slotted(ul)之后.颜色由<li>标记继承,因为CSS就是这样工作的.

In the example above, the only reason the text is red and not blue is because ::slotted(*) affects just the two <ul>, has the same specificity as ::slotted(ul) and is placed after ::slotted(ul). The color is inherited by the <li> tags because that is how CSS works.

背景颜色仅影响<ul>标记的类别,而不会影响具有相同类别的<li>标记.

The background colors only affect the <ul> tags based on their classes and not the <li> tags with identical classes.

在下面的示例中,<li>颜色和背景颜色由阴影DOM外部的CSS控制.即使影子DOM规则同时包含tagclass选择器(ul.bold),外部规则的行为似乎比影子DOM规则更具体.

In the example below, the <li> color and background-color are controlled by the CSS outside the shadow DOM. The external rules act as if they are more specific then the shadow DOM rules even though the shadow DOM rules included both a tag and a class selector (ul.bold).

同样,这是设计使然.

customElements.define('my-navbar', class extends HTMLElement {
  constructor () {
    super();
    const sr = this.attachShadow({ mode: 'open' });
    sr.innerHTML = `
      <style>
      ::slotted(ul)
      {
        color: blue;
      }
      
      ::slotted(ul.bold) {
        font-weight: bold;
        background-color: #222;
        color: #FFF;
      }
      
      ::slotted(ul.italic) {
        font-style: italic;
        background-color: #AAA;
        color: #000;
      }

      ::slotted(*)
      {
        color: red;
      }
      </style>
      <slot></slot>
    `;
  }
});

li {
  color: #555;
  backgroung-color: #ddd;
}

.bold {
  font-weight: bold;
  background-color: #FF0;
}

.italic {
  font-style: italic;
  background-color: #0FF;
}

<my-navbar>
  <ul class="bold">
    <li>link1</li>
    <li class="italic">link2</li>
    <li>link3</li>
  </ul>
  <ul class="italic">
    <li>link1</li>
    <li class="bold">link2</li>
    <li>link3</li>
  </ul>
</my-navbar>

您会注意到,<ul><li>标记的背景色是根据bolditalic的外部类设置的.

You will note that the background colors of the <ul> and <li> tags are set based on the external classes of bold and italic.

如果要使用<slot>,则表示您同意使用组件的开发人员具有放置在插槽中的任何物品的覆盖能力.

If you want to use a <slot> the you agree that the developer using your component has the override power for anything that is placed into the slot.

如果您不希望用户拥有这种控件,那么防止它的唯一方法就是将组件的子代移入组件的影子DOM.

If you don't want the user to have that kind of control then the only way to prevent it is to move the component's children into the component's shadow DOM.

但是要小心.

根据 Web组件构造函数的规则您不能在构造函数中访问或更改组件的子代.

According to the rules of Web Component constructors you can not access or change the children of a component while in the constructor.

但是您必须记住,connectedCallback每次都被称为 ,该组件被插入到DOM中.因此,如果开发人员删除然后重新添加您的组件,则connectedCallback将再次被调用.因此,您必须添加一个门来防止它被调用两次.

But you have to remember that the connectedCallback is called every time the component is inserted into the DOM. So if the developer removes and then re-appends your component then the connectedCallback will be called again. So you have to add a gate to prevent it from getting called twice.

此外,您可能还想添加 MutationObserver 来查看用户何时更改了以下子项.您的组件.

Also you might want to add a MutationObserver to see when the user changes the children of your components.

这篇关于Web组件中的插槽选择器限制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆