gpt4 book ai didi

javascript - shadow DOM 和 light DOM 应该放哪些部分?

转载 作者:数据小太阳 更新时间:2023-10-29 05:49:08 26 4
gpt4 key购买 nike

我正在学习网络组件。在设计自定义元素时,我必须决定将什么隐藏在影子 DOM 中。其余部分将暴露在轻型 DOM 中。

据我所知,这些 API 允许两种具有不同权衡的极端用例:

  • 在 shadow DOM 中几乎不隐藏任何内容,元素的大部分内容都在 light DOM 和元素的属性中:
    • 这允许 HTML 作者在不编写 JS 的情况下为组件提供任何显示内容;
    • 这在可搜索性和可访问性方面接近现状
    • 但所涉及的工作几乎没有返回;我用组件增加了复杂性,但它们不封装任何东西(一切都暴露了)。
  • 隐藏影子 DOM 中的几乎所有内容,元素的 innerHTML 为空:
    • 这需要从 JS 实例化元素;
    • 这会更多地锁定使用,因为从 JS 实例化比使用 HTML 槽和属性更严格(类型方面);
    • 这可能不太容易搜索和访问(我不确定是否属于这种情况);

我目前倾向于将所有内容隐藏在影子 DOM 中,原因如下:

  • 我打算从 JS 实例化所有内容。我不会手动编写 HTML 页面。同时编写 HTML API 和 JS API 的代码工作量更大。
  • 隐藏所有内容的认知工作较少。我不需要在轻型 DOM 中可见哪些信息之间找到合适的平衡点。
  • 它更接近我熟悉的大多数 JS 框架。

我错过了什么吗?


编辑

谢谢,有人回答说这取决于部分回答我问题的用例。但对于我所处的情况,我仍然缺少答案:我宁愿不支持我的某些组件的插槽。

我将为频谱的每个极端添加一个示例:

  • Light-DOM-heavy 组件:组件用户必须将元素插入插槽

    <template id=light-email-view>
    <div>
    <div><slot name=from></slot></div>
    <ul><slot name=to></slot></ul>
    <h1><slot name=subject></slot></h1>
    <div><slot name=content></slot></div>
    <ul><slot name=attachements></slot></ul>
    <div class=zero-attachment-fallback>no attachments</div>
    </div>
    </template>

  • Shadow-DOM-heavy 组件:组件用户必须使用 JS API

    <template id=shadow-email-view>
    <div></div>
    </template>
    <script>
    ...
    let view = document.createElement('shadow-email-view');
    // this method renders the email in the shadow DOM entirely
    view.renderFromOject(email);
    container.appendChild(view);
    </script>

    在第一个示例中,组件作者有更多工作要做,因为他们需要“解析”DOM:他们必须计算附件数量以切换回退;基本上,任何不是浏览器将元素从 light DOM 复制到匹配的 shadow DOM 槽中的输入转换。然后他们需要监听属性变化等等。组件用户还有更多工作,他们必须将正确的元素插入正确的位置,其中一些非常重要(电子邮件内容可能需要链接)。

    在第二个示例中,组件作者不需要实现对从带有槽的 HTML 进行实例化的支持。但是组件用户必须从 JS 实例化。 All 渲染由组件作者在.renderFromObject 方法中完成。一些额外的方法提供了钩子(Hook)来在需要时更新 View 。

    可以通过让组件提供插槽和 JS 助手来填充这些插槽来提倡中间立场。但如果该组件不被 HTML 作者使用,我看不出有什么意义,还有更多工作要做。

    因此,将所有带有影子 DOM 的东西都放在可行的位置还是应该 我提供插槽,因为不这样做不符合标准,并且我的代码会在一些期待它们的用户代理上中断(忽略旧的完全不了解自定义元素的 UA)?

  • 最佳答案

    @supersharp 搞定了。

    我在 Web 组件中看到的一件事是,人们倾向于让他们的组件做太多事情,而不是分解成更小的组件。

    让我们考虑一些原生元素:

    <form>没有影子 DOM,它唯一做的就是从它的子表单元素中读取值,以便能够执行 HTTP GET、POST 等。

    <video> 100% shadowDOM,它使用应用程序提供的子项的唯一目的是定义要播放的视频。用户无法为 <video> 的影子子级调整 任何 CSS标签。他们也不应该被允许。唯一的<video>标签允许隐藏或显示那些影子子项的能力。 <audio>标签做同样的事情。

    <h1><h6>没有阴影。所有这一切都是设置默认字体大小并显示子项。

    <img>标记使用影子子项来显示图像和替代文本。

    就像@supersharp 所说的那样,shadowDOM 的使用是基于元素的。我想进一步说 shadowDOM 应该是一个深思熟虑的选择。我要补充一点,您需要记住,这些应该是组件而不是应用程序。

    是的,您可以将整个应用程序封装到一个组件中,但浏览器并没有尝试使用 Native 组件来做到这一点。您可以使组件越特化,它们的可重用性就越高。

    避免将 任何 添加到您的 Web 组件中,而不是 vanilla JS,换句话说,不要将任何框架代码添加到您的组件中,除非您不想与不使用它的人共享它们框架。我写的组件是 100% Vanilla JS,没有 CSS 框架。它们在 Angular、React 和 vue 中使用,没有更改代码。

    但是为每个编写的组件选择了使用 shadowDOM。而且,如果您必须在本身不支持 Web 组件的浏览器中工作,您可能根本不想使用 shadowDOM。

    最后一件事。如果您编写的组件不使用 shadowDOM 但它具有 CSS,那么您必须小心放置 CSS 的位置,因为您的组件可能会被放置到其他人的 shadowDOM 中。如果您的 CSS 放在 <head> 中标记,那么它将在另一个 shadowDOM 中失败。我使用此代码来防止该问题:

    function setCss(el, styleEl) {
    let comp = (styleEl instanceof DocumentFragment ? styleEl.querySelector('style') : styleEl).getAttribute('component');
    if (!comp) {
    throw new Error('Your `<style>` tag must set the attribute `component` to the component name. (Like: `<style component="my-element">`)');
    }

    let doc = document.head; // If shadow DOM isn't supported place the CSS in `<head>`
    // istanbul ignore else
    if (el.getRootNode) {
    doc = el.getRootNode();
    // istanbul ignore else
    if (doc === document) {
    doc = document.head;
    }
    }

    // istanbul ignore else
    if (!doc.querySelector(`style[component="${comp}"]`)) {
    doc.appendChild(styleEl.cloneNode(true));
    }
    }

    export default setCss;

    关于javascript - shadow DOM 和 light DOM 应该放哪些部分?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54300456/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com