构造函数
创建元素时调用。
用例:
执行必须在第一次更新之前完成的一次性初始化任务。例如,当不使用装饰器时,可以在构造函数中设置属性的默认值,如在静态属性字段中声明属性中所示。
constructor() {
super();
this.foo = 'foo';
this.bar = 'bar';
}
连接回调
在将组件添加到文档的 DOM 时调用。
用例:
connectedCallback()您应该设置仅在元素连接到文档时才发生的任务。其中最常见的是将事件侦听器添加到元素外部的节点,例如添加到窗口的 keydown 事件处理程序
connectedCallback() {
super.connectedCallback()
addEventListener('keydown', this._handleKeydown);
}
断开回调
当组件从文档的 DOM 中移除时调用。
用例:
这个回调是向元素发出它可能不再被使用的主要信号;因此,disconnectedCallback()应该确保没有任何东西持有对元素的引用(例如添加到元素外部节点的事件侦听器),以便可以自由地进行垃圾收集。
disconnectedCallback() {
super.disconnectedCallback()
window.removeEventListener('keydown', this._handleKeydown);
}
属性更改回调 和 通过回调
官网的描述时,一般用不到,具体见:https://lit.dev/docs/components/lifecycle/
当响应属性更改或requestUpdate()显式调用方法时,将触发响应更新周期。Lit 异步执行更新,因此属性更改是批处理的——如果在请求更新后但在更新开始之前有更多属性更改,则所有更改都会在同一个更新中捕获。
更新发生在微任务时间,这意味着它们发生在浏览器将下一帧绘制到屏幕之前。
主要掌握以下几个函数即可:
requestUpdate: 请求更新,主动告知组件需要更新
如果您需要在与属性无关的内容发生更改时更新和呈现元素,这将很有用。例如,计时器组件可能每秒调用requestUpdate()一次。
connectedCallback() {
super.connectedCallback();
this._timerInterval = setInterval(() => this.requestUpdate(), 1000);
}
disconnectedCallback() {
super.disconnectedCallback();
clearInterval(this._timerInterval);
}
shouldUpdate(): 调用以确定是否需要更新周期。
如果shouldUpdate()返回true(默认情况下),则更新正常进行。如果它返回false,则不会调用更新周期的其余部分,但updateCompletePromise 仍会被解析。
可以使用shouldUpdate()
以指定哪些属性更改应导致更新
shouldUpdate(changedProperties) {
// 只有当属性prop1改变时更新元素
return changedProperties.has('prop1');
}
willUpdate(): 计算依赖于其他属性并在更新过程的其余部分中使用的属性值。
willUpdate(changedProperties) {
// 当属性firstName或lastName改变时更新this.sha,类似于vue中的监听
if (changedProperties.has('firstName') || changedProperties.has('lastName')) {
this.sha = computeSHA(`${this.firstName} ${this.lastName}`);
}
}
render() {
return html`SHA: ${this.sha}`;
}
firstUpdated(): 在组件的 DOM 第一次更新后调用
这时dom已经可以被获取到
firstUpdated() {
this.renderRoot.getElementById('my-text-area').focus();
}
updateComplete: 更新完成
当updateComplete元素完成更新时,Promise 将解析。用于updateComplete等待更新。解析的值是一个布尔值,指示元素是否已完成更新。如果true更新周期结束后没有挂起的更新,则为。
渲染完成后从组件调度事件是一种很好的做法,以便事件的侦听器看到组件的完全渲染状态。为此,您可以updateComplete在触发事件之前等待 Promise。
async _loginClickHandler() {
this.loggedIn = true;
// Wait for `loggedIn` state to be rendered to the DOM
await this.updateComplete;
this.dispatchEvent(new Event('login'));
}
Lit 组件使用shadow DOM来封装它们的 DOM。Shadow DOM 提供了一种向元素添加单独隔离和封装的 DOM 树的方法。DOM 封装是解锁与页面上运行的任何其他代码(包括其他 Web 组件或 Lit 组件)互操作性的关键。
Shadow DOM 提供了三个好处:
document.querySelector
不会在组件的影子 DOM 中找到元素,因此全局脚本更难意外破坏您的组件。Lit 将组件渲染到它的renderRoot,默认情况下它是一个影子根。要查找内部元素,您可以使用 DOM 查询 API,例如this.renderRoot.querySelector()
普通方式
您可以在组件初始渲染后(例如 in firstUpdated)查询内部 DOM
firstUpdated(): void {
console.log(
"组件加载完成:",
document.getElementById("#abc"),
this.renderRoot.querySelector("#abc")
);
}
装饰器方式
可以通过 @query、@queryAll、@queryAsync
访问内部组件 DOM 中的节点
注:装饰器是一项提议的 JavaScript 功能,因此您需要使用 Babel 或 TypeScript 之类的编译器来使用装饰器。
@query
修改类属性,将其转换为从渲染根返回节点的 getter。可选的第二个参数为 true 时只执行一次 DOM 查询并缓存结果。@customElement("base-app")
export class BaseApp extends LitElement {
@property()
name: string = "Lit";
@query("#abc")
_abc: any;
// 渲染组件
protected render() {
return html` 你好,${this.name} `;
}
firstUpdated(): void {
console.log("组件加载完成:", this._abc);
}
}
这个装饰器等价于:
get _abc() {
return this.renderRoot?.querySelector('#abc') ?? null;
}
@queryAll
,与@query
类似,只是查询全部@queryAsync
类似@query
,只是它不是直接返回节点,而是Promise在任何挂起的元素渲染完成后返回解析到该节点基本使用
略,上一篇文章介绍样式时已经提到过了
访问有插槽的节点
可以创建一个 getter 来访问特定插槽的分配元素
firstUpdated(): void {
let a = this._slottedChildren;
}
//get 定义的方法是访问器,必须return
get _slottedChildren() {
const slot = this.shadowRoot.querySelector("slot");
console.log(slot);
console.log(slot.assignedElements({ flatten: false }));
return slot.assignedElements({ flatten: true });
}
slotchange事件
@customElement("demo-test")
export class DemoTest extends LitElement {
// 渲染组件
protected render() {
return html`
获取插槽内容
${this.handleSlotchange}>
`;
}
//插槽内容改变事件
handleSlotchange(e: any) {
//获取所有的插槽内容
const childNodes = e.target.assignedNodes({ flatten: true, slot: "test" });
console.log("改变:", childNodes[0].innerText);
}
}
不知道是哪里的问题,按着文档说的应该就是当插槽内容发生改变时触发slotchange事件,结果就初始化时执行了一次,后面就不执行了
@queryAssignedElements 和 @queryAssignedNodes 装饰器
@queryAssignedElements并将@queryAssignedNodes一个类属性转换为一个getter,该getter返回调用slot.assignedElements或slot.assignedNodes分别在组件的影子树中的给定槽上的结果。使用这些查询分配给给定槽的元素或节点。
可选参数:
元素替换为其分配的节点来展平分配的节点。(反正是没理解什么意思,true和false感觉也没啥区别)决定使用哪个装饰器取决于您是要查询分配给插槽的文本节点,还是只查询元素节点。
@customElement("base-app")
export class BaseApp extends LitElement {
static styles?: CSSResultGroup | undefined = css`
.odd {
color: orange;
font-size: 20px;
}
.even {
color: blue;
font-size: 20px;
}
`;
// 渲染组件
protected render() {
return html`
1
2
`;
}
}
@customElement("demo-test")
export class DemoTest extends LitElement {
@queryAssignedElements({ flatten: true, slot: "test", selector: ".even" })
_evenEl: any;
// 渲染组件
protected render() {
return html`
`;
}
_getElement() {
console.log("元素:", this._evenEl[0]);
}
}
略,没太理解是干嘛的。