首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在继承web组件时填充这些空位?

如何在继承web组件时填充这些空位?
EN

Stack Overflow用户
提问于 2021-03-08 07:10:39
回答 2查看 172关注 0票数 0

假设我有一个对话框组件,比如

代码语言:javascript
复制
class ModalDialog extends HTMLElement {
    constructor(){
        super()
        this._shadow = this.attachShadow({mode: 'closed'})
    }

    connectedCallback(){
        const template = `
            <style>
            ... lots of style that doesn't matter to this question ...
            </style>
            <div class="dialog">
                <div class="dialog-content">
                    <div class="dialog-header">
                        <slot name="header"></slot>
                        <span class="close">&times;</span>
                    </div>
                    <div class="dialog-body"><slot name="body"></slot></div>
                    <div class="dialog-footer"><slot name="footer"></slot></div>
                </div>
            </div>
        `

        this._shadow.innerHTML = template
        this._shadow.querySelector('.close').onclick = () => this.hide()
        const dialog = this._shadow.querySelector('.dialog')
        dialog.onclick = evt => {
            if(evt.target == dialog){ //only if clicking on the overlay
                this.hide()
            }
        }
        this.hide()
    }

    show() {
        this.style.display = 'block'
    }

    hide(){
        this.style.display = 'none'
    }
}

window.customElements.define('modal-dialog', ModalDialog)

现在假设我想创建专用的对话框...例如,允许用户选择图像的图像。

我可以这样做

代码语言:javascript
复制
import {} from './modal-dialog.js'

class ImageSelector extends HTMLElement {
    constructor(){
        super()
        this._shadow = this.attachShadow({mode: 'closed'})
    }

    connectedCallback(){
        const template = `
            <style>
                ... more style that doesn't matter ...
            </style>
            <modal-dialog>
                <div slot="header"><h3>Select Image</h3></div>
                <div slot="body">
                     ... pretend there's some fancy image selection stuff here ...
                </div>
            </modal-dialog>
        `
        this._shadow.innerHTML = template
    }

    show(){
        this._shadow.querySelector('modal-dialog').show()
    }

    hide(){
        this._shadow.querySelector('modal-dialog').hide()
    }
}
window.customElements.define('image-selector', ImageSelector)

但是我不喜欢那里的showhide方法。

另一种选择是从对话框而不是从HTMLElement继承...

代码语言:javascript
复制
import {} from './modal-dialog.js'

class ImageSelector extends customElements.get('modal-dialog'){
    constructor(){
        super()
    }

    connectedCallback(){
        ... now what? ...
    }
}
window.customElements.define('image-selector', ImageSelector)

但如果我这样做了,我实际上该如何填补空缺呢?

天真的方法当然是使用_shadow并将其放入插槽的内部html中,但我有一种感觉,这不是一种方法。

EN

回答 2

Stack Overflow用户

发布于 2021-03-08 11:57:26

TLDR;不可能同时使用继承和组合。

长长的答案:

您实际上混合了两个截然不同但不同的概念:

  1. 继承-在覆盖/重载现有behavior
  2. Composition时使用-在使用其他实体的行为并围绕其添加更多行为时使用。

通常,在Web编程中,由于Composition提供的松散耦合,它总是比继承更受欢迎。

在这种情况下,你实际上想要使用模板,而不是实际覆盖它的。因此,组合在这里是一个更好的选择。但这也意味着您实际上必须编写更多的样板代码,即showhide方法的包装器实现。

从理论上讲,发明继承是为了促进代码重用和避免重复代码,但与组合相比,这是一种成本。

票数 1
EN

Stack Overflow用户

发布于 2021-03-08 20:55:25

Harshals的回答提供了不错的信息;以下是userland代码

除非您正在执行SSR,否则读取的第一个文件是HTML文件。

因此,将模板内容放在那里,让one generic Modal Web组件读取模板

代码语言:javascript
复制
<template id="MODAL-DIALOG">
  <style>
    :host { display: block; background: lightgreen; padding:.5em }
    [choice]{ cursor: pointer }
  </style>
  <slot></slot>
  <button choice="yes">Yes</button>
  <button choice="no" >No</button>
</template>
<template id="MODAL-DIALOG-IMAGES">
  <style>
    :host { background: lightblue; } /* overrule base template CSS */
    img { height: 60px; }
    button { display: none; } /* hide stuff from base template */
  </style>
  <h3>Select the Framework that is not Web Components friendly</h3>
  <img choice="React" src="https://image.pngaaa.com/896/2507896-middle.png">
  <img choice="Vue" src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Vue.js_Logo_2.svg/1184px-Vue.js_Logo_2.svg.png">
  <img choice="Svelte" src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Svelte_Logo.svg/1200px-Svelte_Logo.svg.png">
   <slot><!-- remove slot from BaseTemplate, then this slot works --></slot>
</template>

<modal-dialog>Standard Modal</modal-dialog>
<modal-dialog template="-IMAGES">Images Modal</modal-dialog>

<script>
  document.addEventListener("modal-dialog", (evt) => {
    alert(`You selected: ${evt.detail.getAttribute("choice")}`)
  });
  customElements.define('modal-dialog', class extends HTMLElement {
    constructor() {
      let template = (id="") => {// if docs say "use super() first" then docs are wrong
        let templ = document.getElementById(this.nodeName + id);
        if (templ) return templ.content.cloneNode(true);
        else return []; // empty content for .append
      }
      super().attachShadow({mode:"open"})
             .append( template(),
                      template( this.getAttribute("template") ));
      this.onclick = (evt) => {
        let choice = evt.composedPath()[0].hasAttribute("choice");
        if (choice) 
          this.dispatchEvent(
            new CustomEvent("modal-dialog", {
              bubbles: true,
              composed: true,
              detail: evt.composedPath()[0]
            })
          );
       // else this.remove();   
      }
    }
    connectedCallback() {}
  });
</script>

笔记

  • 当然可以将<TEMPLATES>包装在JS字符串

  • 您不能在模板中添加<script>

嗯,你可以..。但它在全局范围内运行,而不是在组件范围内运行

  • 对于更复杂的对话框和<SLOT>,您可能需要使用代码

从底板中移除不需要的插槽

  • 不要把它搞得太复杂:

代码语言:javascript
复制
- Good Components do a handful of things very good.
- Bad Components try to do everything... create another Component
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66522470

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档