大纲
Decorators 装饰器
- @Component() 生命一个新的web组件
- @Prop() 声明一个公开的属性
- @State() 声明组件的内部状态
- @Watch() 声明一个在属性或状态改变时运行的钩子
- @Element() 声明对宿主元素的引用
- @Method() 声明一个公开的公共方法
- @Event() 声明组件可能发出的 DOM 事件
- @Listen() 监听 DOM 事件
生命周期钩子

- connectedCallback()
- disconnectedCallback()
- componentWillLoad()
- componentDidLoad()
- componentShouldUpdate(newValue, oldValue, propName): boolean
- componentWillRender()
- componentDidRender()
- componentWillUpdate()
- componentDidUpdate()
- render()
应用加载事件
window.addEventListener('appload', (event) => {console.log(event.detail.namespace);});
其他(渲染方法)
- Host: Host 是一个功能性组件,可以在渲染函数的根部使用,为宿主元素本身设置属性和事件监听器。
- h(): 它用于render()将 JSX 转换为虚拟 DOM 元素。
- readTask(): 安排一个 DOM 读取任务。提供的回调将在执行 DOM 读取的最佳时刻执行,而不会导致布局抖动。
- writeTask(): 安排一个 DOM 写入任务。提供的回调将在执行 DOM 更改的最佳时刻执行,而不会导致布局抖动。
- forceUpdate(): forceUpdate()不是同步的,可能会在下一帧中执行 DOM 渲染。
- getAssetPath(): 获取Assets的路径
- setMode()
- getMode()
- getElement()
装饰器
Component
示例
import { Component } from '@stencil/core';@Component({tag: 'todo-list',styleUrl: 'todo-list.css'})export class TodoList {}
可选参数ß
@Component(opts: ComponentOptions)需要一个包含所有组件级功能的必需对象。
export interface ComponentOptions {/*** 标记名:全局唯一,必须包含"-"**/tag: string;/*** 样式作用域*/scoped?: boolean;/*** 是否使用本机阴影dom封装*/shadow?: boolean | { delegatesFocus: boolean };/*** 样式文件相对路径*/styleUrl?: string;/*** 为不同模块指定不同的样式表*/styleUrls?: string[] | d.ModeStyles;/*** 内联CSS,只支持css语法,不支持less和sass*/styles?: string;/*** 资源文件夹相对路径*/assetsDirs?: string[];/*** @deprecated Use `assetsDirs` instead*/assetsDir?: string;}
嵌套组件
通过将 HTML 标记添加到 JSX 代码,可以轻松组合组件。
示例:
import { Component, Prop, h } from '@stencil/core';@Component({tag: 'my-embedded-component'})export class MyEmbeddedComponent {@Prop() color: string = 'blue';render() {return (<div>My favorite color is {this.color}</div>);}}
Prop
Props 将数据从父组件向下传递到子组件。组件需要使用@Prop()装饰器显式声明它们期望接收的 Props 。可以是number, string, boolean,甚至是Object或Array
示例
// TodoList.tsximport { Prop } from '@stencil/core';import { MyHttpService } from '../some/local/directory/MyHttpService';...export class TodoList {@Prop() color: string;@Prop() favoriteNumber: number;@Prop() isSelected: boolean;@Prop() myHttpService: MyHttpService;}
在TodoList类中,Props 是通过this操作符访问的。
logColor() {console.log(this.color)}
在外部,Props设置在元素上。
在 HTML 中,您必须使用破折号-来设置属性:
<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); // MyHttpServiceconsole.log(todoListElement.color); // blue
可选参数
export interface PropOptions {attribute?: string;mutable?: boolean;reflect?: boolean;}
props 可变性
_默认情况下_Prop在组件逻辑内部是不可变的。一旦用户设置了一个值,组件就不能在内部更新它。但是,可以声明为mutable来显式允许从组件内部对 Prop 进行变异
import { Prop } from '@stencil/core';...export class NameElement {@Prop({ mutable: true }) name: string = 'Stencil';componentDidLoad() {this.name = 'Stencil 0.7.0';}}
Attribute 名称
可以使用装饰器的attribute选项更改此“默认”行为@Prop()。通过使用此选项,我们可以明确哪些属性具有关联的 DOM 属性及其名称。
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;}
Reflect Properties Values to Attributes
当“prop”设置为“reflect”时,这意味着它们的值将在 DOM 中作为 HTML 属性呈现:
@Prop({reflect: true})
@Component({ tag: 'my-cmp' })class Cmp {@Prop({ reflect: true }) message = 'Hello';@Prop({ reflect: false }) value = 'The meaning of life...';@Prop({ reflect: true }) number = 42;}
<my-cmp message="Hello" number="42"></my-cmp>
props默认值和验证
设置默认值
import { Prop } from '@stencil/core';...export class NameElement {@Prop() name: string = 'Stencil';}
验证prop可以使用@Watch() 装饰器
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') };}}
State
State装饰器用来管理内部组件,不能从外部修改。对@State()属性的任何更改都会导致组件render函数再次被调用。
示例
用@State定义一个属性open, @Listen响应点击事件切换的值。
import { Component, State, Listen, h } from '@stencil/core';@Component({tag: 'my-toggle-button'})export class MyToggleButton {@State() open: boolean;@Listen('click', { capture: true })handleClick() {this.open = !this.open;}render() {return <button>{this.open ? "On" : "Off"}</button>;}}
维护一个Todo类型值列表。
import { State } from '@stencil/core';type Todo = {done: boolean,description: string,}export class TodoList {@State() completedTodos: Todo[];completeTodo(todo: Todo) {// This will cause our render function to be called againthis.completedTodos = [...this.completedTodos, todo];}}
并非所有内部状态都可能需要用 装饰@State(),事实上,如果您确定该值不会更改或不需要触发重新渲染,则避免使用它是一个很好的做法
class Component {// If `cacheData` changes we don't want to rerender the component,// so we DON'T decorate it with @StatecacheData = SOME_BIG_DATA;// If this state change we want to run render() again@State() value;}
Event
生命周期
const el = document.createElement('my-cmp');document.body.appendChild(el);// connectedCallback() called// componentWillLoad() called (first time)el.remove();// disconnectedCallback()document.body.appendChild(el);// connectedCallback() called again, but `componentWillLoad()` is not.
**
