如何将插槽子项附加到 HTML body 标记以进行绝对定位? [英] How to append slot children to HTML body tag for absolute positioning?

查看:27
本文介绍了如何将插槽子项附加到 HTML body 标记以进行绝对定位?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个下拉菜单 Web 组件,供消费者使用,例如:

<自定义菜单锚点><button>切换菜单</button></custom-menu-anchor><custom-menu-item>鱼</custom-menu-item><自定义菜单项><custom-icon name="鸡"/><span>鸡</span></custom-menu-item></自定义菜单>

这里,像 这样的槽项需要绝对定位.

要做到这一点,我们需要

  1. 创建叠加层
  2. 从 Web 组件中删除插槽元素
  3. 将它们附加到覆盖元素.
  4. 提供正确的定位

要设置完美的叠加层,我需要创建一个 overlay/surface 元素并删除 custom-menu-item 子项并将它们全部附加到叠加层元素.

为了实现这一点,我在 connectedCallback 生命周期方法中尝试了以下类似的方法:

const slot = this.shadowRoot.querySelector('slot');const surface = document.createElement('div');const 节点 = slot.assignedNodes();surface.append(...nodes);document.body.appendChild(surface);

这种方法的问题:

  • 我注意到从插槽中删除 assignedNodes 会搞砸很多事情.
  • 当我尝试移动插槽的 lightDOM
  • 时,许多事情都不起作用
  • slotchange 在元素移动后不起作用.
  • 此外,Web 组件可以在任何框架中使用,可以是 lit-htmlVue 甚至普通的 JavaScript.我注意到在移动这些 DOM 元素后,这开始破坏消费者库的抽象.

这种需求适用于任何绝对定位/偏移的组件,如通知、对话框、下拉菜单、Snackbar 和上述方法显然很困难,当然也不是一种更简洁的做事方式.

我们如何才能更有效地避免所有提到的副作用?

解决方案

四处移动轻量 dom 节点通常不是一个好主意 - 您的用户(和浏览器)希望它们停留在原地.

如果您想在其他地方呈现内容,您可以将内容作为属性提供.

lit-html 的简化示例(使用它通过 . 设置属性)

我的内容

'}>

然后在您的自定义元素中,您需要对尚未在 dom 中的那个字符串做一些事情.

class MyEl 扩展 ... {onContentChanged() {document.body.querySelector('my-el-target').innerHTML = this.content;}}

PS:这过于简单化了——实际上你可能想在 connectedCallback 上创建/管理 my-el-target——或者让它由一个完整的控制器处理.此外,模板"可能应该是一个点亮的模板而不是一个普通的字符串......

I am creating a dropdown menu web component that will be used by consumers like:

<custom-menu>
    <custom-menu-anchor>
        <button>Toggle Menu</button>
    </custom-menu-anchor>

    <custom-menu-item>Fish</custom-menu-item>
    <custom-menu-item>
        <custom-icon name="chicken"/>
        <span>Chicken</span>
    </custom-menu-item>
</custom-menu>

Here, the slot items like <custom-menu-items> need to be absolutely positioned.

To do this, we need to

  1. Create an overlay
  2. Remove slot elements from web component
  3. Attach them to the overlay element.
  4. Provide correct positioning

To setup a perfect overlay, I need to create an overlay/surface element and remove the custom-menu-item children and append them all to the overlay element.

To achieve this, I attempted something like below in connectedCallback lifecycle method:

const slot = this.shadowRoot.querySelector('slot');
const surface = document.createElement('div');

const nodes = slot.assignedNodes();

surface.append(...nodes);
document.body.appendChild(surface);

Problems with this approach:

  • I noticed that removing the assignedNodes from slot messes up many things.
  • Many things do not work when I attempt to move slot's lightDOM
  • slotchange doesn't work once the elements are moved.
  • Further, web component could be used in any framework, It could be lit-html, Vue or even plain JavaScript. I noticed that this starts breaking abstractions of the consumer libraries after moving these DOM elements.

This need applies to any absolutely positioned/offset components like notification, dialog, dropdown, Snackbar and the above approach clearly struggles and is certainly not a cleaner way to do things.

How can we do this in a more effective manner avoiding all the mentioned side effects ?

解决方案

Moving light dom nodes around is usually not a good idea - your users (and the browser) expects them to stay where they are.

If you want to render the content somewhere else you could provide the content as an attribute.

A simplified example for lit-html (using it to set a property via .)

<my-el .content=${'<div>my content</div>'}></my-el>

Then in your custom element, you will need to do something with that string which is not yet in the dom.

class MyEl extends ... {
  onContentChanged() {
    document.body.querySelector('my-el-target').innerHTML = this.content;
  }
}

PS: this is highly oversimplified - in real you probably want to create/manage that my-el-target on connectedCallback - or let it be handled by a full controller. Also, the "template" probably should be a lit-template instead of a plain string...

这篇关于如何将插槽子项附加到 HTML body 标记以进行绝对定位?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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