JavaScript Library – Lit
前言
我写过一篇关于 Lit 的文章,Material Design, Angular Material, MDC, MWC, Lit 的关系。
如今 material-web MWC 已经发布 1.0 了,估计 Angular 也会在不远的将来从 material-components-web MDC 迁移到 MWC。
以后,我们要想深入理解 Angular Material 就必须对 MWC 有一定了解,而 MWC 又是基于 Lit 开发的,所以我们也需要了解 Lit。
这篇就让我们来看看 Lit 吧。
参考
Lit 介绍
Lit 的前生是 Google 的 Polymer。它是一个帮助我们写标准 Web Components 的库。
它有 2 个特点:
- 标准 W3C Web Components
Lit 开发出来的组件是 W3C 规范的 Web Components,不像 Angular、React、Vue 那些都是仿冒的。
符合标准的好处是可以 Plug and Play,组件本身不依赖框架技术。
我用 Lit 写出来的组件,可以拿到 Angular、React、Vue 任何项目里跑。 - 提升开发体验
在不借助任何库的情况下,手写 W3C Web Components 开发体验是很差的,代码可读性也差。
Lit 主要就是为了解决这些问题而诞生的。
它借助 Decorator 和 Template literals 特性,实现了声明式定义组件和 MVVM。
Lit Getting Started
Lit 的目的是开发出 W3C Web Components,所以要掌握 Lit 就必须先掌握 W3C Web Components。
不熟悉的朋友们,请先看我以前写的这篇 DOM – Web Components。
安装
Lit 是可以用在纯 HTML、CSS、JS 上的,但是会降低开发体验。所以我还是鼓励大家用 TypeScript。
我这里搭配 Vite 做演示,你想改用 Webpack 或 Rollup 也都可以。
yarn create vite

它默认会有一些 sample code,我们洗掉它,从一个干净的开始。

index.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
index.ts 清空
index.html
<!doctype html>
<html lang="en"> <head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Lit + TS</title>
<link rel="stylesheet" href="./src/index.css" />
<script type="module" src="/src/index.ts"></script>
</head> <body>
</body> </html>
创建组件
Web Components 是由 HTML Templates、Shadow DOM、Custom Elements 三种独立的技术搭配而成的。
而 Lit 把它们组合在一起了。
hello-world.ts
import { LitElement, css, html } from 'lit';
import { customElement } from 'lit/decorators.js';
// 定义组件
// 取代了 window.customElements.define('hello-world', HelloWorldElement);
@customElement('hello-world')
export class HelloWorldElement extends LitElement {
// 取代了 <template>
render() {
return html`<h1>Hello World</h1>`;
}
// 取代了 <style>
static styles = css`
h1 {
color: red;
}
`;
}
// declare type for TypeScript
declare global {
interface HTMLElementTagNameMap {
'hello-world': HelloWorldElement;
}
}
HTML 和 CSS 用了 Template literals 技术。它不像 Angular 搞 compiler 黑魔法,这个只是单纯的 JS runtime render。
Tips: template literals 对 IDE 不友好,需要插件 lit-html 和 vscode-styled-components。
使用组件
index.ts
import './hello-world';
setTimeout(() => {
// 动态使用
const helloWorld = document.createElement('hello-world');
document.body.appendChild(helloWorld);
}, 3000);
记得要 import 先。
index.html
<body>
<!-- 静态使用 -->
<hello-world></hello-world>
</body>
效果


Lit の Shadow DOM
所有原生 Shadow DOM 的特性,在 Lit 都可以用。
比如::host、<slot>、::slotted()、::part()。
除了 :host-context(),相关提问:Stack Overflow – :host-context not working as expected in Lit-Element web component
主要是因为 Firefox 和 Safari 本来就不支持 :host-context 所以 Lit 干脆就完全不支持了。可以使用 CSS Variables 作为替代方案。
从这里也能看出,Lit 实现 Web Components 的手法我们直觉认为的不太一样,它里面动了一些手脚。
Lit の Custom Elements
所有原生 Custom Elements 的特性,在 Lit 都可以用。
比如 lifecycle:connectedCallback、disconnectedCallback、attributeChangedCallback、static get observedAttributes。
Lit の MVVM
到目前为止,我们看到的 @customElement、extends LitElement、html``、css`` 只是 Lit 的小角色。
真正让 Lit 发亮起来的是它的 MVVM,这也是 W3C Web Components 最缺失的功能。
MVVM 的中心思想
MVVM 的宗旨就是不要直接操作 DOM,不要调用 DOM API,凡事都通过 MVVM 库去控制。
Lit 提供了很多种 binding、listening、query 的方式去取代 DOM 操作。
binding & listening
@customElement('hello-world')
export class HelloWorldElement extends LitElement {
@state()
private value = 'default value';
private updateValue() {
this.value = 'new value';
}
render() {
return html`
<h1>${this.value}</h1>
<button @click="${this.updateValue}">update value</button>
`;
}
static styles = css``;
}
效果

如果你熟悉 Angular,那应该对 Lit 的语法不会感到太陌生。它俩其实挺像的。毕竟都是 Google 出品,师出同门嘛。
我们逐个来看

有一个 value 属性,@state() 表示这个属性会被用于模板。这时 Lit 就知道每当这个属性值发生变化,那就需要 re-render(它具体如何实现重渲染我不清楚,估计不会是大面积的替换,应该会做性能优化)

有一个 updateValue 方法,调用它就更新 value 属性。

把 value 属性插入模板。

@click 是一个特殊字符串,表示监听 click 事件,接着把 updateValue 方法插入模板。
至此,Lit 就掌握足够信息,可以做监听和 update DOM 了。
Attribute & Property
@state 和 @property 的区别是,一个是 private 一个是 public。
@customElement('hello-world')
export class HelloWorldElement extends LitElement {
@property({ type: Number, attribute: 'number-value' })
numberValue!: number;
@property({ type: Boolean, attribute: 'bool-value' })
boolValue = false;
render() {
return html` <h1>${this.numberValue.toFixed(4)}</h1>
<h1>${this.boolValue}</h1>`;
}
static styles = css``;
}
外部 HTML 控制
<hello-world number-value="50" bool-value></hello-world>
外部 JS 操控
document.querySelector('hello-world')!.numberValue = 50;
document.querySelector('hello-world')!.boolValue = false;
Dispatch Event
@customElement('hello-world')
export class HelloWorldElement extends LitElement {
private handleClick() {
this.dispatchEvent(new CustomEvent('clickhelloworld', { bubbles: true }));
}
render() {
return html`<h1 @click="${this.handleClick}">Hello World</h1>`;
}
static styles = css``;
}
外部监听
document.body.addEventListener('clickhelloworld', e => {
console.log('clicked', e.target); // <hello-world>
});
注:组件 this.dispatchEvent 的这个 this 只的是 <hello-world> 这个 element。所以 event 不需要设置 composed。
用 Lit 重写 Counter Component
在 DOM – Web Components 文章的结尾,我写了一个 Counter Component,我们现在用 Lit 重写一遍。
最终效果是这样

counter.ts
import { LitElement, css, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
@customElement('counter-component')
export class HTMLCounterElement extends LitElement {
@property({ type: Number })
step = 1;
@state()
private number = 0;
private minus() {
this.number -= this.step;
}
private plus() {
this.number += this.step;
}
render() {
return html`
<div class="counter">
<button class="minus" @click="${this.minus}">-</button>
<span class="number">${this.number}</span>
<button class="plus" @click="${this.plus}">+</button>
</div>
`;
}
static styles = css`
.counter {
display: flex;
gap: 16px;
}
.counter :is(.minus, .plus) {
width: 64px;
height: 64px;
}
.counter .number {
width: 128px;
height: 64px;
border: 1px solid gray;
font-size: 36px;
display: grid;
place-items: center;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
'counter-component': HTMLCounterElement;
}
}
index.html
<counter-component step="10"></counter-component>
Lit 的局限
我们拿 material-web MWC 和 material-components-web MDC 做对比。
MDC 是传统手法,先有 HTML、CSS,然后 JS 做 binding。
MWC 是 Web Components 手法,没有 HTML、CSS,一切都是 JS 生成的。
结论就是 Lit 的渲染依赖于 JS。
如果我们用 Lit 开发企业网站,需要 SEO,那就需要搞服务端渲染 Server-side rendering。但这个目前还在 experimental 阶段。
JavaScript Library – Lit的更多相关文章
- A javascript library providing cross-browser, cross-site messaging/method invocation. http://easyxdm.net
easyXDM - easy Cross-Domain Messaging easyXDM is a Javascript library that enables you as a develope ...
- Dynamices CRM JS 类库 神器 XrmServiceToolkit - A Microsoft Dynamics CRM 2011 & CRM 2013 JavaScript Library
XrmServiceToolkit - A Microsoft Dynamics CRM 2011 & CRM 2013 JavaScript Library http://xrmservic ...
- Raphaël—JavaScript Library
Raphaël-JavaScript Library What is it? Raphaël is a small JavaScript library that should simplify yo ...
- a Javascript library for training Deep Learning models
w强化算法和数学,来迎接机器学习.神经网络. http://cs.stanford.edu/people/karpathy/convnetjs/ ConvNetJS is a Javascript l ...
- JavaScript 工具库:Cloudgamer JavaScript Library v0.1 发布
JavaScript 工具库:Cloudgamer JavaScript Library v0.1 发布 研究了一年多的js,也差不多写一个自己的js库了.我写这个不算框架,只是一个小型的js工具 ...
- jQuery JavaScript Library v3.2.1
/*! * jQuery JavaScript Library v3.2.1 * https://jquery.com/ * * Includes Sizzle.js * https://sizzle ...
- A JavaScript library for reading EXIF meta data from image files.
exif-js/exif-js: JavaScript library for reading EXIF image metadata https://github.com/exif-js/exif- ...
- javascript library
<!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...
- 转:Build Your First JavaScript Library
http://net.tutsplus.com/tutorials/javascript-ajax/build-your-first-javascript-library/ Step 1: Creat ...
- [React] 01 - Intro: javaScript library for building user interfaces
教学视频: http://www.php.cn/code/8217.html React 教程: http://www.runoob.com/react/react-tutorial.html 本篇是 ...
随机推荐
- 解读MySQL 8.0数据字典缓存管理机制
背景介绍 MySQL的数据字典(Data Dictionary,简称DD),用于存储数据库的元数据信息,它在8.0版本中被重新设计和实现,通过将所有DD数据唯一地持久化到InnoDB存储引擎的DD t ...
- [oeasy]python0037_终端_terminal_电传打字机_tty_shell_控制台_console_发展历史
换行回车 回忆上次内容 换行 和 回车 是两回事 换行 对应字节0x0A Line-Feed 水平 不动 垂直 向上喂纸 所以是 feed 回车 对应字节0x0D Carriage-Return 垂直 ...
- [oeasy]python0018_ ASCII_字符分布_数字_大小写字母_符号_黑暗森林
打包和解包 回忆上次内容 decode 就是解码 解码和编码可以转化 encode 编码 decode 解码 互为逆过程 大小写字母之间序号全都相差(32)10进制 编辑 这是 ...
- 学习笔记--Java 运算符
Java 运算符 算术运算符 关系运算符 逻辑运算符 位运算[略] 赋值运算符 字符串连接符 三元运算符 Java 运算符 按照功能划分: 功能 运算符 算术运算符 +.-.*./.++.--.% 关 ...
- 毕设项目:springboot+vue实现的在线求职平台
一.前言 随着信息技术的飞速发展和互联网的普及,线上求职已成为众多求职者和企业招聘的重要渠道.为满足市场需求,我们利用Spring Boot和Vue技术栈,开发了一款功能全面.用户友好的在线求职平台. ...
- Ubuntu本地安装Docker
Ubuntu本地安装Docker 目录 Ubuntu本地安装Docker 查看Ubuntu系统版本代号 安装 修改镜像源 官方文档:Install Docker Engine on Ubuntu | ...
- 图解翻转单向链表,超详细(python语言实现)
节点类: 1 class ListNode(object): 2 def __init__(self, x): 3 self.val = x 4 slef.next = None 反转单向链表的函数如 ...
- 【.bat】IISExpress配置通过IP访问程序
本页只记录便携运行方式脚本 详细IISExpress配置方法请看: VS的IISExpress配置通过IP访问程序 网络信息:192.168.1.45:8378 Run.bat :: run as a ...
- 《最新出炉》系列入门篇-Python+Playwright自动化测试-56- 多文件上传 - 下篇
1.简介 前边的两篇文章中,宏哥分别对input控件上传文件和非input控件上传文件进行了从理论到实践地讲解和介绍,但是后来又有人提出疑问,前边讲解和介绍的都是上传一个文件,如果上传多个文件,Pla ...
- 【Hibernate】02 快速入门
环境搭建 : Windo7 x64 + IDEA 2018+ JDK 8+ Maven 3.0+ MySQL 5.0+ 创建Hibernate工程: 导入依赖坐标 <dependencies&g ...