【问题标题】:How to embed a link in a custom component as a slot?如何将链接作为插槽嵌入到自定义组件中?
【发布时间】:2021-09-12 01:15:51
【问题描述】:

我正在尝试创建一个包含一些动画的简单组件。我为链接的文本设置了名称属性。我为链接的目标设置了一个插槽,但模板不允许将链接设置为插槽。我不确定接下来要尝试什么。

当我将鼠标悬停在链接上时,它只会显示 <slot name= 而不是实际的 URL。

const template = document.createElement('template');
template.innerHTML = `
  <style>
    .txt-link a {
      color: #005fec;
      font-weight: 700;
      font-size: 18px;
      text-decoration: none;
      position: relative;
    }
    .txt-link a:hover {
      text-decoration: none;
      cursor: pointer;
    }
    .txt-link a::before {
      content: "";
      position: absolute;
      bottom: -5px;
      left: 0;
      width: 0;
      height: 1px;
      background-color: #005fec;
      visibility: hidden;
      transition: all 0.3s ease-in-out 0s;
    }
    .txt-link a:hover::before {
      visibility: visible;
      width: 100%;
    }
    .txt-link.arrow-link img {
      height: 15px;
      position: relative;
      top: 2px;
    }
  </style>
  <div class="txt-link arrow-link">
    <a href="<slot name="destination" />"></a>
    <img alt="arrow right icon" class="learn-more-arrow" src="https://www.pikpng.com/pngl/m/73-734729_arrow-blue-right-transparent-blue-arrow-right-clipart.png" loading="lazy">
  </div>
`;

class CustomAnimLink extends HTMLElement {
  constructor() {
    super();

    this.showInfo = true;

    this.attachShadow({ mode: 'open' });
    this.shadowRoot.appendChild(template.content.cloneNode(true));
    this.shadowRoot.querySelector('a').innerText = this.getAttribute('name');
  }
}

window.customElements.define('custom-anim-link', CustomAnimLink);
<custom-anim-link name="Learn more">
  <div slot="destination">https://www.yahoo.com</div>
</custom-anim-link>

【问题讨论】:

    标签: javascript shadow-dom custom-component custom-element createelement


    【解决方案1】:

    你不能用插槽做到这一点。插槽用于将HTMLElements 放置在插槽的位置,除此之外不能用于任何其他用途。

    而是将 URL 作为属性传递。这似乎适合数据类型。 Web Components 有一些很好的生命周期可以帮助您解决这个问题。

    我添加了static get observedAttributes() 表示应该遵守一些属性。这样做可以让您在某个属性中的值发生更改时执行某些操作,例如更新 Shadow DOM 中锚点上的 URL。

    每当观察到的属性值发生变化时,都会调用attributeChangedCallback,您可以在其中确定值发生变化时应该发生的情况。

    observedAttributesattributeChangedCallback 都是 Web 组件生命周期挂钩的一部分。

    const template = document.createElement('template');
    template.innerHTML = `
      <style>
        .txt-link a {
          color: #005fec;
          font-weight: 700;
          font-size: 18px;
          text-decoration: none;
          position: relative;
        }
        .txt-link a:hover {
          text-decoration: none;
          cursor: pointer;
        }
        .txt-link a::before {
          content: "";
          position: absolute;
          bottom: -5px;
          left: 0;
          width: 0;
          height: 1px;
          background-color: #005fec;
          visibility: hidden;
          transition: all 0.3s ease-in-out 0s;
        }
        .txt-link a:hover::before {
          visibility: visible;
          width: 100%;
        }
        .txt-link.arrow-link img {
          height: 15px;
          position: relative;
          top: 2px;
        }
      </style>
      <div class="txt-link arrow-link">
        <a href=""><slot></slot></a>
        <img alt="arrow right icon" class="learn-more-arrow" src="https://www.pikpng.com/pngl/m/73-734729_arrow-blue-right-transparent-blue-arrow-right-clipart.png" loading="lazy">
      </div>
    `;
    
    class CustomAnimLink extends HTMLElement {
    
      static get observedAttributes() {
        return ['name', 'destination'];
      }
    
      constructor() {
        super();
    
        this.showInfo = true;
        this.attachShadow({
          mode: 'open'
        });
        this.shadowRoot.appendChild(template.content.cloneNode(true));
      }
    
      get anchor() {
        return this.shadowRoot.querySelector('a');
      }
    
      get name() {
        return this.getAttribute('name');
      }
    
      set name(value) {
        if ('string' === typeof value) {
          this.setAttribute('name', value);
        }
      }
    
      get destination() {
        return this.getAttribute('destination');
      }
    
      set destination(value) {
        if ('string' === typeof value) {
          this.setAttribute('destination', value);
        }
      }
    
      attributeChangedCallback(attrName, oldValue, newValue) {
        switch (attrName) {
          case 'destination':
            this.anchor.href = newValue;
            break;
          case 'name':
            this.anchor.textContent = newValue;
            break;
        }
      }
    }
    
    window.customElements.define('custom-anim-link', CustomAnimLink);
    &lt;custom-anim-link name="Learn more" destination="https://www.yahoo.com"&gt;&lt;/custom-anim-link&gt;

    或者,您可以在插槽的位置传递&lt;a&gt; 标记。然后获取分配给destination 槽的所有元素,并根据name 属性的值设置textContent 属性。我们在上一个示例中添加的 destination 属性也是如此。

    const template = document.createElement('template');
    template.innerHTML = `
      <style>
        .txt-link a {
          color: #005fec;
          font-weight: 700;
          font-size: 18px;
          text-decoration: none;
          position: relative;
        }
        .txt-link a:hover {
          text-decoration: none;
          cursor: pointer;
        }
        .txt-link a::before {
          content: "";
          position: absolute;
          bottom: -5px;
          left: 0;
          width: 0;
          height: 1px;
          background-color: #005fec;
          visibility: hidden;
          transition: all 0.3s ease-in-out 0s;
        }
        .txt-link a:hover::before {
          visibility: visible;
          width: 100%;
        }
        .txt-link.arrow-link img {
          height: 15px;
          position: relative;
          top: 2px;
        }
      </style>
      <div class="txt-link arrow-link">
        <slot name="destination"></slot>
        <img alt="arrow right icon" class="learn-more-arrow" src="https://www.pikpng.com/pngl/m/73-734729_arrow-blue-right-transparent-blue-arrow-right-clipart.png" loading="lazy">
      </div>
    `;
    
    class CustomAnimLink extends HTMLElement {
    
      static get observedAttributes() {
        return ['name', 'destination'];
      }
    
      constructor() {
        super();
    
        this.showInfo = true;
        this.attachShadow({
          mode: 'open'
        });
        this.shadowRoot.appendChild(template.content.cloneNode(true));
      }
    
      get destinations() {
        const slot = this.shadowRoot.querySelector('slot');
        const assignedElements = slot.assignedElements();
        return assignedElements;
      }
    
      get name() {
        return this.getAttribute('name');
      }
    
      set name(value) {
        if ('string' === typeof value) {
          this.setAttribute('name', value);
        }
      }
      
      get destination() {
        return this.getAttribute('destination');
      }
    
      set destination(value) {
        if ('string' === typeof value) {
          this.setAttribute('destination', value);
        }
      }
      
      attributeChangedCallback(attrName, oldValue, newValue) {
        switch(attrName) {
          case 'name':
            this.destinations.forEach(destination => {
              destination.textContent = newValue;
            });
            
            break;
          case 'destination':
            this.destinations.forEach(destination => {
              destination.href = newValue;
            });
            
            break;
        }
      }
    }
    
    window.customElements.define('custom-anim-link', CustomAnimLink);
    <custom-anim-link name="Learn more" destination="https://www.yahoo.com">
      <a slot="destination"></a>
    </custom-anim-link>

    或者作为最后的简单手段,只需将 &lt;a&gt; 作为子元素完整地传递给您的自定义元素。

    <custom-anim-link>
      <a href="https://www.yahoo.com">Learn more</a>
    </custom-anim-link>
    

    【讨论】:

    • 看来我还有很多东西要学。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2018-06-20
    • 1970-01-01
    • 2014-01-02
    • 1970-01-01
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    • 2021-04-03
    相关资源
    最近更新 更多