属性装饰器
Props 是在标签上拥有向组件内部传值功能的自定义属性。子组件不应该关心或引用父组件的值,因此应该使用
Props 将数据从父组件向下传递到子组件。组件需要使用
@Prop() 装饰器显式声明它们期望接收的
Props。可以是 number,
string, boolean,
Object 或者 Array。默认情况下,当设置了用
@Prop() 装饰器装饰的属性时,组件将重新渲染。
import { Prop } from '@stencil/core';
...
export class TodoList {
@Prop() color: string;
@Prop() favoriteNumber: number;
@Prop() isSelected: boolean;
@Prop() myHttpService: MyHttpService;
} 在TodoList 类中,可以通过this 操作符访问Props。
logColor() {
console.log(this.color)
} 在外部 Props 设置在元素上。
在 HTML 中,设置属性必须要使用 dash-case 的方式命名:
<todo-list color="blue" favorite-number="24" is-selected="true"></todo-list> 在 JSX 中设置属性使用驼峰命名:
<todo-list color="blue" favoriteNumber={24} isSelected="true"></todo-list> 它们也可以通过 JS 获取元素访问。
const todoListElement = document.querySelector('todo-list');
console.log(todoListElement.myHttpService); // MyHttpService
console.log(todoListElement.color); // blue
Prop 配置
@Prop(opts?: PropOptions) 装饰器接受一个可选参数来指定某些选项,例如
mutability、DOM 属性的名称或该属性的值是否应该展示到DOM。
export interface PropOptions {
attribute?: string;
mutable?: boolean;
reflect?: boolean;
}
Prop 值的变化
Prop 在组件逻辑内部
默认 是不可变的。一旦用户在外部设置了一个值,组件就不能在内部更新它。
但是,可以通过将 Prop 声明为
mutable 来明确允许从组件内部改变 Prop,如下例所示:
import { Prop } from '@stencil/core';
...
export class NameElement {
@Prop({ mutable: true }) name: string = 'Stencil';
componentDidLoad() {
this.name = 'Stencil 0.7.0';
}
} properties 和 attributes
properties 和组件 attributes 有很强的联系,但不一定是一回事。attributes 是一个 HTML 概念,而 properties 是面向对象编程中固有的 JS 概念。
在 Stencil 中,应用于 property 的
@Prop() 装饰器将设置 Stencil 编译器也监听 DOM
attribute 的变化。
通常属性的 property 与属性的
attribute 相同,但情况并非总是如此。以下组件为例:
import { Component, Prop } from '@stencil/core';
@Component({ tag: 'my-cmp' })
class Component {
@Prop() value: string;
@Prop() isValid: boolean;
@Prop() controller: MyController;
} 该组件有 3 个 properties,但编译器将仅创建 2 个 attributes:value 和 is-valid。
<my-cmp value="Hello" is-valid></my-cmp> 请注意,controller 类型不是原始类型,因为 DOM 属性只能是字符串,所以关联 DOM 属性
controller 是没有意义的。
同时,isValid 属性遵循
camelCase 命名,但 attributes 不区分大小写,因此属性名称默认为is-valid。
幸运的是,可以使用@Prop() 装饰器的 attribute 选项更改这种“默认”行为:
import { Component, Prop } from '@stencil/core';
@Component({ tag: 'my-cmp' })
class Component {
@Prop() value: string;
@Prop({ attribute: 'valid' }) isValid: boolean;
@Prop({ attribute: 'controller' }) controller: MyController;
} 通过使用此选项,我们可以明确哪些 properties 具有关联的 DOM
attribute 及其名称。
将 Properties 值同步到 Attributes
在某些情况下,保持
Prop 与属性同步可能很有用。在这种情况下,您可以将
@Prop() 装饰器中的
reflect 选项设置为 true,因为它默认为
false:
@Prop({
reflect: true
}) 当 prop 设置为
reflect 时,这意味着它们的值将在 DOM 中作为 HTML 属性渲染:
以下组件为例:
@Component({ tag: 'my-cmp' })
class Cmp {
@Prop({ reflect: true }) message = 'Hello';
@Prop({ reflect: false }) value = 'The meaning of life...';
@Prop({ reflect: true }) number = 42;
}
当在 DOM 中渲染时,是这样的:
<my-cmp message="Hello" number="42"></my-cmp> 请注意,设置为reflect(true) 的属性呈现为
attributes,而未设置为“reflect”的属性则不会。
虽然未设置为reflect”的属性,例如“value”,不会呈现为 attributes,但这并不意味着它不存在 - property
value 的值仍然为
The meaning of life... :
const cmp = document.querySelector('my-cmp');
console.log(cmp.value); // it prints 'The meaning of life...'
Prop 默认值和监听
设置一个默认值:
import { Prop } from '@stencil/core';
...
export class NameElement {
@Prop() name: string = 'Stencil';
}
要监听 Prop,可以使用
import { Prop, Watch } from '@stencil/core';
...
export class TodoList {
@Prop() name: string = 'Stencil';
@Watch('name')
validateName(newValue: string, oldValue: string) {
const isBlank = typeof newValue !== 'string' || newValue === '';
const has2chars = typeof newValue === 'string' && newValue.length >= 2;
if (isBlank) { throw new Error('name: required') };
if (!has2chars) { throw new Error('name: has2chars') };
}
}
Contributors
Thanks for your interest!
We just need some basic information so we can send the guide your way.