stencilJs学习之构建 Drawer 组件

简介: 在之前的文字了我们一起学习了StencilJs的基础知识,现在我们就一起来实现一个组件吧!

前言

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

为什么选择抽屉组件

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

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

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

实现抽屉组件

创建一个项目

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

#使用 npm
npm init stencil
#使用 yarn
yarn create stencil
#使用 pnpm
pnpm create stencil

创建成功,终端显示如下
image.png

创建一个组件

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

#使用 npm
npm run generate
#使用 yarn
yarn generate
#使用 pnpm
pnpm run generate

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

实现组件

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

import { Host, h } from '@stencil/core';

@Component({
  tag: 'ce-drawer',
  styleUrl: 'ce-drawer.css',
  shadow: true,
})
export class CeDrawer {

  renderHeader() {
    if (this.showHeader) {
      return (
        <div class="ivy-drawer-header">
          <slot name="header">{this.header}</slot>
        </div>
      );
    } else {
      return null;
    }
  }

  render() {
    return (
      <Host>
        <div class="ivy-mask"></div>
        <div class="ivy-drawer">
          {this.renderHeader()}
          <div class="ivy-drawer-body">
            <slot></slot>
          </div>
        </div>
      </Host>
    );
  }
}

接下来,声明 prop


import { Component, Event, EventEmitter, Host, Method, Prop, Watch, h } from '@stencil/core';

@Component({
  tag: 'ce-drawer',
  styleUrl: 'ce-drawer.css',
  shadow: true,
})
export class CeDrawer {
    @Prop({
      attribute: 'show',
      mutable: true,
      reflect: true,
    })
    visible: Boolean = false;
    @Prop() width: string = '36%';

    @Prop({
        attribute: 'show-header',
        mutable: true,
        reflect: true,
    })
    showHeader: boolean = false;

    @Prop({
        attribute: 'header',
    })
    header: string = '';

    @Prop({
        attribute: 'mask-closable',
        mutable: true,
        reflect: true,
    })
    maskClosable: boolean = true;

    @Prop({
        attribute: 'placement',
        mutable: true,
        reflect: true,
    })
    placement: string = 'right';

    /**监听传入的 placement 是否符合要求*/
    @Watch('placement')
    validateName(val: string) {
        const flag = ['left', 'right', 'top', 'bottom'].includes(val);
        if (!flag) {
          throw new Error('placement 必须是 left/right/top/bottom 其中之一');
        }
    }

    renderHeader() {
        if (this.showHeader) {
          return (
            <div class="ivy-drawer-header">
              <slot name="header">{this.header}</slot>
            </div>
          );
        } else {
          return null;
        }
    }

    render() {
        return (
          <Host show={this.visible}>
            <div class="ivy-mask" onClick={this.maskClose.bind(this)}></div>
            <div
                class="ivy-drawer"
                style={
  
  { width: ['left', 'right'].includes(this.placement) ? this.width : '100%', height: ['top', 'bottom'].includes(this.placement) ? this.width : '100%' }}
            >
                {this.renderHeader()}

                <div class="ivy-drawer-body">
                    <slot></slot>
                </div>
            </div>
          </Host>
        );
    }
}

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

// ...
maskClose() {
    if (this.maskClosable) {
      this.visible = false;
    }
}

@Event() closed: EventEmitter;
closeHandler() {
    this.closed.emit();
}

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

// ...

@Method()
async open() {
    this.visible = true;
}
@Method()
async close() {
    this.closeHandler();
    this.visible = false;
}

源码

完整代码

相关文章
|
Java Shell Linux
Android——编译(二):android.mk的相关知识
Android——编译(二):android.mk的相关知识
714 0
|
设计模式 算法 Java
Springboot 使用设计模式- 策略模式
Springboot 使用设计模式- 策略模式
1084 0
Springboot 使用设计模式- 策略模式
|
搜索推荐 数据可视化 数据挖掘
基于Python flask框架的招聘数据分析推荐系统,有数据推荐和可视化功能
本文介绍了一个基于Python Flask框架的招聘数据分析推荐系统,该系统具备用户登录注册、数据库连接查询、首页推荐、职位与城市分析、公司性质分析、职位需求分析、用户信息管理以及数据可视化等功能,旨在提高求职者的就业效率和满意度,同时为企业提供人才匹配和招聘效果评估手段。
493 0
基于Python flask框架的招聘数据分析推荐系统,有数据推荐和可视化功能
|
11月前
|
存储 关系型数据库 数据库
轻量级数据库的利器:Python 及其内置 SQLite 简介
轻量级数据库的利器:Python 及其内置 SQLite 简介
334 3
|
10月前
|
C++
vs code常见的查找快捷键大全
【11月更文挑战第1天】本文介绍了 VS Code 中的基本查找和替换操作,包括在当前文件中查找(Ctrl + F)、查找替换(Ctrl + H)、查找下一个(F3)和查找上一个(Shift + F3)。还涵盖了在多个文件中查找(Ctrl + Shift + F)和查找替换(Ctrl + Shift + H),以及符号查找相关操作,如转到符号(Ctrl + T)和在文件中查找符号(Ctrl + Shift + O)。这些快捷键和功能帮助用户高效地管理和编辑代码。
1568 2
|
缓存 监控 NoSQL
Redis在减轻数据库压力中的关键角色
**摘要:** 本文介绍了Redis如何减轻数据库压力。Redis作为高性能内存数据库,利用其缓存热点数据、异步处理、分布式锁和数据聚合功能降低数据库负载。实践中,应合理设置缓存策略,优化数据结构和查询,监控告警并进行扩容容灾,以确保系统性能和稳定性。
458 4
|
NoSQL Go API
简洁、轻量级的 Go API 框架
简洁、轻量级的 Go API 框架
186 0
|
11月前
|
存储 前端开发 Java
springboot整合最新版minio和minio的安装(完整教程,新人必看)
本文详细介绍了如何使用Docker安装配置最新版的MinIO,并展示了如何在Spring Boot应用中整合MinIO以及如何通过前端进行文件上传测试。
1233 3
springboot整合最新版minio和minio的安装(完整教程,新人必看)
HOSTAPD ht_capab设置
HOSTAPD ht_capab设置
479 1
|
容器 Perl Kubernetes
深入 Kubernetes 网络:实战K8s网络故障排查与诊断策略
本文介绍了Kubernetes网络的基础知识和故障排查经验,重点讨论了私有化环境中Kubernetes网络的挑战。首先,文章阐述了Kubernetes网络模型的三大核心要素:Pod网络、Service网络和CNI,并强调了其在容器通信和服务发现中的作用。接着,通过三个具体的故障案例,展示了网络冲突、主节点DNS配置更改导致的服务中断以及容器网络抖动问题的解决过程,强调了网络规划、配置管理和人员培训的重要性。最后,提到了KubeSkoop exporter工具在监控和定位网络抖动问题中的应用。通过这些案例,读者可以深入了解Kubernetes网络的复杂性,并学习到实用的故障排查方法。
148314 19