1

我正在将应用程序从聚合物 1 转换为聚合物 3。我使用了 juicy-html,但它们尚未更新到 Polymer 3,我看到有 lit-html。我想知道如何将此代码段更改为使用 lit-html。它用于扩展字符串,例如:'Hello <span class="highlight">world</span>!'

这是我的聚合物 1 组件中的代码片段。

<template is="dom-repeat" items="[[item.snippets]]">
  <template is="dom-repeat" items="[[item.matches]]">
    <div><template is="juicy-html" content$="[[item.text]]"></template></div>
  </template>
</template>

我需要为内部 div 实现一个新组件吗?有没有我可以看的例子?

这是生成的 Polymer 3 元素,用于在字符串中显示突出显示的文本:

从'@polymer/lit-element/lit-element.js'导入{html,LitElement};

/**
 * `search-snippet-highlight`
 * 
 *
 * @customElement
 * @polymer
 * @demo demo/index.html
 */
class SearchSnippetHighlight extends LitElement {

  static get properties() {
    return {
      snippet: { type: String }
    };
  }

  render() {
    return html`
      <style>.highlight { background-color: yellow; }</style>
      <div .innerHTML="${this.sanitizeHtml(this.snippet)}"></div>`;
  }

  sanitizeHtml(input) {
    return input; // TODO: actually sanitize input with sanitize-html library
  }

}

window.customElements.define('search-snippet-highlight', SearchSnippetHighlight);
4

2 回答 2

1

<template>juicy-htmlPolymer's 中的等效项LitElement(使用 的推荐基本元素lit-html)是:

render() {
  let content = '';
  for (const s of this.item.snippets) {
    for (const m of s.matches) {
      content += `<div>${m.text}</div>`;
    }
  }
  return html`<div .innerHTML="${this.sanitizeHtml(content)}"></div>`;
}

上面的render函数执行以下操作:

  1. 从输入构建一个 HTML 字符串
  2. 清理 HTML
  3. 使用语法 ( )将结果放入容器divinnerHTMLLitElement.PROPERTY="VALUE"

<html>
<head>
  <!-- Polyfills only needed for Firefox and Edge. -->
  <script src="https://unpkg.com/@webcomponents/webcomponentsjs@latest/webcomponents-loader.js"></script>
</head>
<body>
  <!-- Works only on browsers that support Javascript modules like
       Chrome, Safari, Firefox 60, Edge 17 -->
  <script type="module">
    import {LitElement, html} from 'https://unpkg.com/@polymer/lit-element/lit-element.js?module';

    class MyElement extends LitElement {

      static get properties() {
        return {
          item: { type: Object }
        }
      }

      constructor() {
        super();
        this.item = {
          snippets: [
            {
              matches: [
                {text: 'hello <span class="highlight">world</span>'},
                {text: 'we are the <span class="highlight">world</span>'},
                {text: 'war of the <span class="highlight">world</span>s'},
              ]
            },
            {
              matches: [
                {text: 'the <span class="highlight">cat</span> in the hat'},
                {text: '<span class="highlight">cat</span>fish are in the water'},
                {text: '<span class="highlight">cat</span>erpillars become butterflies'},
              ]
            },
          ]
        };
      }

      render() {
        let content = '';
        for (const s of this.item.snippets) {
          for (const m of s.matches) {
            content += `<div>${m.text}</div>`;
          }
        }
        return html`
          <style>.highlight { background: rgb(255, 251, 222); }</style>
          <div .innerHTML="${this.sanitizeHtml(content)}"></div>`;
      }

      sanitizeHtml(input) {
        return input; // TODO: actually sanitize input with sanitize-html library
      }
    }

    customElements.define('my-element', MyElement);
  </script>
  
  <my-element mood="great"></my-element>
  
</body>
</html>

于 2018-09-30T10:51:40.820 回答
0

我把它放在一个答案中,因为@tony19 建议它可以正确格式化。我并不是真的问一个单独的问题,实际上只是问一个修辞问题,而不是提供一个单独的解决方案。

您可以稍微简化该方法,因为 lit 允许您通过该map函数在层中构建 html。

render() {    
    return html`
        <div>${this.item.snippets.map(s => s.matches.map(m => 
                html`<div>${this.sanitizeHtml(m.text)}</div>`
            ))}
       </div>
    `; 
}

现在这个问题(以及公认的答案)是每次渲染都会重新计算整个事情,包括清理 Html。 lit-html有一个guard指令可以帮助解决这个问题。添加它只会在更改时重新渲染。

render() {    
    return html`
        <div>${guard(this.item.snippets, () => this.item.snippets.map(s => 
                 guard(s.matches, () => s.matches.map(m => 
                html`<div>${this.sanitizeHtml(m.text)}</div>`
            ))))}
       </div>
    `; 
}

这确实需要您对两者this.item.snippets和底层的matches更新方式施加一些纪律。您必须确保在有更新时使用的“数组”引用发生变化。像这样的东西(假设正在使用新匹配更新匹配)并且sindexsnippet您要更新的索引,并且是您要更新的内部mindex索引;matchsnippetnewMatch

this.items.snippets = this.items.snippets.map((snippet, index) => index === sindex ?
   {...snippet, matches: snippet.matches.map((match, index) => index === mindex ?
      newMatch : match)} : snippet);
于 2018-10-26T11:38:45.403 回答