翼度科技»论坛 编程开发 JavaScript 查看内容

StencilJs 学习之 JSX

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
Stencil 组件使用 JSX 渲染,这是一种流行的声明式模板语法。每个组件都有一个渲染函数,它返回在运行时渲染到 DOM 的组件树。
基础用法

render 函数用于输出将绘制到屏幕上的组件树。
  1. class MyComponent {
  2.     render() {
  3.         return (
  4.             
  5.                 <h1>Hello World</h1>
  6.                 <p>This is JSX!</p>
  7.             
  8.         );
  9.     }
  10. }
复制代码
在这个例子中,我们返回了一个 div ,它有两个子元素 h1 和 p。
Host Element

如果你想修改宿主元素本身,比如向组件本身添加一个类或一个属性,可以使用 Host 组件。
数据绑定

组件经常需要渲染动态数据。要在 JSX 中执行此操作,请使用 {}
  1. render() {
  2.   return (
  3.     Hello {this.name}
  4.   )
  5. }
复制代码
如果你熟悉 ES6 模板变量,JSX 变量和 ES6 非常相似,只是没有 $ 符号。
  1. //ES6
  2. `Hello ${this.name}`
  3. //JSX
  4. Hello {this.name}
复制代码
条件

如果你想根据不同的条件渲染不同的内容,可以使用 if/else 来实现
  1. render() {
  2.   if (this.name) {
  3.     return ( Hello {this.name} )
  4.   } else {
  5.     return ( Hello, World )
  6.   }
  7. }
复制代码
此外,可以使用 JavaScript 的三元运算符来创建内联条件
  1. render() {
  2.   return (
  3.    
  4.     {this.name ? <p>Hello {this.name}</p> : <p>Hello World</p> }
  5.    
  6.   );
  7. }
复制代码
请注意:Stencil 重用 DOM 元素以获得更好的性能。请看下面的代码:
  1. {
  2.     someCondition ? (
  3.         <my-counter initialValue={2} />
  4.     ) : (
  5.         <my-counter initialValue={5} />
  6.     );
  7. }
复制代码
上面的代码与下面的代码完全相同:
  1. [/code]因此,如果某些条件发生了变化,my-counter的内部状态不会被重置,它的生命周期方法(如 componentWillLoad())也不会被触发。相反,条件语句只会触发同一个组件的更新。
  2. 如果你想在一个条件语句中销毁并重新创建一个组件,你可以指定 key 属性。这告诉 Stencil,这些组件实际上是不同的兄弟组件:
  3. [code]{
  4.     someCondition ? (
  5.         <my-counter initialValue={2} />
  6.     ) : (
  7.         <my-counter initialValue={5} />
  8.     );
  9. }
复制代码
这样,如果某些条件发生变化,你会得到一个新的 my-counter 组件实例,它具有新的内部状态,同时也将会同步运行生命周期 componentWillLoad()和 componentDidLoad()。
Slots

组件通常需要在其组件树的特定位置动态渲染子组件,允许开发人员在使用我们的组件时提供子内容,我们的组件将子组件放置在适当的位置。
要做到这一点,您可以在 my-component 中使用 Slot 标签。
  1. // my-component.tsx
  2. render() {
  3.   return (
  4.    
  5.       <h2>A Component</h2>
  6.       <slot />
  7.    
  8.   );
  9. }
复制代码
然后,如果用户在创建组件 my-component 时传递子组件,那么 my-component 将把该组件放在上面第二层的 div 中:
  1. render(){
  2.   return(
  3.     <my-component>
  4.       <p>Child Element</p>
  5.     </my-component>
  6.   )
  7. }
复制代码
slot 可以增加 name 属性,来决定内容的输出位置:
  1. // my-component.tsx
  2. render(){
  3.   return [
  4.     <slot name="item-start" />,
  5.     <h1>Here is my main content</h1>,
  6.     <slot name="item-end" />
  7.   ]
  8. }
  9. render(){
  10.   return(
  11.     <my-component>
  12.       <p slot="item-start">I'll be placed before the h1</p>
  13.       <p slot="item-end">I'll be placed after the h1</p>
  14.     </my-component>
  15.   )
  16. }
复制代码
Dealing with Children

JSX 中节点的子节点在运行时对应于一个节点数组,无论它们是通过 array.prototype.map 跨数组创建的,还是直接在 JSX 中声明为兄弟节点。这意味着在运行时,下面两个顶级
div 的子元素(.Todo-one 和.todo-two)的表示方式相同:
  1. render() {
  2.   return (
  3.     <>
  4.       
  5.         {this.todos.map((todo) => (
  6.           { todo.taskName }
  7.         )}
  8.       
  9.       
  10.         { todos[0].taskName }
  11.         { todos[1].taskName }
  12.       
  13.     </>
  14.   )
  15. }
复制代码
如果这个子元素数组是动态的,即任何节点都可以被添加、删除或重新排序,那么最好为每个元素设置一个唯一的 key 属性,如下所示:
  1. render() {
  2.   return (
  3.    
  4.       {this.todos.map((todo) =>
  5.         
  6.           {todo.taskName}
  7.         
  8.       )}
  9.    
  10.   )
  11. }
复制代码
当子数组中的节点被重新排列时,Stencil 会努力在渲染时保留 DOM 节点,但它不能在所有情况下都这样做。设置一个 key 属性可以让 Stencil 确保在渲染时能够匹配新旧子节点,从而避免
不必要地重新创建 DOM 节点。
不要使用数组索引或其他非唯一值作为键。尝试确保每个子节点都有一个不变的 key,并且在其所有兄弟节点中是唯一的。
处理用户输入

Stencil 使用原生的 DOM 事件。
下面是一个处理按钮点击的例子。注意箭头函数的使用。
  1. ...
  2. export class MyComponent {
  3.   private handleClick = () => {
  4.     alert('Received the button click!');
  5.   }
  6.   render() {
  7.     return (
  8.       <button onClick={this.handleClick}>Click Me!</button>
  9.     );
  10.   }
  11. }
复制代码
这是另一个监听输入变化的例子。注意箭头函数的使用。
  1. ...
  2. export class MyComponent {
  3.   private inputChanged = (event: Event) => {
  4.     console.log('input changed: ', (event.target as HTMLInputElement).value);
  5.   }
  6.   render() {
  7.     return (
  8.       <input onChange={this.inputChanged}/>
  9.     );
  10.   }
  11. }
复制代码
复杂的模板内容(Complex Template Content)

到目前为止,我们已经看到了如何只返回一个根元素的例子。我们也可以在根元素中嵌套元素
在组件有多个“顶级”元素的情况下,render 函数可以返回一个数组。注意 div 元素。
  1. render() {
  2.   return ([
  3.   // first top level element
  4.   
  5.     <ul>
  6.       <li>Item 1</li>
  7.       <li>Item 2</li>
  8.       <li>Item 3</li>
  9.     </ul>
  10.   ,
  11.   // second top level element, note the , above
  12.   
  13.     ... more html content ...
  14.   
  15.   ]);
  16. }
复制代码
或者你可以使用 Fragment 函数组件,在这种情况下你不需要添加逗号:
  1. import { Fragment } from '@stencil/core';
  2. ...
  3. render() {
  4.   return (<Fragment>
  5.     // first top level element
  6.    
  7.       <ul>
  8.         <li>Item 1</li>
  9.         <li>Item 2</li>
  10.         <li>Item 3</li>
  11.       </ul>
  12.    
  13.    
  14.       ... more html content ...
  15.    
  16.   </Fragment>);
  17. }
复制代码
也可以使用 innerHTML 直接将内容内联到元素中。例如,当动态加载一个 svg,然后想要在 div 中渲染它时,这就很有用了。这就像在普通的 HTML 中一样:
  1. [/code][size=5]获取 DOM 元素的引用[/size]
  2. 在 jsx 中使用 ref 属性来获取 dom 的引用,示例如下
  3. [code]@Component({
  4.     tag: "app-home",
  5. })
  6. export class AppHome {
  7.     textInput!: HTMLInputElement;
  8.     handleSubmit = (event: Event) => {
  9.         event.preventDefault();
  10.         console.log(this.textInput.value);
  11.     };
  12.     render() {
  13.         return (
  14.             <form onSubmit={this.handleSubmit}>
  15.                 <label>
  16.                     Name:
  17.                     <input
  18.                         type="text"
  19.                         ref={(el) => (this.textInput = el as HTMLInputElement)}
  20.                     />
  21.                 </label>
  22.                 <input type="submit" value="Submit" />
  23.             </form>
  24.         );
  25.     }
  26. }
复制代码
避免共享 JSX 节点

在 jsx 中应该避免共享 jsx 节点,每一个 jsx 节点应该都是唯一的,这是因为在再次渲染时会遇到问题。
  1. @Component({
  2.   tag: 'my-cmp',
  3. })
  4. export class MyCmp {
  5.   render() {
  6. -    const sharedNode = Text;
  7.     return (
  8.       
  9. -        {sharedNode}
  10. -        {sharedNode}
  11. +        Text
  12. +        Text
  13.       
  14.     );
  15.   }
  16. }
复制代码
或者,可以创建一个工厂函数来返回一个通用的 JSX 节点,因为返回值将是一个唯一的实例。 示例如下:
  1. @Component({
  2.     tag: "my-cmp",
  3. })
  4. export class MyCmp {
  5.     getText() {
  6.         return Text;
  7.     }
  8.     render() {
  9.         return (
  10.             
  11.                 {this.getText()}
  12.                 {this.getText()}
  13.             
  14.         );
  15.     }
  16. }
复制代码
结束语

至此,我们已经基本把 StencilJs 的相关基础知识已经学习的差不多了,在下一个章节中将会使用之前学习到的知识来开发一个常用的组件。
由于我们只是使用 StencilJs 来开发 web component 组件,其它不想关的知识(router)便不再讲解。

来源:https://www.cnblogs.com/guojikun/p/17495330.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具