【问题标题】:Get modified element in HTML slot获取 HTML 插槽中的修改元素
【发布时间】:2021-05-11 21:04:44
【问题描述】:

我正在尝试创建一个自定义 HTML 组件,该组件为其拥有的每个子元素创建选项卡。这是该自定义组件的代码:

const code_window = document.getElementById("window");
class CodeWindow extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({
            mode: 'open'
        });
        this.shadowRoot.appendChild(code_window.content.cloneNode(true));
        this.code = this.shadowRoot.getElementById("code");
        this.tabbar = this.shadowRoot.getElementById("tabbar");
        this.code.addEventListener("slotchange", e => {
            var elems = e.target.assignedNodes();
            for (let i = 0; i < elems.length; i++) {
                var tab = document.createElement("div");
                tab.classList.add("tab");
                var name = elems[i].getAttribute("name");
                tab.innerHTML = name;
                tab.setAttribute("name", name);
                this.tabbar.appendChild(tab);
                if (elems[i].hasAttribute("active")) this.activateTab(name);
                tab.addEventListener("click", e => this.activateTab(e.target.getAttribute("name")));
            }
            if (!this.previous_tab && this.tabbar.children.length > 0) this.activateTab(this.tabbar.children[0].getAttribute("name"));
        });
    }
    activateTab(name) {
        if (this.previous_tab) {
            this.previous_frame.removeAttribute("active");
            this.previous_tab.removeAttribute("active");
        }
        var tabs = this.tabbar.children,
            frames = this.code.assignedElements();
        for (let i = 0; i < tabs.length; i++) {
            if (tabs[i].getAttribute("name") == name) {
                tabs[i].setAttribute("active", "");
                frames[i].setAttribute("active", "");
                this.previous_frame = frames[i];
                this.previous_tab = tabs[i];
                break;
            }
        }
    }
}
customElements.define("c-window", CodeWindow);
<template id="window">
    <style>
        :host {
            display: flex;
            flex-direction: column;
        }
        #titlebar {
            display: flex;
            background-color: green;
        }
        #tabbar {
            flex-grow: 1;
            display: flex;
        }
        #tabbar .tab {
            display: flex;
            align-items: center;
            padding: 5px 10px;
            background-color: #bbb;
        }
        #tabbar .tab[active] {
            background-color: #fff;
        }
        #code {
            flex-grow: 1;
            display: block;
            position: relative;
        }
        #code::slotted(*) {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            padding: 5px;
            display: none;
        }
        #code::slotted(*[active]) {
            display: block;
        }
    </style>
    <div id="titlebar">
        <div id="tabbar"></div>
    </div>
    <slot id="code" name="frames"></slot>
</template>
<c-window style="border: 2px solid green; height: 300px;">
    <div slot="frames" name="Content 1">Contents of tab 1</div>
    <div slot="frames" name="Content 2">Contents of tab 2</div>
</c-window>

自定义组件内部有一个插槽,我希望每次添加子元素时都应添加一个选项卡,如果删除了子元素,则应删除与该子元素关联的选项卡。

slotchange 事件不包含有关已添加/删除哪个元素的信息,因此目前,每次调用slotchange 事件时,我都必须循环遍历slot.assignedElements() 并为每个元素创建选项卡。这意味着对于特定的孩子,将创建重复的选项卡,这也可能是 CPU 密集型的。

所以,我在想是否有某种方法可以获取有关已修改元素的信息,以便仅对已修改元素执行操作。有没有办法只获得修改后的元素?如果没有,我可以申请什么方法来实现这一点?

【问题讨论】:

  • 请访问help center,使用tour查看内容和How to Ask。做一些研究,搜索关于SO的相关主题;如果您遇到困难,请发布您尝试的minimal reproducible example,注意输入和预期输出,最好在Stacksnippet
  • 不行,你要根据assignedNodes自己记账;它就像在您处理的节点上设置属性一样简单。您的(提升)var 而不是 letusage 占用更多 CPU 周期。

标签: javascript html custom-component


【解决方案1】:

您正在为 Tabs 使用 oldskool Switch-DIVs 方法

您可以使用 一个 shadowDOM &lt;slot ="active"&gt;

完成所有操作

一个点击处理程序

需要更多的工作;但你得到了slot="active" 的概念

<template id="TABS-MEISTER">
  <style>
    #bar { display:flex }
    #bar div { width: 100px; background: lightgreen ; margin-right:1em ; cursor:pointer}
  </style>
  <div id="bar"></div>
  <div style="clear:both"><slot name="active"></slot></div>
</template>
<tabs-meister>
  <div title="Tab1">Tab #1</div>
  <div slot="active" title="Tab2">Tab #2</div>
  <div title="Tab3">Tab #3</div>
</tabs-meister>
<script>
  customElements.define('tabs-meister', class extends HTMLElement {
    constructor() {
      let template = (id) => document.getElementById(id).content.cloneNode(true);
      super()
        .attachShadow({mode: 'open'})
        .append(template(this.nodeName));
      this.onclick = (evt) => {
        if (this.activetab) this.activetab.removeAttribute("slot");
        let tab = evt.composedPath()[0];
        this.activetab = this.querySelector(`[title="${tab.title}"]`);
        this.activetab.slot = 'active';
      }
    }
    connectedCallback() {
      let tabs = [...this.children].map(node => {
          return `<div title=${node.title}>${node.title}</div>`;
      }).join ``;
      this.shadowRoot.querySelector("#bar").innerHTML = tabs;
    }
  });
</script>

【讨论】:

    猜你喜欢
    • 2019-10-22
    • 2023-02-05
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-18
    相关资源
    最近更新 更多