标签:中指明 oat log ssi ora meta generate conf attribute
LitElement管理您声明的属性及其对应的属性。默认情况下,LitElement将:
属性声明是具有以下格式的对象:
{ optionName1: optionValue1, optionName2: optionValue2, ... }
也可以是以下选项:
converter: Convert between properties and attributes.type: Use LitElement’s default attribute converter.attribute: Configure observed attributes.reflect: Configure reflected attributes.noAccessor: Whether to set up a default property accessor.hasChanged: Specify what constitutes a property change.可以在静态属性getter中或使用TypeScript装饰器指定所有属性声明选项。
通过实现静态 properties 或使用装饰器(注解)来声明元素的属性,就像C的声明与定义分开的写法:
// properties getter static get properties() { return { prop1: { type: String } }; }
// Decorators (requires TypeScript or Babel) export class MyElement extends LitElement { @property( { type : String } ) prop1 = ‘‘;
static get properties() { return { prop1: { type: String }, prop2: { type: Number }, prop3: { type: Boolean } }; }
注意:如果实现静态属性获取器,请在元素构造函数中初始化属性值。
constructor() { // Always call super() first super(); this.prop1 = ‘Hello World‘; ... }
请记住,首先要在构造函数中调用super(),否则元素将无法渲染。
示例:使用静态属性获取器声明属性
import { LitElement, html } from ‘lit-element‘;
class MyElement extends LitElement {
static get properties() { return {
prop1: { type: String },
prop2: { type: Number },
prop3: { type: Boolean },
prop4: { type: Array },
prop5: { type: Object }
};}
constructor() {
super();
this.prop1 = ‘Hello World‘;
this.prop2 = 5;
this.prop3 = false;
this.prop4 = [1,2,3];
this.prop5 = { subprop1: ‘prop 5 subprop1 value‘ }
}
render() {
return html`
<p>prop1: ${this.prop1}</p>
<p>prop2: ${this.prop2}</p>
<p>prop3: ${this.prop3}</p>
<p>prop4[0]: ${this.prop4[0]}</p>
<p>prop5.subprop1: ${this.prop5.subprop1}</p>
`;
}
}
customElements.define(‘my-element‘, MyElement);
2.2 用注解声明属性
翻译为装饰器,但我更喜欢称之为注解(Java框架),一般用在TS文件中
@property({type : String}) prop1 = ‘Hello World‘;
装饰器是JavaScript的一项建议功能,因此您需要使用Babel或Translate编译器(例如TypeScript编译器)来使用装饰器。
如果您使用的是Babel,则需要使用@babel/plugin-proposal-decorators插件
如果你使用TypeScript,你需要激活 experimentalDecorators 编译选项(例如:在tsconfig.json配置文件中设置"experimentalDecorators": true),不推荐也不必要激活emitDecoratorMetadata选项
用注解声明属性的例子:
my-element.ts
import { LitElement, html, customElement, property } from ‘lit-element‘;
@customElement(‘my-element‘)
export class MyElement extends LitElement {
@property({type : String}) prop1 = ‘Hello World‘;
@property({type : Number}) prop2 = 5;
@property({type : Boolean}) prop3 = true;
@property({type : Array}) prop4 = [1,2,3];
@property({type : Object}) prop5 = { subprop1: ‘prop 5 subprop1 value‘ };
render() {
return html`
<p>prop1: ${this.prop1}</p>
<p>prop2: ${this.prop2}</p>
<p>prop3: ${this.prop3}</p>
<p>prop4[0]: ${this.prop4[0]}</p>
<p>prop5.subprop1: ${this.prop5.subprop1}</p>
`;
}
}
index.ts
import ‘./my-element.ts‘;
index.html
<!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> <title>lit-element code sample</title> </head> <body> <my-element></my-element> </body> </html>
static get properties() { return { /* Property declarations */ }; }
constructor() {
// Always call super() first
super();
// Initialize properties
this.prop1 = ‘Hello World‘;
}
注意:组件实现类的所有构造方法中都必须手动调用父类的构造方法 super()
完整的例子:
import { LitElement, html } from ‘lit-element‘;
class MyElement extends LitElement {
static get properties() { return {
prop1: { type: String },
prop2: { type: Number },
prop3: { type: Boolean },
prop4: { type: Array },
prop5: { type: Object }
};}
constructor() {
super();
this.prop1 = ‘Hello World‘;
this.prop2 = 5;
this.prop3 = true;
this.prop4 = [1,2,3];
this.prop5 = { stuff: ‘hi‘, otherStuff: ‘wow‘ };
}
render() {
return html`
<p>prop1: ${this.prop1}</p>
<p>prop2: ${this.prop2}</p>
<p>prop3: ${this.prop3}</p>
<p>prop4: ${this.prop4.map((item, index) =>
html`<span>[${index}]:${item} </span>`)}
</p>
<p>prop5:
${Object.keys(this.prop5).map(item =>
html`<span>${item}: ${this.prop5[item]} </span>`)}
</p>
`;
}
}
customElements.define(‘my-element‘, MyElement);
在TypeScript中使用@property注解来初始化属性值
@property({ type : String }) prop1 = ‘Hello World‘;
即可以直接在声明的同时初始化,将 static properties getter()方法和 constructor()方法所作的事情合而为一
例子:
import { LitElement, html, customElement, property } from ‘lit-element‘;
@customElement(‘my-element‘)
export class MyElement extends LitElement {
// Declare and initialize properties
@property({type : String}) prop1 = ‘Hello World‘;
@property({type : Number}) prop2 = 5;
@property({type : Boolean}) prop3 = true;
@property({type : Array}) prop4 = [1,2,3];
@property({type : Object}) prop5 = { subprop1: ‘hi‘, thing: ‘fasdfsf‘ };
render() {
return html`
<p>prop1: ${this.prop1}</p>
<p>prop2: ${this.prop2}</p>
<p>prop3: ${this.prop3}</p>
<p>prop4: ${this.prop4.map((item, index) =>
html`<span>[${index}]:${item} </span>`)}
</p>
<p>prop5:
${Object.keys(this.prop5).map(item =>
html`<span>${item}: ${this.prop5[item]} </span>`)}
</p>
`;
}
}
ndex.html
<my-element mystring="hello world" mynumber="5" mybool myobj=‘{"stuff":"hi"}‘ myarray=‘[1,2,3,4]‘></my-element>
就像普通的html写法一样
虽然元素 properties 可以是任何类型,但是 attributes 始终是字符串。这会影响非字符串属性的 observed attributes 和 reflected attributes:
要 observe 一个属性(set a property from an attribute),属性值必须由string类型转换为匹配的类型
要 reflect 一个属性(set an attribute from a property),属性值必须被转化为string
在处理 String,Number, Boolean,Array, and Object 属性类型时,LitElement有一个默认的转换规则
要使用默认的转换规则,需要在你的属性声明中指明 type 选项
// Use LitElement‘s default converter prop1: { type: String }, prop2: { type: Number }, prop3: { type: Boolean }, prop4: { type: Array }, prop5: { type: Object }
以下信息显示默认转换器如何处理每种类型的转换。
从 attribute 转换到 property :
从 property 转换到 attribute :
使用默认转换的例子:
import { LitElement, html } from ‘lit-element‘;
class MyElement extends LitElement {
static get properties() { return {
prop1: { type: String, reflect: true },
prop2: { type: Number, reflect: true },
prop3: { type: Boolean, reflect: true },
prop4: { type: Array, reflect: true },
prop5: { type: Object, reflect: true }
};}
constructor() {
super();
this.prop1 = ‘‘;
this.prop2 = 0;
this.prop3 = false;
this.prop4 = [];
this.prop5 = { };
}
attributeChangedCallback(name, oldVal, newVal) {
console.log(‘attribute change: ‘, name, newVal);
super.attributeChangedCallback(name, oldVal, newVal);
}
render() {
return html`
<p>prop1 ${this.prop1}</p>
<p>prop2 ${this.prop2}</p>
<p>prop3 ${this.prop3}</p>
<p>prop4: ${this.prop4.map((item, index) =>
html`<span>[${index}]:${item} </span>`)}
</p>
<p>prop5:
${Object.keys(this.prop5).map(item =>
html`<span>${item}: ${this.prop5[item]} </span>`)}
</p>
<button @click="${this.changeProperties}">change properties</button>
<button @click="${this.changeAttributes}">change attributes</button>
`;
}
changeAttributes() {
let randy = Math.floor(Math.random()*10);
let myBool = this.getAttribute(‘prop3‘);
this.setAttribute(‘prop1‘, randy.toString());
this.setAttribute(‘prop2‘, randy.toString());
this.setAttribute(‘prop3‘, myBool? ‘‘ : null);
this.setAttribute(‘prop4‘, JSON.stringify([...this.prop4, randy]));
this.setAttribute(‘prop5‘,
JSON.stringify(Object.assign({}, this.prop5, {[randy]: randy})));
this.requestUpdate();
}
changeProperties() {
let randy = Math.floor(Math.random()*10);
let myBool = this.prop3;
this.prop1 = randy.toString();
this.prop2 = randy;
this.prop3 = !myBool;
this.prop4 = [...this.prop4, randy];
this.prop5 = Object.assign({}, this.prop5, {[randy]: randy});
}
updated(changedProperties) {
changedProperties.forEach((oldValue, propName) => {
console.log(`${propName} changed. oldValue: ${oldValue}`);
});
}
}
customElements.define(‘my-element‘, MyElement);
您可以使用converter选项在属性声明中指定自定义属性转换器:
myProp: { converter: // Custom property converter }
converter可以是一个对象或函数,如果是一个对象,它有2个关键字 fromAttribute 和 toAttribute
prop1: { converter: { fromAttribute: (value, type) => { // `value` is a string // Convert it to a value of type `type` and return it }, toAttribute: (value, type) => { // `value` is of type `type` // Convert it to a string and return it } } }
如果是一个函数,它被用来替代 fromAttribute:
myProp: { converter: (value, type) => { // `value` is a string // Convert it to a value of type `type` and return it } }
如果没有为反射的属性提供toAttribute函数,则该属性将设置为property 值,而无需进行转换。
在更新期间:
If toAttribute returns null, the attribute is removed.
If toAttribute returns undefined, the attribute is not changed.
自定义转换的例子:
import { LitElement, html } from ‘lit-element‘;
class MyElement extends LitElement {
static get properties() { return {
myProp: {
reflect: true,
converter: {
toAttribute(value) {
console.log(‘myProp\‘s toAttribute.‘);
console.log(‘Processing:‘, value, typeof(value));
let retVal = String(value);
console.log(‘Returning:‘, retVal, typeof(retVal));
return retVal;
},
fromAttribute(value) {
console.log(‘myProp\‘s fromAttribute.‘);
console.log(‘Processing:‘, value, typeof(value));
let retVal = Number(value);
console.log(‘Returning:‘, retVal, typeof(retVal));
return retVal;
}
}
},
theProp: {
reflect: true,
converter(value) {
console.log(‘theProp\‘s converter.‘);
console.log(‘Processing:‘, value, typeof(value));
let retVal = Number(value);
console.log(‘Returning:‘, retVal, typeof(retVal));
return retVal;
}},
};}
constructor() {
super();
this.myProp = ‘myProp‘;
this.theProp = ‘theProp‘;
}
attributeChangedCallback(name, oldval, newval) {
// console.log(‘attribute change: ‘, name, newval);
super.attributeChangedCallback(name, oldval, newval);
}
render() {
return html`
<p>myProp ${this.myProp}</p>
<p>theProp ${this.theProp}</p>
<button @click="${this.changeProperties}">change properties</button>
<button @click="${this.changeAttributes}">change attributes</button>
`;
}
changeAttributes() {
let randomString = Math.floor(Math.random()*100).toString();
this.setAttribute(‘myprop‘, ‘myprop ‘ + randomString);
this.setAttribute(‘theprop‘, ‘theprop ‘ + randomString);
this.requestUpdate();
}
changeProperties() {
let randomString = Math.floor(Math.random()*100).toString();
this.myProp=‘myProp ‘ + randomString;
this.theProp=‘theProp ‘ + randomString;
}
}
customElements.define(‘my-element‘, MyElement);
只要 observed attribute 发生更改,就会触发自定义元素API回调 attributeChangedCallback。默认情况下,每当某个属性触发此回调时,LitElement就会使用属性的 fromAttribute函数从该attribute 设置property值。
默认情况下,LitElement为所有声明的属性创建一个相应的观察属性。被观察属性的名称是属性名称,小写:
// observed attribute name is "myprop" myProp: { type: Number }
要使用其他名称创建观察到的属性,请将attribute设置为字符串:
// Observed attribute will be called my-prop myProp: { attribute: ‘my-prop‘ }
为了防止为从property创建observed attribute,请将attribute设置为false。该property 不会从标记中的attributes 初始化,并且attribute 更改不会对其产生影响。
// No observed attribute for this property myProp: { attribute: false }
配置observed attributes的例子
import { LitElement, html } from ‘lit-element‘;
class MyElement extends LitElement {
static get properties() { return {
myProp: { attribute: true },
theProp: { attribute: false },
otherProp: { attribute: ‘other-prop‘ },
};}
constructor() {
super();
this.myProp = ‘myProp‘;
this.theProp = ‘theProp‘;
this.otherProp = ‘otherProp‘;
}
attributeChangedCallback(name, oldval, newval) {
console.log(‘attribute change: ‘, name, newval);
super.attributeChangedCallback(name, oldval, newval);
}
render() {
return html`
<p>myProp ${this.myProp}</p>
<p>theProp ${this.theProp}</p>
<p>otherProp ${this.otherProp}</p>
<button @click="${this.changeAttributes}">change attributes</button>
`;
}
changeAttributes() {
let randomString = Math.floor(Math.random()*100).toString();
this.setAttribute(‘myprop‘, ‘myprop ‘ + randomString);
this.setAttribute(‘theprop‘, ‘theprop ‘ + randomString);
this.setAttribute(‘other-prop‘, ‘other-prop ‘ + randomString);
this.requestUpdate();
}
updated(changedProperties) {
changedProperties.forEach((oldValue, propName) => {
console.log(`${propName} changed. oldValue: ${oldValue}`);
});
}
}
customElements.define(‘my-element‘, MyElement);
您可以配置property ,以便每当property 更改时,其值都会反射到其 observed attribute 中。例如:
// Value of property "myProp" will reflect to attribute "myprop" myProp: { reflect: true }
property更改后,LitElement使用属性转换器中的toAttribute函数从新property值中设置attribute值。
If toAttribute returns null, the attribute is removed.
If toAttribute returns undefined, the attribute is not changed.
If toAttribute itself is undefined, the property value is set to the attribute value without conversion.
LitElement跟踪更新期间的反射状态。LitElement跟踪状态信息,以避免在属性与观察到的反射属性之间创建无限循环的变化。
import { LitElement, html } from ‘lit-element‘;
class MyElement extends LitElement {
static get properties() { return {
myProp: { reflect: true }
};}
constructor() {
super();
this.myProp=‘myProp‘;
}
attributeChangedCallback(name, oldval, newval) {
console.log(‘attribute change: ‘, newval);
super.attributeChangedCallback(name, oldval, newval);
}
render() {
return html`
<p>${this.myProp}</p>
<button @click="${this.changeProperty}">change property</button>
`;
}
changeProperty() {
let randomString = Math.floor(Math.random()*100).toString();
this.myProp=‘myProp ‘ + randomString;
}
}
customElements.define(‘my-element‘, MyElement);
默认情况下,LitElement为所有声明的属性生成一个属性访问器。每当您设置属性时,都会调用访问器:
// Declare a property static get properties() { return { myProp: { type: String } }; } ... // Later, set the property this.myProp = ‘hi‘; // invokes myProp‘s generated property accessor
生成的访问器会自动调用requestUpdate,如果尚未开始,则启动更新。
也就是Java类常用的自定义属性的get set方法
要指定属性的获取和设置的工作方式,可以定义自己的属性访问器。例如:
static get properties() { return { myProp: { type: String } }; }
set myProp(value) {
const oldValue = this.myProp;
// Implement setter logic here...
this.requestUpdate(‘myProp‘, oldValue);
}
get myProp() { ... }
...
// Later, set the property
this.myProp = ‘hi‘; // Invokes your accessor
如果您的类为属性定义了自己的访问器,则LitElement不会用生成的访问器覆盖它们。如果您的类没有为属性定义访问器,即使超类定义了一个或多个属性,LitElement也会生成它们。
LitElement生成的设置器会自动调用requestUpdate。如果编写自己的设置器,则必须手动调用requestUpdate,并提供属性名称及其旧值。
例子:
import { LitElement, html } from ‘lit-element‘;
class MyElement extends LitElement {
static get properties() {
return { prop: { type: Number } };
}
set prop(val) {
let oldVal = this._prop;
this._prop = Math.floor(val);
this.requestUpdate(‘prop‘, oldVal);
}
get prop() { return this._prop; }
constructor() {
super();
this._prop = 0;
}
render() {
return html`
<p>prop: ${this.prop}</p>
<button @click="${() => { this.prop = Math.random()*10; }}">
change prop
</button>
`;
}
}
customElements.define(‘my-element‘, MyElement);
如果要将自己的属性访问器与@property装饰器一起使用,则可以通过将装饰器放在getter上来实现此目的:
_myProp: string = ‘‘; @property({ type: String }) public get myProp(): string { return this._myProp; } public set myProp(value: string) { const oldValue = this.myProp; this._myProp = value; this.requestUpdate(‘myProp‘, oldValue); }
在极少数情况下,子类可能需要为其父类上存在的属性更改或添加属性选项
为了防止LitElement生成覆盖父类的已定义访问器的属性访问器(防止覆盖父类属性get set 方法),请在属性声明中将noAccessor设置为true:
static get properties() { return { myProp: { type: Number, noAccessor: true } }; }
定义自己的访问器时,无需设置Accessor。
例如,
父类
import { LitElement, html } from ‘lit-element‘;
export class SuperElement extends LitElement {
static get properties() {
return { prop: { type: Number } };
}
set prop(val) {
let oldVal = this._prop;
this._prop = Math.floor(val);
this.requestUpdate(‘prop‘, oldVal);
}
get prop() { return this._prop; }
constructor() {
super();
this._prop = 0;
}
render() {
return html`
<p>prop: ${this.prop}</p>
<button @click="${() => { this.prop = Math.random()*10; }}">
change prop
</button>
`;
}
}
customElements.define(‘super-element‘, SuperElement);
子类
import { SuperElement } from ‘./super-element.js‘;
class SubElement extends SuperElement {
static get properties() {
return { prop: { reflectToAttribute: true, noAccessor: true } };
}
}
customElements.define(‘sub-element‘, SubElement);
所有声明的属性都有一个函数hasChanged,只要设置了属性,就会调用该函数。
hasChanged比较属性的旧值和新值,并评估属性是否已更改。如果hasChanged返回true,则如果尚未安排元素更新,则LitElement将开始元素更新。有关更新如何工作的更多信息,请参见Element更新生命周期文档。
hasChanged returns true if newVal !== oldVal.hasChanged returns false if both the new and old values are NaN.要为属性定制hasChanged,请将其指定为属性选项,也就是自定义属性更改的比较规则,相当于Java重写equals方法
myProp: { hasChanged(newVal, oldVal) { // compare newVal and oldVal // return `true` if an update should proceed }}
例子:
import { LitElement, html } from ‘lit-element‘;
class MyElement extends LitElement {
static get properties(){ return {
myProp: {
type: Number,
/**
* Compare myProp‘s new value with its old value.
*
* Only consider myProp to have changed if newVal is larger than
* oldVal.
*/
hasChanged(newVal, oldVal) {
if (newVal > oldVal) {
console.log(`${newVal} > ${oldVal}. hasChanged: true.`);
return true;
}
else {
console.log(`${newVal} <= ${oldVal}. hasChanged: false.`);
return false;
}
}
}};
}
constructor(){
super();
this.myProp = 1;
}
render(){
return html`
<p>${this.myProp}</p>
<button @click="${this.getNewVal}">get new value</button>
`;
}
updated(){
console.log(‘updated‘);
}
getNewVal(){
let newVal = Math.floor(Math.random()*10);
this.myProp = newVal;
}
}
customElements.define(‘my-element‘, MyElement);
标签:中指明 oat log ssi ora meta generate conf attribute
原文地址:https://www.cnblogs.com/jixiaohua/p/11986496.html