Lit-Element - 如何从外部文本渲染模板?

Lit-Element - How to render template from an external text?

提问人:megloff 提问时间:5/19/2023 最后编辑:megloff 更新时间:5/27/2023 访问量:187

问:

我有一个从外部服务接收的字符串,其中包含 HTML 模板和一些需要由 render 函数动态计算的表达式。如何使用 Lit 做到这一点?我尝试了 and and with,但我的字符串中的表达式没有得到计算并保留为文本。unsafeHTML()unsafeStatic()${new Date()}

...
import {unsafeStatic, html} from 'lit/static-html.js';
import {unsafeHTML} from 'lit-html/directives/unsafe-html.js';

@customElement('my-component')
export class MyComponent extends LitElement {

    templ = "<div>${new Date()}</div>";

    render() {
        return html`${unsafeHTML(this.templ)}`;
    }

    // OR

    render() {
        return html`${unsafeStatic(this.templ)}`;
    }  

}

输出被评估为文本:“${new Date()}”,而不是当前日期,如“19.05.2023”

JavaScript 模板 eval web-component lit

评论


答:

0赞 megloff 5/19/2023 #1

我通过使用函数和嵌套指令找到了解决方案。也许有人有更好的解决方案?eval()html

import {html} from "lit";
import { customElement, state} from "lit/decorators.js";

@customElement('my-component')
export class MyComponent extends LitElement {

    @state()
    templ = "<div>${new Date()}</div>";

    render() {
        // output as static text, template content not evaluated
        console.log(this.templ);
        // render the template content
        return html`${eval("html`"+this.templ+"`")}`;
    }
}

这也适用于更高级的结构,如下所示。因此,您可以从外部服务检索模板,并使用您准备的数据进行评估。希望这也有助于其他可能有类似要求的人。templ

@customElement('my-component')
export class MyComponent extends LitElement {

    // produce an array with mixed elements which some of these need to be evaluated
    data = [`${new Date()}`, `${1 + 1}`, "text"];
    
    // create a template as string which later get evaluated
    @state()
    templ : any;
        
    connectedCallback() {
        super.connectedCallback();
            
           // receive the template content from an external service
           (async() => {
            await fetch("template.html")
            .then(response => response.text())
            .then(text => {
                this.templ = text;
            });
        })();

    render() {
        console.log(this.templ);
        return html`${eval("html`"+this.templ+"`")}`;
    }
    
}

“模板.html”的内容

<div>${this.data.map(item => html`<li>${item}</li>`)}</div>

这会产生类似这样的东西

<div>
    <li>>Fri May 19 2023 17:09:42 GMT+0200 (Central European Summer Time)</li>
    <li>2</li>
    <li>text</li>
</div>
1赞 Brendan Baldwin 5/27/2023 #2

如果您的服务器能够在 javascript 模块响应中返回模板,则可以从该文件导入模板函数,然后使用它来生成所需的内容。例如,您的服务器可以通过动态 :import(requestURL)

export template = (html, data) => html`<div>${new Date()}</div>
<ul>${data.items.map((i) => html`<li>${i}`}</ul>`;

我想在某些方面,这是一种 eval(),除了它确保一切都遵守相同的安全级别和基本规则。动态返回的模块内容具有许多有趣的优点和额外的陷阱。

我不确定您需要动态返回模板的原因是否源于其中包含模板的 CMS,或者更像是服务器端渲染和客户端的混合体,但动态导入显然只从 URL 的 http GET 请求返回,如果您需要将请求中的一堆数据直接捆绑到模块中,您将无法使用这种方法。