简体   繁体   English

防止在 lit-html/lit-element 中重用 DOM

[英]Prevent DOM reuse within lit-html/lit-element

I am looking for a way to NOT reuse DOM elements within lit-html/lit-element (yes, I know, I'm turning off one of the prime features).我正在寻找一种不在 lit-html/lit-element 中重用 DOM 元素的方法(是的,我知道,我正在关闭其中一个主要功能)。 The particular scenario is moving an existing system to lit-element/lit-html that at certain points embeds the trumbowyg WYSIWYG editor.特定场景是将现有系统移动到 lit-element/lit-html,该系统在某些点嵌入了 trumbowyg WYSIWYG 编辑器。 This editor attaches itself to a <div> tag made within lit-element and modifies its own internal DOM, but of course lit-html does not know that this has happened, so it will often reuse the same <div> tag instead of creating a new one.这个编辑器将自己附加到一个在 lit-element 中创建的<div>标签并修改它自己的内部 DOM,但当然 lit-html 不知道这已经发生了,所以它通常会重用相同的<div>标签而不是创建一个新的。 I am looking for something similar to the vue.js key attribute (eg, preventing Vue from aggresively reusing dom-elements )我正在寻找类似于vue.js关键属性的东西(例如, 防止 Vue 积极重用 dom-elements

I feel like the live() directive in lit-html should be useful for this, but that guards against reuse based on a given attribute, and I want to prevent reuse even if all attributes are identical.我觉得lit-html中的live()指令应该对此有用,但它可以防止基于给定属性的重用,即使所有属性都相同,我也想防止重用。 Thanks!谢谢!

I have had similar issues with rich text editors and contenteditable - due to how templates update the DOM you don't want that to be part of a template.我在富文本编辑器和contenteditable方面遇到过类似的问题——由于模板如何更新 DOM,您不希望它成为模板的一部分。

You do this by adding a new element with the non-Lit DOM and then adding that to the DOM that Lit does manage:为此,您可以使用非 Lit DOM 添加一个新元素,然后将添加到 Lit 管理的 DOM:

class TrumbowygEditor
  extends HTMLElement {

  constructor() {
    super();
    const shadow = this.attachShadow({mode: 'open'});
    const div = document.createElement('div');
    shadow.appendChild(div);
    
    const style = document.createElement('style');
    // Add CSS required 
    shadow.appendChild(style);

    $(div).trumbowyg(); //init
  }
}

customElements.define('trumbowyg-editor', TrumbowygEditor);

As this is running in a custom element's shadow DOM Lit won't touch it, you can do:由于这是在自定义元素的阴影 DOM 中运行,因此 Lit 不会触及它,您可以执行以下操作:

html`
    <div>Lit managed DOM</div>
    <trumbowyg-editor></trumbowyg-editor>`;

However, you will have to implement properties and events on TrumbowygEditor to add everything you want to pass to or get from the nested jQuery component.但是,您必须在TrumbowygEditor上实现属性和事件,以添加您想要传递到嵌套 jQuery 组件或从中获取的所有内容。

You can add the scripts with import if you can get module versions of jQuery/Trumbowyg (or your build tools support it) or you can add <script> tags to your component, add fallback loading DOM content in the constructor , and then on the load event of the <script> call the $(div).trumbowyg() to init the component.如果您可以获得 jQuery/Trumbowyg 的模块版本(或您的构建工具支持它),您可以通过import添加脚本,或者您可以将<script>标签添加到您的组件,在constructor中添加后备加载 DOM 内容,然后在<script>的加载事件调用$(div).trumbowyg()来初始化组件。

While messier and more work I'd recommend the latter as both components are large and (thanks to jQuery being built on assumptions that are now 15 years old) need to load synchronously ( <script async or <script defer don't work).虽然更混乱和更多的工作我推荐后者,因为这两个组件都很大并且(感谢 jQuery 建立在现在已经 15 年的假设之上)需要同步加载( <script async<script defer不起作用)。 Especially on slower connections Lit will be ready long before jQuery/Trumbowyg have loaded in, so you want <trumbowyg-editor> to look good (show spinner, layout in the right amount of space etc) while that's happening.特别是在较慢的连接上 Lit 会在 jQuery/Trumbowyg 加载之前很久就准备好了,所以你希望<trumbowyg-editor>在发生这种情况时看起来不错(显示微调器,在适当的空间量中布局等)。

You write that you attach the external library directly to an element managed by lit-html.您写道,您将外部库直接附加到由 lit-html 管理的元素。 It sounds like you're doing essentially this:听起来你基本上是在这样做:

render(html`<section><div id=target></div></section>`, document.body)
external_lib.render_to(document.querySelector("#target"))

If this is what you do instead try to create your own div, let the external lib render to that div, and finally attach that div to lit-html:如果这是您所做的,请尝试创建自己的 div,让外部 lib 渲染到该 div,最后将该 div 附加到 lit-html:

let target_div = document.createElement('div')
render(html`<section>${div}</section>`, document.body)
external_lib.render_to(target_div)

The most up-to-date answer to this problem is to use Lit's built-in keyed directive.这个问题的最新答案是使用 Lit 的内置keyed指令。 This scenario is exactly what it's for:这个场景正是它的用途:

https://lit.dev/docs/templates/directives/#keyed https://lit.dev/docs/templates/directives/#keyed

Associates a renderable value with a unique key.将可渲染值与唯一键相关联。 When the key changes, the previous DOM is removed and disposed before rendering the next value, even if the value—such as a template—is the same.当 key 改变时,之前的 DOM 会在渲染下一个值之前被移除和处理,即使值(例如模板)是相同的。

@customElement('my-element')
class MyElement extends LitElement {

  @property()
  userId: string = '';

  render() {
    return html`
      <div>
        ${keyed(this.userId, html`<user-card .userId=${this.userId}></user-card>`)}
      </div>`;
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM