介绍
什么是 hi-element?
hi-element 是基于 Web Components 和现代 Web 标准构建的一系列技术,旨在帮助您有效地解决网站和应用程序设计和开发中的一些最常见的挑战。
什么是 Web Components?
Web Components 是一个总称,指的是一系列专注于创建自定义 HTML 元素的 Web 标准。一些标准包括定义新的 HTML 标签、插入标准组件生命周期、封装 HTML 渲染和 CSS、参数化 CSS、皮肤组件等。这些平台功能中的每一个都是由 W3C 定义的,并且已经在当今的每个主要浏览器中发布。
hi-element 如何利用 Web Components?
hi-element 在 Web Components 基础上提供了一层封装,通过提供以下内容,提升了抽象级别,使构建组件变得更加容易和快速:
- 属性同步
- 丰富的模型视图 ViewModel(MVVM)支持
- 高效的模板渲染/更新
- 风格构成
- 元素引用、模板指令等等。
hi-element 的驱动原则之一是“尽可能采用开放的、基于 web 标准的方法”。为此,hi-element 直接建立在上述 W3C web 组件标准之上,并不创建自己的组件模型。这允许使用 hi-element 构建的组件与内置的原生 HTML 元素具有相同的功能。您不需要框架来使用它,但可以将它们与您选择的任何框架或库结合使用。
1. 快速启动
1.1 安装软件包
npm install --save hi-element
1.2 创建 Web Components
使用 hi-element 创建的 web 组件由 3 个部分组成,即 HTML 模板、CSS 样式和组件逻辑。Web 组件可以像按钮一样简单,也可以像整个页面的交互体验一样复杂。
首先,让我们创建一个简单的 web 组件,它结合了所有必要的部分:
import { attr, css, HIElement, html } from "hi-element";
/**
*使用HTML标签模板文字创建HTML模板,
*其中包含来自传递属性的插值文本内容
*/
const template = html`<span>Hello ${x => x.name}!</span>`
/**
*使用CSS标签模板文字创建CSS样式
*/
const styles = css`
:host {
border: 1px solid blue;
}
span {
color: red;
}
`;
/**
*通过创建一个扩展的类来定义组件逻辑
*HIElement,注意添加了attr装饰器,
*这将在组件上创建一个可以传递的属性。
*/
class HelloWorld extends HIElement {
@attr
name: string;
}
/**
*一旦文件完成,就为浏览器定义自定义web组件
*如果导入包含此逻辑的元素“hello world”,则
*在DOM中定义它的html、样式、逻辑和标签名。
*/
HelloWorld.define({
name: "hello-world",
template,
styles,
});
1.3 将其添加到您的项目中
现在已经定义了“hello world”自定义 web 组件,它可以像这样包含在 HTML 中:
<script type="module" src="path/to/hello-world.js"></script>
<hello-world name="Earth"></hello-world>
就这么简单!
2. HTML 模板
hi-element
提供了一个命名导出html
,这是一个模板字符串。它可以用来创建 HTML 片段,这些片段将成为您的 web components 影子 DOM(shadow DOM)。
例子:
import { html } from "hi-element";
export const template = html`
<template>Hello world</template>
`;
2.1 绑定
使用html
模板时,绑定允许比简单传递属性更复杂的行为。这些绑定是动态的,由箭头函数表示。默认情况下,属性被假定为字符串。我们通常用x
表示元素,用c
表示上下文。
例子:
import { HIElement, attr, html } from 'hi-element';
const template = html<NameTag>`
<h3>${(x,c) => x.greeting.toUpperCase()}</h3>
`;
export class NameTag extends HIElement {
@attr
greeting: string = 'hello';
}
NameTag.define({
name: 'name-tag',
template
});
当greeting
属性更新时,模板也会更新。
2.2 布尔值
布尔绑定使用?
符号,将这些用于布尔属性。
例子:
import { html } from "hi-element";
export const template = html`
<button
?disabled="${(x) => x.disabled}"
>
Button
</button>
`;
2.3 事件
事件绑定使用@
符号。所有 Element 事件都可用,有关详细信息,请参阅 MDN 文档。
例子:
import { html } from "hi-element";
export const template = html`
<button
@click="${(x, c) => x.clickHandler(c.event)}"
>
Button
</button>
`;
重要
执行事件处理程序后,默认情况下将对事件对象调用preventDefault()
。您可以从处理程序返回 true 以选择退出此行为。
2.4 属性
属性绑定使用:
符号。
例子:
import { html } from "hi-element";
export const template = html`
<input
:value="${(x) => x.value}"
/>
`;
一些复杂的用例包括绑定到自定义属性、更新该属性并观察它。要了解有关观察属性的更多信息,请查看 HIElement 文档。
2.5 键入模板
您可以将模板键入到它们正在渲染的数据模型中。在 TypeScript 中,我们提供类型作为标签的一部分:html<NameTag>
。
import { html } from 'hi-element';
const template = html<NameTag>`
<div>${x => x.greeting}</div>
`;
3. HTML 指令
我们提供指令以帮助解决一些常见情况。
3.1 ref
有时,您需要从模板中直接引用单个 DOM 节点。这可能是因为您需要节点的渲染尺寸,您想控制video
元素的播放,使用canvas
元素的绘图上下文,或者将元素传递给第三方库。无论出于什么原因,您都可以通过使用ref
指令来获取对 DOM 节点的引用。
示例:引用元素
import { HIElement, attr, html, ref } from 'hi-element';
const template = html<MP4Player>`
<video ${ref('video')}>
<source src=${x => x.src} type="video/mp4">
</video>
`;
export class MP4Player extends HIElement {
@attr
src: string;
video: HTMLVideoElement;
connectedCallback() {
super.connectedCallback();
this.video.play();
}
}
MP4Player.define({
name: "mp4-player",
template
});
将ref
指令放在要引用的元素上,并为其提供一个属性名称以分配引用。一旦connectdCallback
生命周期事件运行,您的属性将被设置为引用,可以正常使用。
如果你为 HTML 模板提供了一个类型,TypeScript 会对你提供的属性名进行类型检查,以确保它确实存在于你的元素上。
3.2 slotted
有时,您可能希望引用分配给特定插槽的所有节点。要完成此操作,请使用插槽指令。
import { HIElement, html, slotted } from 'hi-element';
const template = html<MyElement>`
<div>
<slot ${slotted('slottedNodes')}></slot>
</div>
`;
export class MyElement extends HIElement {
@observable
slottedNodes: Node[];
slottedNodesChanged() {
// respond to changes in slotted node
}
}
MyElement.define({
name: 'my-element',
template
});
与children
指令类似,sloted
指令将用分配给插槽的节点填充slottedNodes
属性。如果slottedNodes
被@observable
修饰,那么它将随着分配的节点的变化而动态更新。与任何可观察对象一样,您可以选择实现一个 propertyNameChanged 方法,以便在节点更改时收到通知。此外,您可以为slotted
指令提供一个选项对象,以指定底层 assignedNodes() API 调用的自定义配置或指定filter
。
最好为插槽节点利用更改处理程序,而不是假设节点将出现在connectedCallback
中。
3.3 children
除了使用ref
引用单个 DOM 节点外,您还可以使用子节点来获取对特定元素的所有子节点的引用。
示例:引用子节点
import { HIElement, html, children, repeat } from 'hi-element';
const template = html<FriendList>`
<ul ${children('listItems')}>
${repeat(x => x.friends, html<string>`
<li>${x => x}</li>
`)}
</ul>
`;
export class FriendList extends HIElement {
@observable
listItems: Node[];
@observable
friends: string[] = [];
connectedCallback() {
super.connectedCallback();
console.log(this.listItems);
}
}
FriendList.define({
name: 'friend-list',
template
});
在上面的示例中,listItems
属性将填充 ul 元素的所有子节点。如果listItems
被@observable
修饰,那么它将随着子节点的变化而动态更新。与任何可观察对象一样,您可以选择实现一个 propertyNameChanged 方法,以便在节点更改时收到通知。此外,您可以为children
指令提供一个options
对象,以指定底层 MutationObserver 的自定义配置。
与ref
一样,在connectedCallback
生命周期事件之前,子节点不可用。
在模板元素上使用children
指令将为您提供对自定义元素的所有 DOM 子节点的引用,无论它们是否在插槽或放在其它地方。
您还可以提供一个filter
函数来控制哪些子节点与您的属性同步。为了方便起见,我们提供了一个元素过滤器,让您可以选择指定选择器。以上面的例子为例,如果我们想确保我们的listItems
数组只包含li
元素(而不包含任何文本节点或其他潜在的子节点),我们可以这样编写模板:
示例:带有筛选子节点的 HTML 模板
const template = html<FriendList>`
<ul ${children({ property: 'listItems', filter: elements('li') })}>
${repeat(x => x.friends, html<string>`
<li>${x => x}</li>
`)}
</ul>
`;
如果为子项使用子树选项,则需要一个选择器来代替过滤器。这使得在整个子树中存在潜在的大量节点的情况下,能够更有效地收集所需的节点。
3.4 when
请谨慎使用,这将对性能产生影响。如果您发现自己在单个组件中大量使用此指令,请考虑创建多个组件。
when
指令使您能够有条件地呈现 HTML 块。当您向when
提供表达式时,当表达式计算结果为true
时,它会将子模板渲染到 DOM 中,当计算结果为false
时,它将删除子模板(或者如果它从未为真,则将完全跳过渲染)。
示例:条件渲染
import { HIElement, observable, html, when } from 'hi-element';
const template = html<MyApp>`
<h1>My App</h1>
${when(x => !x.ready, html<MyApp>`
Loading...
`)}
`;
export class MyApp extends HIElement {
@observable
ready: boolean = false;
@observable
data: any = null;
connectedCallback() {
super.connectedCallback();
this.loadData();
}
async loadData() {
const response = await fetch('some/resource');
const data = await response.json();
this.data = data;
this.ready = true;
}
}
MyApp.define({
name: 'my-app',
template
});
@observable
装饰器创建了一个属性,模板系统可以监视该属性的更改。它类似于@attr
,但该属性不会作为元素本身的 HTML 属性出现。
除了提供有条件渲染的模板外,您还可以提供一个计算结果为模板的表达式。这使您能够动态更改有条件渲染的内容。
示例:带条件渲染和动态模板的 HTML 模板
const template = html<MyApp>`
<h1>My App</h1>
${when(x => x.ready, x => x.dataTemplate)}
`;
3.5 repeat
请谨慎使用,这将对性能产生影响。相反,使用插槽并使用多个嵌套元素组合组件,插槽元素可以提供更高性能和更可维护的解决方案。
要呈现数据列表,请使用 repeat 指令,提供要呈现的列表和在呈现每个项目时使用的模板。
示例:列表渲染
import { HIElement, observable, html, repeat } from 'hi-element';
const template = html<FriendList>`
<h1>Friends</h1>
<form @submit="${x => x.addFriend()}>"
<input type="text" :value="${x => x.name}" @input="${(x, c) => x.handleNameInput(c.event)}">
<button type="submit">Add Friend</button>
</form>
<ul>
${repeat(x => x.friends, html<string>`
<li>${x => x}</li>
`)}
</ul>
`;
export class FriendList extends HIElement {
@observable
friends: string[] = [];
@observable
name: string = '';
addFriend() {
if (!this.name) {
return;
}
this.friends.push(this.name);
this.name = '';
}
handleNameInput(event: Event) {
this.name = (event.target! as HTMLInputElement).value;
}
}
FriendList.define({
name: 'friend-list',
template
})
与事件处理程序类似,在重复块中,您可以访问特殊的上下文对象。以下是上下文中可用的属性列表:
- event-事件处理程序中的事件对象。
- parent-位于
repeat
内的父视图模型。 - parentContext-在
repeat
内时的父ExecutionContext
。当重复嵌套并且最内部的重复需要访问根视图模型时,这很有用。 - index-当前项目在
repeat
内的索引。 - length-数组在
repeat
内时的长度。 - isEven-如果当前项的索引在
repeat
内为偶数(选择加入),则为true
。 - isOdd-如果当前项的索引在
repeat
内为奇数(选择加入),则为true
。 - isFirst-如果当前项在
repeat
内的数组中是第一个,则为true
。 - isInMiddle-如果当前项位于
repeat
内数组的中间位置,则为true
。 - isLast-如果当前项在
repeat
内的数组中是最后一个(选择加入),则为true
。
一些上下文属性是可选的,因为它们的更新成本更高。因此,出于性能原因,默认情况下它们不可用。要选择使用定位属性,请将选项传递给repeat
指令,并设置position:true
。例如,以下是我们如何使用上面朋友模板中的index
:
示例:带有列表呈现和项目索引的 HTMLTemplate
const template = html<FriendList>`
<ul>
${repeat(x => x.friends, html<string>`
<li>${(x, c) => c.index} ${x => x}</li>
`, { positioning: true })}
</ul>
`;
repeat
指令是否重用项目视图可以通过回收选项设置来控制。当recycle:true
为默认值时,repeat
指令可能会重用视图,而不是从模板创建新的视图。回收时:以前使用过的错误视图总是被丢弃,每个项目总是会被分配一个新视图。在某些情况下,回收以前使用的视图可能会提高性能,但也可能会使以前显示的项目变得“dirty”。
示例:带列表呈现且不回收视图的 HTML 模板
const template = html<FriendList>`
<ul>
${repeat(
x => x.friends,
html<string>`<li>${(x, c) => c.index} ${x => x}</li>`,
{ positioning: true, recycle: false }
)}
</ul>
`;
除了提供用于呈现项目的模板外,您还可以提供一个计算结果为模板的表达式。这使您能够动态更改用于渲染项目的内容。
4. CSS 模板
hi-element
提供了一个名为css
的模板字符串。它可以用来创建 CSS 片段,这些片段将成为您的 web components CSS。这些样式被采用 adoptedStylesheets 并与ShadowRoot
相关联,因此它们不会影响文档其余部分的样式。为了在文档和 web 组件之间共享样式,我们建议使用 CSS 属性。
示例:
import { HIElement, attr, css, html } from 'hi-element';
const template = html`
<span>${x => x.greeting.toUpperCase()}</span>
`;
export const styles = css`
:host {
color: red;
background: var(--background-color, green);
}
`;
export class NameTag extends HIElement {
@attr
greeting: string = 'hello';
}
NameTag.define({
name: 'name-tag',
template,
styles
});
HTML 文件:
<style>
body {
--background-color: orange;
}
</style>
<name-tag></name-tag>
使用 css 助手,我们能够创建ElementStyles
。我们通过装饰器的 styles 选项用元素配置它。在内部,HIElement 将利用可构造样式表对象和ShadowRoot#adoptedStyleSheets
在组件之间高效地重用 CSS。这意味着,即使我们有 1 千个name-tag
组件的实例,它们也将共享一个相关样式的实例,从而减少内存分配并提高性能。因为这些样式与ShadowRoot
相关联,所以它们也将被封装。这可确保您的样式不会影响其他元素,其他元素样式也不会影响您的元素。
4.1 编写样式
ElementStyles
的一个优点是它可以与其他样式组合。想象一下,我们有一个 CSS 规范化,我们想在我们的名字标签组件中使用它。我们可以这样把它组合成我们的风格:
示例:编写 CSS 注册表
import { normalize } from './normalize';
const styles = css`
${normalize}
:host {
display: inline-block;
contain: content;
color: white;
background: var(--fill-color);
border-radius: var(--border-radius);
min-width: 325px;
text-align: center;
box-shadow: 0 0 calc(var(--depth) * 1px) rgba(0,0,0,.5);
}
...
`;
CSS 助手理解normalize
是ElementStyles
,而不是简单的连接 CSS 字符串,并且能够像使用normalize
的任何其他组件一样重用相同的可构造样式表实例。
您还可以将 CSS 字符串或CSSStyleSheet
实例直接传递给元素定义,甚至可以传递字符串、CSSStyleSheet
或ElementStyles
的混合数组。
可以使用withBehaviors()
向 css 标记模板或HIElement
中添加或删除样式。
4.2 添加外部样式
样式可以作为数组添加,这对于在组件之间共享样式和以字符串形式引入样式非常有用。
const sharedStyles = `
h2 {
font-family: sans-serif;
}
`;
NameTag.define({
name: 'name-tag',
template,
styles: [
css`
:host {
color: red;
background: var(--background-color, green);
}
`,
sharedStyles
]
})
您可能会注意到,我们使用了:host
,这是标准 CSS 伪类的一部分。可用于设置自定义 web components 样式的伪元素包括::sloted
和::part
。
5. HIElement
HIElement 类可以扩展用于您的自定义组件逻辑。
5.1 属性绑定
属性是使用@attr 装饰器定义的
示例:
import { HIElement, attr } from 'hi-element';
export class MyElement extends HIElement {
@attr
foo: string;
}
HTML 文件:
<my-element foo="Hello"></my-element>
@attr
可以使用以下选项进行配置:
属性 | 描述 | 类型 | 默认 | ||
attribute | DOM 中反映的属性名称,在首选不同字符串的情况下可以指定 | string | 类属性已转换为小写 | ||
mode | 如果属性是布尔值,并且模式设置为“boolean”,则允许 HIElement 以与元素上的原生布尔属性相同的方式在元素中添加/删除属性。“fromView”行为仅根据 DOM 中的更改更新属性值,但不会反映回属性更改。 | "reflect" | "boolean" | "fromView" | "reflect" |
converter | 这允许在移入和移出 HTML 模板时转换属性的值 |
具有自定义属性名称和布尔模式的示例:
import { HIElement, attr } from 'hi-element';
export class MyElement extends HIElement {
@attr({
attribute: "foo-bar",
mode: "boolean"
})
foo: boolean;
}
HTML 文件:
<my-element foo-bar></my-element>
作为一个方便的功能,属性名称在 HTML 中会自动转换为小写版本,因此在HIElement
中将fooBar
声明为@attr
将在 HTML 中转换为foobar
。我们包括属性的配置选项以允许重新命名,最常见的用例之一是添加破折号,因此您可以像上面的示例一样使用foo-bar
。
当mode
设置为boolean
时,内置的booleanConverter
会自动用于确保类型正确性,因此在这种常见情况下不需要手动配置转换器。
5.2 Converters
除了设置模式外,您还可以通过设置属性配置的转换器属性来提供自定义ValueConverter
。转换器必须实现以下接口:
interface ValueConverter {
toView(value: any): string;
fromView(value: string): any;
}
其工作原理如下:
- 当 DOM 属性值更改时,将调用转换器的
fromView
方法,允许自定义代码将值强制转换为属性所需的正确类型。 - 当属性值更改时,转换器的
fromView
方法也将被调用,以确保类型正确。在此之后,将确定模式。如果模式设置为反射,则将调用转换器的toView
方法,以允许在使用setAttribute
写入属性之前对类型进行格式化。
示例:具有自定义转换的反射模式中的属性
import { HIElement, attr, ValueConverter } from 'hi-element';
const numberConverter: ValueConverter = {
toView(value: any): string {
// convert numbers to strings
},
fromView(value: string): any {
// convert strings to numbers
}
};
export class MyCounter extends HIElement {
@attr({ converter: numberConverter }) count: number = 0;
}
MyCounter.define({
name: 'my-counter'
});
也有一些常用的转换器可供选择:
booleanConverter
一个用于转换布尔值的值转换器,选择布尔时自动使用。
booleanConverter: ValueConverter
nullableBooleanConverter
一个用于转换布尔值的值转换器。null、undefined、""和 void 值转换为 null
nullableBooleanConverter: ValueConverter
nullableNumberConverter
一个用于转换数值的值转换器,此转换器允许可以为 null 的数字,如果输入为 null、undefined 或 NaN,则返回 null。
nullableNumberConverter: ValueConverter
5.3 Observables
@attr
用于基本属性(字符串、布尔值和数字),而@observable
装饰器用于所有其他属性。除了观察属性,模板系统还可以观察数组。
这些装饰器是对类上的属性进行元编程的一种手段,这样它们就包括了支持状态跟踪、观察和反应所需的所有实现。您可以访问模板中的任何属性,但如果它没有用这两个装饰器之一进行装饰,则其值在初始渲染后不会更新。
仅具有 getter 的属性,作为计算属性,不应使用@attr
或@observable
来修饰。然而,根据内部逻辑,它们可能需要用@volatile
进行装饰。
import { HIElement, observable } from 'hi-element';
export class MyComponent extends HIElement {
@observable
someBoolean = false;
@observable
valueA = 0;
@observable
valueB = 42;
}
@observable
的一个常见用例是使用插槽元素。
示例:跟踪添加/删除到插槽中的元素的更改
import { HIElement, observable } from 'hi-element';
class MyComponent extends HIElement {
@observable
public slottedItems: HTMLElement[];
protected itemCount: number;
public slottedItemsChanged(oldValue: HTMLElement[], newValue: HTMLElement[]): void {
if (this.$HiController.isConnected) {
this.itemCount = newValue.length;
}
}
}
手动跟踪可观测值
当在模板渲染过程中访问@attr
和@observable
装饰属性时,它们会被跟踪,使引擎能够深入了解模型和视图之间的关系。这些装饰器用于为您对属性进行元编程,注入代码以启用观察系统。但是,如果你不喜欢这种方法,对于@observable
,你总是可以手动实现通知。如果你需要在getter
和setter
中执行一些额外的逻辑,这尤其有用。这是它的样子:
示例:手动观察者实现
import { Observable } from 'hi-element';
export class Person {
private _name: string;
get name() {
Observable.track(this, 'name');
return this._name;
}
set name(value: string) {
this._name = value;
Observable.notify(this, 'name');
}
}
5.4 发射事件
在各种情况下,自定义元素发布其自己的特定于元素的事件可能是合适的。为此,您可以在 HIElement 上使用$emit
辅助程序。这是一种方便的方法,可以创建CustomEvent
的实例,并使用 HIElement 上的dispatchEvent
API 和bubble:true
和composed:true
选项。它还确保只有当自定义元素完全连接到 DOM 时才会发出事件。
示例:自定义事件调度
const template = html`
<input @change="${x => x.valueChanged()}" />
`;
export class MyInput extends HIElement {
@attr
value: string = '';
valueChanged() {
this.$emit('change', this.value);
}
}
在发出自定义事件时,请确保您的事件名称始终为小写,以便您的 Web Components 与通过 DOM 绑定模式附加事件的各种前端框架保持兼容(DOM 不区分大小写)。
5.5 定义
HIElement 有一个define
方法,这是向浏览器注册自定义 Web Components 的方法。
例子:
import { HIElement } from 'hi-element';
export class MyElement extends HIElement {}
MyElement.define({
name: 'my-element'
});
定义 Web Components 会产生副作用。这一点很重要,因为摇树优化可能会导致在运行过程中删除 web 组件,即使它们是导入的。确保您的构建系统考虑到了这一点,并且不会对您的 Web Components 进行摇树优化。
此配置可以采取各种选项:
熟悉 | 描述 | 默认 | 必选 |
name | 自定义元素的名称 | 是 | |
template | 为自定义元素渲染的模板。使用 html 标签模板文字创建此模板 | ||
styles | 与自定义元素关联的样式。使用 css 标签模板文字创建此模板 | ||
shadowOptions | 控制自定义元素的 shadow DOM 创建的选项。提供 null 以将关联的模板呈现给轻量级 DOM。示例:{delegatesFocus:true} ,有关详细信息,请参阅 ShadowRoot API。 | 默认为打开 shadow root。 | |
elementOptions | 控制如何使用平台定义自定义元素的选项 | ||
registry | 默认情况下,用于注册此组件的注册表 | 如果未提供,则默认为全局注册表 |
典型的配置至少包括名称、模板和样式。
例子:
import { attr, css, HIElement, html } from "hi-element";
const template = html`<span>Hello ${x => x.name}!</span>`
const styles = css`
:host {
border: 1px solid blue;
}
`;
class HelloWorld extends HIElement {
@attr
name: string;
}
HelloWorld.define({
name: "hello-world",
template,
styles,
});
示例:使用自定义注册表进行定义
export const FooRegistry = Object.freeze({
prefix: 'foo',
registry: customElements,
});
HelloWorld.compose({
name: `${FooRegistry.prefix}-tab`,
template,
styles,
}).define(FooRegistry);
5.6 生命周期
所有 Web Components 都支持一系列生命周期事件,您可以利用这些事件在特定时间点执行自定义代码。HIElement 自动实现了其中几个回调,以启用其模板引擎的功能。但是,您可以覆盖它们以提供自己的代码。下面是一个示例,说明当元素插入 DOM 时如何执行自定义代码。
示例:利用自定义元素生命周期
import { HIElement, attr } from 'hi-element';
export class NameTag extends HIElement {
@attr
greeting: string = 'Hello';
greetingChanged() {
this.shadowRoot!.innerHTML = this.greeting;
}
connectedCallback() {
super.connectedCallback();
console.log('name-tag is now connected to the DOM');
}
}
可用生命周期回调的完整列表:
生命周期 | 描述 |
constructor | 创建或升级元素时运行。HIElement此时将附加阴影DOM |
connectedCallback | 当元素插入DOM时运行。在第一次连接时,HIElement会水合HTML模板,连接模板绑定,并添加样式 |
disconnectedCallback | 从DOM中删除元素时运行。HIElement此时将删除模板绑定并清理资源 |
Changed(oldVal, newVal) | 每当元素的自定义属性发生变化时运行。HIElement使用此功能将属性与其属性同步。当属性更新时,如果存在模板依赖关系,渲染更新也会排队。命名约定是在属性名称的末尾添加“Changed”,这就是将被调用的方法。 |
adoptedCallback | 如果元素通过对adoptNode(…)API的调用从其当前文档移动到新文档中,调用当前函数 |
附:基于 hi-element 开发的 UI 组件库 Hi-kits
ys-zjrs.haier.net/Hi-Kits-Doc…
6. 团队介绍
「三翼鸟数字化技术平台-ToC服务平台」以用户行为数据为基础,利用推荐引擎为用户提供“千人千面”的个性化推荐服务,改善用户体验,持续提升核心业务指标。通过构建高效、智能的线上运营系统,全面整合数据资产,实现数据分析-人群圈选-用户触达-后效分析-策略优化的运营闭环,并提供可视化报表,一站式操作提升数字化运营效率。