LitElement(二)模板編寫基本語法


原文:https://lit-element.polymer-project.org/guide/templates

1、定義一個渲染模板

1.1 基本規則

要用LitElement 組件定義一個模板,必須為你的模板類寫一個render方法:

import { LitElement, html } from 'lit-element';

class MyElement extends LitElement {
  render() {
    return html`<p>template content</p>`;
  }
}

這里 html`...` 中 html 是引用的父類函數,用模板字符串包裹原始的HTML標簽

組件的 render 方法可以返回 lit-html 可以渲染的任何內容。通常,它返回單個 TemplateResult 對象(與 html 標記函數返回的類型相同)。

完整的例子

import { LitElement, html } from 'lit-element';

class MyElement extends LitElement {

  // Implement `render` to define a template for your element.
  render(){
    /**
     * Return a lit-html `TemplateResult`.
     *
     * To create a `TemplateResult`, tag a JavaScript template literal
     * with the `html` helper function.
     */
    return html`
      <div>
        <p>A paragraph</p>
      </div>
    `;
  }
}
customElements.define('my-element', MyElement);

1.2 動態更改模板內容

我們可以通過捕獲加載消息作為屬性,並根據事件設置屬性來改變模板:update-properties.js

import { LitElement, html } from 'lit-element';

/**
 * Use this pattern instead.
 */
class UpdateProperties extends LitElement {
  static get properties(){
    return {
      message: String
    };
  }
  constructor() {
    super();
    this.message = 'Loading';
    this.addEventListener('stuff-loaded', (e) => { this.message = e.detail } );
    this.loadStuff();
  }
  render() {
    return html`
      <p>${this.message}</p>
    `;
  }
  loadStuff() {
    setInterval(() => {
      let loaded = new CustomEvent('stuff-loaded', {
        detail: 'Loading complete.'
      });
      this.dispatchEvent(loaded);
    }, 3000);
  }
}

customElements.define('update-properties', UpdateProperties);

該例子中為模板元素綁定了一個加載事件,事件函數模擬3秒后改變元素屬性值,從而動態改變模板。這是動態改變模板的方法。

注意:每一個模板類都必須引用  import { html, LitElement } from 'lit-element'; 就算套用了其他模板也是一樣

2、在模板中使用屬性、循環和條件判斷

2.1 屬性

static get properties() {
  return { myProp: String };
}
...
render() {
  return html`<p>${this.myProp}</p>`;
}

通過靜態的 get properties() 函數指定屬性的類型, 構造函數 constructor() 初始化屬性的初始值

2.2 循環

html`<ul>
  ${this.myArray.map(i => html`<li>${i}</li>`)}
</ul>`;

ES6數組的map方法,為每一個數組元素執行括號中的操作

2.3 三目運算符

html`
  ${this.myBool?
    html`<p>Render some HTML if myBool is true</p>`:
    html`<p>Render some other HTML if myBool is false</p>`}
`;

完整的例子

import { LitElement, html } from 'lit-element';

class MyElement extends LitElement {
  static get properties() {
    return {
      myString: { type: String },
      myArray: { type: Array },
      myBool: { type: Boolean }
    };
  }
  constructor() {
    super();
    this.myString = 'Hello World';
    this.myArray = ['an','array','of','test','data'];
    this.myBool = true;
  }
  render() {
    return html`
      <p>${this.myString}</p>
      <ul>
        ${this.myArray.map(i => html`<li>${i}</li>`)}
      </ul>
      ${this.myBool?
        html`<p>Render some HTML if myBool is true</p>`:
        html`<p>Render some other HTML if myBool is false</p>`}
    `;
  }
}

customElements.define('my-element', MyElement);

一個包含了 get properties(), constructor(), render() 方法的模板

3、給模板元素綁定屬性值

您可以插入JavaScript表達式作為HTML文本內容,基本屬性,布爾屬性,元素屬性和事件處理器的占位符。

  • Text content: <p>${...}</p>
  • Attribute: <p id="${...}"></p>
  • Boolean attribute: ?disabled="${...}"
  • Property: .value="${...}"
  • Event handler: @event="${...}"

3.1 綁定到正文

html`<div>${this.prop1}</div>`

3.2 綁定到基本屬性

html`<div id="${this.prop2}"></div>`

3.3 綁定到布爾類型屬性

html`<input type="text" ?disabled="${this.prop3}">`

3.4 綁定到元素屬性

html`<input type="checkbox" .value="${this.prop4}"/>`

3.5 綁定到事件處理程序

html`<button @click="${this.clickHandler}">pie?</button>`

完整的例子

import { LitElement, html } from 'lit-element';

class MyElement extends LitElement {
  static get properties() {
    return {
      prop1: String,
      prop2: String,
      prop3: Boolean,
      prop4: String
    };
  }
  constructor() {
    super();
    this.prop1 = 'text binding';
    this.prop2 = 'mydiv';
    this.prop3 = true;
    this.prop4 = 'pie';
  }
  render() {
    return html`
      <!-- text binding -->
      <div>${this.prop1}</div>

      <!-- attribute binding -->
      <div id="${this.prop2}">attribute binding</div>

      <!-- boolean attribute binding -->
      <div>
        boolean attribute binding
        <input type="text" ?disabled="${this.prop3}"/>
      </div>

      <!-- property binding -->
      <div>
        property binding
        <input type="text" .value="${this.prop4}"/>
      </div>

      <!-- event handler binding -->
      <div>event handler binding
        <button @click="${this.clickHandler}">click</button>
      </div>
    `;
  }
  clickHandler(e) {
    console.log(e.target);
  }
}

customElements.define('my-element', MyElement);

4、使用slot占位符給模板元素渲染子節點

4.1 slot標簽

要實現如下形式的渲染,必須通過slot占位符標簽實現

<my-element>
  <p>A child</p>
</my-element>

默認情況下,如果元素具有陰影樹,則其子元素根本不會渲染。

要渲染子節點,您的模板需要包含一個或多個<slot>元素,這些元素充當子節點的占位符。

例如定義如下形式的模板

render(){
  return html`
    <div>
      <slot></slot>
    </div>
  `;
}

就可以在 <slot> 標簽的位置渲染子節點

<my-element>
  <p>Render me</p>
</my-element>

這些子項不會在DOM樹中移動,但會像它們是<slot>的子項一樣呈現。

任意多個子節點可以填充到一個slot

<my-element>
  <p>Render me</p>
  <p>Me too</p>
  <p>Me three</p>
</my-element>

4.2 使用命名的slot

要將子節點分配給特定的 slot ,請確保該子節點的 slot 屬性與該 slot name 屬性匹配:

render(){
  return html`
    <div>
      <slot name="one"></slot>
    </div>
  `;
}
<my-element>
  <p slot="one">Include me in slot "one".</p>
</my-element>

命名 slot 僅接受具有匹配 slot 屬性的子節點。

例如:

import { LitElement, html } from 'lit-element';

class MyElement extends LitElement {
  render(){
    return html`
      <div>
        <slot name="one"></slot>
        <slot name="two"></slot>
      </div>
    `;
  }
}
customElements.define('my-element', MyElement);

one對one,two對two,沒有名字的不會被渲染

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
  <script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
  
  <script type="module" src="./my-element.js"></script>
  <title>lit-element code sample</title>
</head>
<body>
    <!-- Assign child to a specific slot -->

    <my-element>
      <p slot="two">Include me in slot "two".</p>
    </my-element>

    <!-- 
      Named slots only accept children with a matching `slot` attribute. 
      
      Children with a `slot` attribute can only go into a slot with a matching name. 
    -->

    <my-element>
      <p slot="one">Include me in slot "one".</p>
      <p slot="nope">This one will not render at all.</p>
      <p>No default slot, so this one won't render either.</p>
    </my-element>
</body>
</html>

5、多個模板組合成頁面

您可以從其他LitElement模板組成新的LitElement模板。在以下示例中,我們通過導入其他元素並在模板中使用它們來組成新的<my-page>模板:

my-article.js

import { LitElement, html } from 'lit-element';

class MyArticle extends LitElement {
    render() {
        return html`
        <article>article</article>
        `;
    }
}
customElements.define('my-article', MyArticle);

my-header.js

import { html, LitElement } from 'lit-element';

class MyHeader extends LitElement {
    render() {
        return html`
        ${this.headerTemplate}
      `;
    }
    get headerTemplate() {
        return html`<header>header</header>`;
    }
}
customElements.define('my-header', MyHeader);

my-footer.js

import { LitElement, html } from 'lit-element';

class MyFooter extends LitElement {
    render() {
        return html`
        <footer>footer</footer>
        `;
    }
}
customElements.define('my-footer', MyFooter);

用以上三個子模版元素組成頁面元素my-page.js

import { LitElement, html } from 'lit-element';

import './my-header.js';
import './my-article.js';
import './my-footer.js';

class MyPage extends LitElement {
    render() {
        return html`
        <my-header></my-header>
        <my-article></my-article>
        <my-footer></my-footer>
    `;
    }
}
customElements.define('my-page', MyPage);

然后配一個 模板元素整合文件,例如 mian.js

import './my-page.js';

在頁面 my-page.html中引用這個文件

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>lit-element code sample</title>
    <script src="main.js"></script>
</head>

<body>
    <my-page></my-page>
    <script src="webcomponents-loader.js"></script>
</body>

</html>

此時可能有 index.html, my-page.html兩個頁面, index.js, main.js兩個腳本文件,需要同時打包輸出,修改rollup,config.js文件,以數組形式輸出多個js文件

import resolve from 'rollup-plugin-node-resolve';
import babel from 'rollup-plugin-babel';

export default [{
    input: ['src/index.js'],
    output: {
        file: 'build/index.js',
    format: 'es',
        sourcemap: true
    },
    plugins: [
    resolve(),
    babel()
  ],
},{
    input: ['src/main.js'],
      output: {
          file: 'build/main.js',
      format: 'es',
          sourcemap: true
      },
      plugins: [
      resolve(),
      babel()
    ]
}];

修改package.json中的html打包命令

"scripts": {
    "copyindex": "cp src/*.html build",
    "copywc": "cp -r node_modules/@webcomponents/webcomponentsjs/bundles build && cp node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js build",
    "build": "rm -rf build && mkdir build && npm run copyindex && npm run copywc && rollup -c",
    "start": "serve build"
  },

就可以在build下生成兩個html文件及其對應的js文件了,其他同理可得

6、 lit-html

 lit-html作為LitElement的核心,可以使用很多它的其他功能

npm i lit-element@^2.0.0
npm i lit-html@^1.0.0

例如:

import { LitElement, html } from 'lit-element';
import { until } from 'lit-html/directives/until.js';

const content = fetch('./content.txt').then(r => r.text());

html`${until(content, html`<span>Loading...</span>`)}`

讀取一個文件內容作為渲染內容

其他詳見文檔:https://lit-html.polymer-project.org/guide/template-reference#built-in-directives


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM