Stencil组件使用jsx(一种流行的声明性模板语法)来呈现。每个组件都有一个render函数,这个函数返回在运行时要呈现给dom的组件树。
基本用法
class MyComponent {
render() {
return (
<div>
<h1>Hello World</h1>
<p>This is JSX!</p>
</div>
);
}
}
在这个例子中,返回了div的jsx表示,并带有两个子元素:h1和p。
数据绑定
组件通常需要动态的呈现数据。在jsx中,使用{}来包含变量:
render() {
return (
<div>Hello {this.name}</div>
)
}
这类似与Ionic的插值表达式{{}},但有所不同的是:
1.使用一个大括号,2.要用this指向
条件语句
如果想要有条件地渲染不同的内容,可以简单地使用javascript if / else语句:下面例子表示,如果没有定义name属性,那将返回<div>Hello, World</div> 。
render() {
if (this.name) {
return ( <div>Hello {this.name}</div> )
} else {
return ( <div>Hello, World</div> )
}
}
此外,还可以使用javascript的三元运算符:
render() {
return (
<div>
{this.name
? <p>Hello {this.name}</p>
: <p>Hello World</p>
}
</div>
);
}
Slots:插槽
与ng的组件不一样的是,ng组件的结构是写死的了,只是通过输入属性来改变内容。
当组件需要在其组件树中的特定位置动态的呈现子组件时,可以在使用组件时提供不同的子组件,同时父组件将把子组件放置在适当的位置。那具体放到哪呢?就要用到Slots标签。例子:
// my-component.tsx
render() {
return (
<div>
<h2>A Component</h2>
<div><slot /></div>
</div>
);
}
然后,如果在创建组件my-component时传递子组件,那么my-component会把子组件放置在上面的第二个<div>中(也就是<slot/>的位置):
render(){
return(
<my-component>
<p>Child Element</p>
</my-component>
)
}
即:
render(){
return(
<div>
<h2>A Component</h2>
<div><p>Child Element</p></div>
</div>
)
}
Slots还可以指定名称以用来指定Slots输出的位置:
// my-component.tsx
render(){
return [
<slot name="item-start" />,
<h1>Here is my main content</h1>,
<slot name="item-end" />
]
}
// other-component.tsx
render(){
return(
<my-component>
<p slot="item-start">I'll be placed before the h1</p>
<p slot="item-end">I'll be placed after the h1</p>
</my-component>
)
}
循环
jsx中还可以使用循环语句,传统循环(for),甚至使用数组运算符(如map)。在下面的例子中,组件已有一个todos的属性,它是todo对象数组。使用数组的map函数来遍历。
render() {
return (
<div>
{this.todos.map((todo) =>
<div>
<div>{todo.taskName}</div>
<div>{todo.isCompleted}</div>
</div>
)}
</div>
)
}
处理用户输入
Stencil使用原生dom事件。这里是一个处理按钮点击的例子。注意箭头函数。
export class MyComponent {
handleClick(event: UIEvent) {
alert('Received the button click!');
}
render() {
return (
<button onClick={ (event: UIEvent) => this.handleClick(event)}>Click Me!</button>
);
}
}
也等同于:
handleClick(event: UIEvent) {
alert('Received the button click!');
}
render() {
return (
<button onClick={this.handleClick.bind(this)}>Click Me!</button>
);
}
更复杂的模板内容
有一点还没说到的是:render返回的组件必须只有一个顶级元素
render() {
return (
<div>div1</div>
<div>div2</div>
);
}
这里两个div都是顶级,这是不允许的。那么如果想要返回多个“顶级”元素呢?render函数还可以返回一个数组!注意<div>元素之间的逗号。
render() {
return ([
// first top level element
<div class="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>,
// second top level element, note the , above
<div class="another-container">
... more html content ...
</div>
]);
}
此外,还可以使用innerHTML将内容直接内嵌到元素中。例子:
<div innerHTML={svgContent}></div>
这很方便啊,不用获取到div来修改innerHTML,直接改变svgContent属性即可。