Stencil可以轻松构建丰富的交互式组件。
现在有以下几个装饰器:
每个组件都要用这个装饰器来装饰。
装饰器里最基本的要有一个tag元数据,当然,styleUrl也几乎是必须的。另外还有styleUrls,这个元数据可引用多个样式表。
import { Component } from '@stencil/core';
@Component({
tag: 'todo-list',
styleUrl: 'todo-list.scss'
})
export class TodoList {
...
}
此外还有可选的host元数据,它的作用是设置组件的属性或者class
import { Component } from '@stencil/core';
@Component({
tag: 'todo-list',
styleUrl: 'todo-list.scss',
host: {
theme: 'todo',
role: 'list'
}
})
当使用组件时,它会自动添加class属性和role的值
<todo-list class='todo' role='list'></todo-list>
感觉和ng的@Input一样,用于自定义属性。
如:
import { Prop } from '@stencil/core';
...
export class TodoList {
@Prop() color: string;
@Prop() favoriteNumber: number;
@Prop() isSelected: boolean;
@Prop() myHttpService: MyHttpService;
}
在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从组件内部进行改变,方法是将其声明为可变的,如下例所示:
import { Prop } from '@stencil/core';
...
export class NameElement {
@Prop({ mutable: true }) name: string = 'Stencil';
componentDidLoad() {
this.name = 'Stencil 0.7.0';
}
}
如下所示,name的值默认为Stencil。
要对其验证其输入,可使用@watch装饰器。
import { Prop, Watch } from '@stencil/core';
...
export class TodoList {
@Prop() name: string = 'Stencil';
// 当值改变时,验证其是否为空,以及是否长度小于2
@Watch('name')
validateName(newValue: string, oldValue: string) {
const isBlank = typeof newValue == null;
const atLeast2chars = typeof newValue === 'string' && newValue.length >= 2;
if (isBlank) { throw new Error('name: required') };
if ( !atLeast2chars ) { throw new Error('name: atLeast2chars') };
}
}
...
当用户改变prop时,会触发watch的监听,并调用函数。像上面用到的那样。
@State()装饰可用于为组件管理的内部数据。这意味着用户不能从组件外部修改属性。对@State()属性的任何更改都会导致再次调用组件reader函数。
import { State } from '@stencil/core';
...
export class TodoList {
@State() completedTodos: Todo[];
// 在这个方法里改变了State装饰的属性,那么将触发reader函数的调用
completeTodo(todo: Todo) {
// This will cause our render function to be called again
this.completedTodos = [...this.completedTodos, todo];
}
render() {
//
}
}
@Method()装饰用于定义组件的公共接口。用@Method()装饰器装饰的函数可以直接从元素中调用。
import { Method } from '@stencil/core';
...
export class TodoList {
@Method()
showPrompt() {
// show a prompt
}
}
获取到组件后便可调用其方法,很有用的样子。
const todoListElement = document.querySelector('todo-list');
todoListElement.showPrompt();
这个不太懂,获取到HTMLElement实例?
import { Element } from '@stencil/core';
...
export class TodoList {
@Element() todoListEl: HTMLElement;
addClass(){
this.todoListEl.classList.add('active');
}
}
与ng或Ionic不同的是,嵌套组件时不用显示地导入子组件,因为子组件也是原生HTML标签。直接在父组件直接使用即可。
import { Component } from '@stencil/core';
@Component({
tag: 'my-parent-component'
})
export class MyParentComponent {
render() {
return (
<div>
// 这是子组件,无需导入再使用
<my-embedded-component color="red"></my-embedded-component>
</div>
);
}
}