经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » JavaScript » 查看文章
stencilJs学习之构建 Drawer 组件
来源:cnblogs  作者:guojikun  时间:2023/9/1 8:48:09  对本文有异议

前言

在之前的学习中,我们已经掌握了 stencilJs 中的一些核心概念和基础知识,如装饰器 PropStateEventListenMethodComponent 以及生命周期方法。这些知识是构建复杂组件和应用的基础,而抽屉组件是一个很好的示例,能够综合运用这些知识,让我们更深入地理解它们的作用和用法。

为什么选择抽屉组件

为什么选择抽屉组件作为综合练习呢?因为抽屉组件是现代 Web 应用中常见的 UI 元素,具有以下特点:

  1. 交互性强:抽屉组件允许用户在不离开当前页面的情况下进行额外操作,因此它需要响应用户的交互行为,如打开、关闭等。
  2. 多状态管理:抽屉可以有多种状态,比如打开、关闭、正在拖拽等,这就需要使用 State 装饰器来管理和控制组件内部的状态。
  3. 属性传递:抽屉可能需要一些用户自定义的属性,如标题、内容、位置等。这就需要使用 Prop 装饰器来接收外部传递的数据。
  4. 自定义事件:抽屉的打开和关闭需要触发自定义事件,以便其他组件或应用能够响应状态变化。
  5. 方法调用:用户可能需要通过调用方法来控制抽屉的行为,例如通过点击按钮来打开或关闭抽屉,这就需要使用 Method 装饰器来定义公开方法。
  6. 生命周期方法:抽屉在不同的生命周期阶段可能需要执行特定的逻辑,例如组件初始化、渲染、卸载等。这就需要使用生命周期方法来实现这些逻辑。
  7. 可复用性:抽屉是一个通用的 UI 元素,在不同的场景中都可能被使用,因此需要设计良好的组件结构和接口,以实现高度的可复用性。

通过实际构建一个抽屉组件,我们能够在综合应用的背景下,更深入地理解这些概念的作用和相互关系。同时,这也为我们未来在实际项目中构建更复杂的组件和应用奠定了坚实的基础。抽屉组件的案例将帮助我们更好地运用 stencilJs 的知识,从而成为更有信心和能力的前端开发者。

实现抽屉组件

创建一个项目

使用以下的命令创建一个 Stencil 项目

  1. #使用 npm
  2. npm init stencil
  3. #使用 yarn
  4. yarn create stencil
  5. #使用 pnpm
  6. pnpm create stencil

创建成功,终端显示如下
Snipaste_2023-08-19_16-56-54.png

创建一个组件

Stencil 项目内置一个生成组件命令 generate,使用下面的命令生成一个组件

  1. #使用 npm
  2. npm run generate
  3. #使用 yarn
  4. yarn generate
  5. #使用 pnpm
  6. pnpm run generate

执行之后会让用户输入一个组件的名字(以-作为连字符),输入之后按回车键会让用户选择要生成的文件,选择之后按回车就能生成一个组件了。你可以在 src/components 目录下看到 ce-drawer, 如下图

image.png

实现组件

首先,创建组件的 HTML 结构:

  1. import { Host, h } from '@stencil/core';
  2. @Component({
  3. tag: 'ce-drawer',
  4. styleUrl: 'ce-drawer.css',
  5. shadow: true,
  6. })
  7. export class CeDrawer {
  8. renderHeader() {
  9. if (this.showHeader) {
  10. return (
  11. <div class="ivy-drawer-header">
  12. <slot name="header">{this.header}</slot>
  13. </div>
  14. );
  15. } else {
  16. return null;
  17. }
  18. }
  19. render() {
  20. return (
  21. <Host>
  22. <div class="ivy-mask"></div>
  23. <div class="ivy-drawer">
  24. {this.renderHeader()}
  25. <div class="ivy-drawer-body">
  26. <slot></slot>
  27. </div>
  28. </div>
  29. </Host>
  30. );
  31. }
  32. }

接下来,声明 prop

  1. import { Component, Event, EventEmitter, Host, Method, Prop, Watch, h } from '@stencil/core';
  2. @Component({
  3. tag: 'ce-drawer',
  4. styleUrl: 'ce-drawer.css',
  5. shadow: true,
  6. })
  7. export class CeDrawer {
  8. @Prop({
  9. attribute: 'show',
  10. mutable: true,
  11. reflect: true,
  12. })
  13. visible: Boolean = false;
  14. @Prop() width: string = '36%';
  15. @Prop({
  16. attribute: 'show-header',
  17. mutable: true,
  18. reflect: true,
  19. })
  20. showHeader: boolean = false;
  21. @Prop({
  22. attribute: 'header',
  23. })
  24. header: string = '';
  25. @Prop({
  26. attribute: 'mask-closable',
  27. mutable: true,
  28. reflect: true,
  29. })
  30. maskClosable: boolean = true;
  31. @Prop({
  32. attribute: 'placement',
  33. mutable: true,
  34. reflect: true,
  35. })
  36. placement: string = 'right';
  37. /**监听传入的 placement 是否符合要求*/
  38. @Watch('placement')
  39. validateName(val: string) {
  40. const flag = ['left', 'right', 'top', 'bottom'].includes(val);
  41. if (!flag) {
  42. throw new Error('placement 必须是 left/right/top/bottom 其中之一');
  43. }
  44. }
  45. renderHeader() {
  46. if (this.showHeader) {
  47. return (
  48. <div class="ivy-drawer-header">
  49. <slot name="header">{this.header}</slot>
  50. </div>
  51. );
  52. } else {
  53. return null;
  54. }
  55. }
  56. render() {
  57. return (
  58. <Host show={this.visible}>
  59. <div class="ivy-mask" onClick={this.maskClose.bind(this)}></div>
  60. <div
  61. class="ivy-drawer"
  62. style={{ width: ['left', 'right'].includes(this.placement) ? this.width : '100%', height: ['top', 'bottom'].includes(this.placement) ? this.width : '100%' }}
  63. >
  64. {this.renderHeader()}
  65. <div class="ivy-drawer-body">
  66. <slot></slot>
  67. </div>
  68. </div>
  69. </Host>
  70. );
  71. }
  72. }

接着,声明自定义事件和遮罩层点击事件:

  1. // ...
  2. maskClose() {
  3. if (this.maskClosable) {
  4. this.visible = false;
  5. }
  6. }
  7. @Event() closed: EventEmitter;
  8. closeHandler() {
  9. this.closed.emit();
  10. }

最后,声明外部可用的辅助方法,例如显示/关闭 Drawer 组件:

  1. // ...
  2. @Method()
  3. async open() {
  4. this.visible = true;
  5. }
  6. @Method()
  7. async close() {
  8. this.closeHandler();
  9. this.visible = false;
  10. }

源码

完整代码

原文链接:https://www.cnblogs.com/guojikun/p/17669894.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号