Stencil 組件使用 JSX
渲染,這是一種流行的宣告式模板語法,每個組件都有一個渲染函式,它回傳在運行時渲染到 DOM 的組件樹,
基礎用法
render
函式用于輸出將繪制到螢屏上的組件樹,
class MyComponent {
render() {
return (
<div>
<h1>Hello World</h1>
<p>This is JSX!</p>
</div>
);
}
}
在這個例子中,我們回傳了一個 div
,它有兩個子元素 h1
和 p
,
Host Element
如果你想修改宿主元素本身,比如向組件本身添加一個類或一個屬性,可以使用 Host
組件,
資料系結
組件經常需要渲染動態資料,要在 JSX
中執行此操作,請使用 {}
render() {
return (
<div>Hello {this.name}</div>
)
}
如果你熟悉 ES6 模板變數,JSX 變數和 ES6 非常相似,只是沒有
$
符號,
//ES6
`Hello ${this.name}`
//JSX
Hello {this.name}
條件
如果你想根據不同的條件渲染不同的內容,可以使用 if/else
來實作
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>
);
}
請注意:Stencil 重用 DOM 元素以獲得更好的性能,請看下面的代碼:
{
someCondition ? (
<my-counter initialValue=https://www.cnblogs.com/guojikun/archive/2023/06/21/{2} />
) : (
);
}
上面的代碼與下面的代碼完全相同:
<my-counter initialValue=https://www.cnblogs.com/guojikun/archive/2023/06/21/{someCondition ? 2 : 5} />
因此,如果某些條件發生了變化,my-counter
的內部狀態不會被重置,它的生命周期方法(如 componentWillLoad()
)也不會被觸發,相反,條件陳述句只會觸發同一個組件的更新,
如果你想在一個條件陳述句中銷毀并重新創建一個組件,你可以指定 key
屬性,這告訴 Stencil
,這些組件實際上是不同的兄弟組件:
{
someCondition ? (
<my-counter key="a" initialValue=https://www.cnblogs.com/guojikun/archive/2023/06/21/{2} />
) : (
);
}
這樣,如果某些條件發生變化,你會得到一個新的 my-counter
組件實體,它具有新的內部狀態,同時也將會同步運行生命周期 componentWillLoad()
和 componentDidLoad()
,
Slots
組件通常需要在其組件樹的特定位置動態渲染子組件,允許開發人員在使用我們的組件時提供子內容,我們的組件將子組件放置在適當的位置,
要做到這一點,您可以在 my-component
中使用 Slot
標簽,
// my-component.tsx
render() {
return (
<div>
<h2>A Component</h2>
<div><slot /></div>
</div>
);
}
然后,如果用戶在創建組件 my-component 時傳遞子組件,那么 my-component 將把該組件放在上面第二層的 div
中:
render(){
return(
<my-component>
<p>Child Element</p>
</my-component>
)
}
slot
可以增加 name
屬性,來決定內容的輸出位置:
// my-component.tsx
render(){
return [
<slot name="item-start" />,
<h1>Here is my main content</h1>,
<slot name="item-end" />
]
}
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>
)
}
Dealing with Children
JSX
中節點的子節點在運行時對應于一個節點陣列,無論它們是通過 array.prototype.map
跨陣列創建的,還是直接在 JSX
中宣告為兄弟節點,這意味著在運行時,下面兩個頂級
div
的子元素(.Todo-one 和.todo-two)的表示方式相同:
render() {
return (
<>
<div >
{this.todos.map((todo) => (
<span>{ todo.taskName }</span>
)}
</div>
<div >
<span>{ todos[0].taskName }</span>
<span>{ todos[1].taskName }</span>
</div>
</>
)
}
如果這個子元素陣列是動態的,即任何節點都可以被添加、洗掉或重新排序,那么最好為每個元素設定一個唯一的 key
屬性,如下所示:
render() {
return (
<div>
{this.todos.map((todo) =>
<div key={todo.uid}>
<div>{todo.taskName}</div>
</div>
)}
</div>
)
}
當子陣列中的節點被重新排列時,Stencil 會努力在渲染時保留 DOM 節點,但它不能在所有情況下都這樣做,設定一個 key
屬性可以讓 Stencil 確保在渲染時能夠匹配新舊子節點,從而避免
不必要地重新創建 DOM 節點,
不要使用陣列索引或其他非唯一值作為鍵,嘗試確保每個子節點都有一個不變的
key
,并且在其所有兄弟節點中是唯一的,
處理用戶輸入
Stencil 使用原生的 DOM 事件,
下面是一個處理按鈕點擊的例子,注意箭頭函式的使用,
...
export class MyComponent {
private handleClick = () => {
alert('Received the button click!');
}
render() {
return (
<button onClick={this.handleClick}>Click Me!</button>
);
}
}
這是另一個監聽輸入變化的例子,注意箭頭函式的使用,
...
export class MyComponent {
private inputChanged = (event: Event) => {
console.log('input changed: ', (event.target as HTMLInputElement).value);
}
render() {
return (
<input onChange={this.inputChanged}/>
);
}
}
復雜的模板內容(Complex Template Content)
到目前為止,我們已經看到了如何只回傳一個根元素的例子,我們也可以在根元素中嵌套元素
在組件有多個“頂級”元素的情況下,render 函式可以回傳一個陣列,注意 div
元素,
render() {
return ([
// first top level element
<div >
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>,
// second top level element, note the , above
<div >
... more html content ...
</div>
]);
}
或者你可以使用 Fragment
函陣列件,在這種情況下你不需要添加逗號:
import { Fragment } from '@stencil/core';
...
render() {
return (<Fragment>
// first top level element
<div >
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
<div >
... more html content ...
</div>
</Fragment>);
}
也可以使用 innerHTML
直接將內容行內到元素中,例如,當動態加載一個 svg
,然后想要在 div
中渲染它時,這就很有用了,這就像在普通的 HTML
中一樣:
<div innerHTML={svgContent}></div>
獲取 DOM 元素的參考
在 jsx
中使用 ref 屬性來獲取 dom
的參考,示例如下
@Component({
tag: "app-home",
})
export class AppHome {
textInput!: HTMLInputElement;
handleSubmit = (event: Event) => {
event.preventDefault();
console.log(this.textInput.value);
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input
type="text"
ref={(el) => (this.textInput = el as HTMLInputElement)}
/>
</label>
<input type="submit" value="https://www.cnblogs.com/guojikun/archive/2023/06/21/Submit" />
</form>
);
}
}
避免共享 JSX 節點
在 jsx 中應該避免共享 jsx 節點,每一個 jsx 節點應該都是唯一的,這是因為在再次渲染時會遇到問題,
@Component({
tag: 'my-cmp',
})
export class MyCmp {
render() {
- const sharedNode = <div>Text</div>;
return (
<div>
- {sharedNode}
- {sharedNode}
+ <div>Text</div>
+ <div>Text</div>
</div>
);
}
}
或者,可以創建一個工廠函式來回傳一個通用的 JSX 節點,因為回傳值將是一個唯一的實體, 示例如下:
@Component({
tag: "my-cmp",
})
export class MyCmp {
getText() {
return <div>Text</div>;
}
render() {
return (
<div>
{this.getText()}
{this.getText()}
</div>
);
}
}
結束語
至此,我們已經基本把 StencilJs
的相關基礎知識已經學習的差不多了,在下一個章節中將會使用之前學習到的知識來開發一個常用的組件,
由于我們只是使用 StencilJs
來開發 web component
組件,其它不想關的知識(router)便不再講解,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/555736.html
標籤:其他
下一篇:返回列表