React+TS前台项目实战(十九)-- 全局常用组件封装:带加载状态和清除等功能的Input组件实现

news2024/11/23 11:02:27

文章目录

  • 前言
  • Input组件
    • 1. 功能分析
    • 2. 代码+详细注释
    • 3. 使用方式
    • 4. 效果展示
  • 总结


前言

今天我们来封装一个input输入框组件,并提供一些常用的功能,你可以选择不同的 尺寸添加前缀显示加载状态触发回调函数自定义样式 等等。这些功能在这个项目中已经足够了,无论你是一个经验丰富的开发者还是一个刚刚入门的新手,这篇文章都将提供有用的知识和实践经验,以帮助你在自己项目中封装输入框时更加高效


Input组件

1. 功能分析

(1)通过传入loading加载状态属性,当激活时会显示加载图标
(2)通过传入size属性, 可以有不同的大小:“default”、“small” 或 “large”
(3)提供onChange值发生变化回调函数;失去焦点onBlur回调函数;键盘回车onKeyUp回调函数;
(4)当输入框有值时,组件会显示一个清除按钮,用户可以通过点击按钮来清除输入框的值
(5)通过传入className属性, 可以自定义输入框的样式
(6)通过 elprops 属性将其他属性传递给底层的 input 元素

2. 代码+详细注释

// @/components/Input/index.tsx
import { FC, ReactNode, useCallback, useState, ChangeEventHandler, FocusEvent, ComponentPropsWithoutRef, KeyboardEventHandler } from "react";
import classNames from "classnames";
import { InputContainer } from "./styled";
import { ReactComponent as SearchIcon } from "./assets/search.svg";
import { ReactComponent as LoadingIcon } from "./assets/loading.svg";
import { ReactComponent as ClearIcon } from "./assets/clear.svg";
import SimpleButton from "@/components/SimpleButton";

// 组件的属性类型
type Props = Omit<ComponentPropsWithoutRef<"input">, "size"> & {
  // 按下回车的回调
  onEnter?: () => void;
  // 是否显示加载状态
  loading?: boolean;
  // 输入框大小
  size?: "default" | "small" | "large" | undefined;
  // 输入框前缀
  prefix?: boolean | ReactNode;
};

// 输入框组件
const Input: FC<Props> = ({ loading, size, onEnter, value: propsValue, onChange: propsOnChange, onKeyUp: propsOnKeyUp, onBlur: propsOnBlur, className, ...elprops }) => {
  // 输入框的值,通过状态管理
  const [value, setValue] = useState(propsValue);

  // 输入事件
  const handlerChange: ChangeEventHandler<HTMLInputElement> = useCallback(
    (event) => {
      // 如果正在加载,直接返回
      if (loading) {
        return;
      }
      // 更新状态和回调
      setValue(event.target.value);
      propsOnChange?.(event);
    },
    [propsOnChange, setValue, loading]
  );

  // 回车事件
  const onKeyUp: KeyboardEventHandler<HTMLInputElement> = useCallback(
    (event) => {
      // 如果是回车键,触发回调
      const isEnter = event.keyCode === 13;
      if (isEnter) {
        onEnter?.();
      }
      propsOnKeyUp?.(event);
    },
    [onEnter, propsOnKeyUp]
  );

  // 失去焦点事件
  const onBlur = useCallback(
    (event: FocusEvent<HTMLInputElement>) => {
      propsOnBlur?.(event);
    },
    [propsOnBlur]
  );

  return (
    <InputContainer className={classNames(className)} size={size}>
      {/* 加载状态图标 */}
      {loading ? <LoadingIcon className={classNames("input-loading-icon")} /> : <SearchIcon className={classNames("input-search-icon")} />}
      {/* 输入框 */}
      <input enterKeyHint="search" value={value} onChange={handlerChange} onKeyUp={onKeyUp} onBlur={onBlur} {...elprops} />
      {/* 清除按钮 */}
      {value && (
        <SimpleButton className={classNames("input-clear-icon")} title="clear" onClick={() => setValue("")}>
          <ClearIcon />
        </SimpleButton>
      )}
    </InputContainer>
  );
};

export default Input;
------------------------------------------------------------------------------
// @/components/Input/styled.tsx
import styled from "styled-components";
import variables from "@/styles/variables.module.scss";
type InputProps = {
  size: "default" | "small" | "large" | undefined;
};
export const InputContainer = styled.div<InputProps>`
  @keyframes rotate {
    100% {
      transform: rotate(360deg);
    }
  }
  position: relative;
  margin: 0 auto;
  width: 100%;
  height: ${({ size }) => {
    if (size === "default") return "var(--cd-input-height)";
    else if (size === "small") return "var(--cd-input-sm-height)";
    else return "var(--cd-input-large-height)";
  }};
  padding-right: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: white;
  border: 0 solid white;
  border-radius: 4px;
  input {
    position: relative;
    width: 100%;
    height: 100%;
    font-size: 14px;
    padding: 0 8px;
    background: #fff;
    color: #333;
    border: 0 solid #fff;
    border-radius: 5px;
    &:focus {
      color: #333;
      outline: none;
    }
    &::placeholder {
      color: #888;
    }
    @media (max-width: ${variables.mobileBreakPoint}) {
      font-size: 12px;
      width: 100%;
      padding-left: 6px;
      padding-right: 16px;
    }
  }
  .input-loading-icon,
  .input-search-icon {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    margin-left: 8px;
  }
  .input-loading-icon {
    animation: rotate 2s linear infinite;
  }
  .input-clear-icon {
    display: flex;
    align-items: center;
    flex-shrink: 0;
  }
`;

3. 使用方式

// 引入组件
import Input from '@/components/Input'
// 使用
const [loading, setLoading] = useState(false);
const [searchkeyword, setSearchkeyword] = useState("");
{/* 输入框值变化回调事件 */}
const onInputChange: ChangeEventHandler<HTMLInputElement> = (event) => {
  console.log("onInputChange", event.target.value);
  setSearchkeyword(event.target.value);
};
{/* 失焦回调事件 */}
const onInputBlur = () => {};
{/* 小尺寸,不带loading */}
<Input placeholder="请输入" size="small" />
{/* 标准尺寸,带loading */}
<Input placeholder="请输入" loading={loading} onChange={onInputChange} onBlur={onInputBlur} />
{/* 大尺寸,不带loading */}
<Input placeholder="请输入" size="large" />
{/* 带前缀 */}
<Input hasPrefix placeholder="请输入" loading={loading}} />
{/* 不带前缀 */}
<Input placeholder="请输入" loading={loading} onChange={onInputChange} onBlur={onInputBlur} />

4. 效果展示

(1)输入后,加载效果如下
注:如请求数据时添加加载状态,请求结束后取消加载状态

在这里插入图片描述

(2)点击清除按钮,清除数据效果

在这里插入图片描述

(3)三种尺寸显示如下

在这里插入图片描述
(4)带前缀 / 不带前缀效果
在这里插入图片描述


总结

下一篇讲【全局常用Search组件封装】。关注本栏目,将实时更新。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1877236.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JAVA高级进阶13单元测试、反射、注解

第十三天、单元测试、反射、注解 单元测试 介绍 单元测试 就是针对最小的功能单元(方法)&#xff0c;编写测试代码对其进行正确性测试 咱们之前是如何进行单元测试的&#xff1f; 有啥问题 &#xff1f; 只能在main方法编写测试代码&#xff0c;去调用其他方法进行测试。 …

老牌开源解压缩工具 7-Zip 24.07 更新发布

数据的压缩与解压已成为日常操作中不可或缺的一部分&#xff0c;无论是为了节省存储空间、加速文件传输&#xff0c;还是方便管理和归档。在众多压缩工具中&#xff0c;7-Zip 以其开源免费、高效能和强大的压缩率脱颖而出&#xff0c;成为众多用户的首选。 开发历史 7-Zip 由 …

【效率提升】新一代效率工具平台utools

下载地址&#xff1a;utools uTools这款软件&#xff0c;是一款功能强大且高度可定制的效率神器&#xff0c;使用快捷键alt space(空格) 随时调用&#xff0c;支持调用系统应用、用户安装应用和市场插件等。 utools可以调用系统设置和内置应用&#xff0c;这样可以方便快捷的…

基于Java的地方废物回收机构管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java技术&#xff0c;MIS的总体思想&#xff0c;MySQL数据库 工具&#xff1a;Eclipse&#xff0c;…

【计算机毕业设计】073智慧旅游平台开发微信小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

信息发布小程序h5 uniapp thinkphp

纯手工uniapp thinkphp 全开源打造 信息发布小程序 一、概述 信息发布小程序是一种基于微信平台的小程序应用&#xff0c;旨在为用户提供便捷的信息发布与展示服务。用户可以通过该小程序快速发布各类信息&#xff0c;如招聘、寻物、公告等&#xff0c;同时也可以浏览和搜索…

20240629在飞凌的OK3588-C开发板的Linux R4系统下使用i2cdetect确认I2C总线

rootok3588:/# i2cdetect -y -r 0 rootrk3588-buildroot:/# i2cdetect -l rootrk3588-buildroot:/# i2cdetect -F 0 20240629在飞凌的OK3588-C开发板的Linux R4系统下使用i2cdetect确认I2C总线 2024/6/29 15:37 在CAM1、CAM2挂载OV13850。 在CAM3、CAM4和CAM5挂载OV5645了。 in…

Day38:LeedCode 1049. 最后一块石头的重量 II 494. 目标和 474.一和零

1049. 最后一块石头的重量 II 有一堆石头&#xff0c;用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合&#xff0c;从中选出任意两块石头&#xff0c;然后将它们一起粉碎。假设石头的重量分别为 x 和 y&#xff0c;且 x < y。那么粉碎的可能结果…

HuatuoGPT2本地运行失败

transformer 版本不能太高 transformer<4.3.32 查看config.json文件 其实 https://huggingface.co/FreedomIntelligence/HuatuoGPT2-7B/blob/main/config.json

os实训课程模拟考试(大题复习)

目录 一、Linux操作系统 &#xff08;1&#xff09;第1关&#xff1a;Linux初体验 &#xff08;2&#xff09;第2关&#xff1a;Linux常用命令 &#xff08;3&#xff09;第3关&#xff1a;Linux 查询命令帮助语句 二、Linux之进程管理—&#xff08;重点&#xff09; &…

MySQL 12种锁:真实业务与流程图解析

文章目录 1. 表级锁&#xff08;Table Lock&#xff09;场景1&#xff1a;全表扫描统计 2. 行级锁&#xff08;Row Lock&#xff09;场景2&#xff1a;修改特定用户信息 3. 全局锁&#xff08;Global Lock&#xff09;场景3&#xff1a;数据备份 4. 意向锁&#xff08;Intent L…

数字黄金 vs 全球计算机:比特币与以太坊现货 ETF 对比

撰文&#xff1a;Andrew Kang 编译&#xff1a;J1N&#xff0c;Techub News 本文来源香港Web3媒体&#xff1a;Techub News 比特币现货 ETF 的通过为许多新买家打开了进入加密货币市场的大门&#xff0c;让他们可以在投资组合中配置比特币。但以太坊现货 ETF 的通过&#xf…

关于StringTokenizer使用详解

近日在项目中遇到一个使用StringTokenizer进行字符串分割的操作&#xff0c;以前按一定分隔符分割字符串都是用String[] result string.split("分隔符"&#xff09;&#xff0c;然后遍历result得到逐个分割后的元素。既然java给我提供了现有的类&#xff0c;我们何不…

【分布式系列】分布式锁的设计与实现

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

C语言中的基础指针操作

在C语言中&#xff0c;指针是一个非常重要的概念&#xff0c;它提供了直接访问内存地址的能力。指针变量用于存储内存地址&#xff0c;而不是数据值&#xff0c;在某种意义上和门牌号具有相似含义&#xff1a;指针是一个变量&#xff0c;其存储的是另一个变量的内存地址&#x…

成品视频素材下载网站有哪些?剪辑好可以用的视频素材网站分享

对于初学者在制作短视频时&#xff0c;常常希望能够快速获取高质量的素材。如果你正计划从事短视频创作&#xff0c;这里推荐几个优秀的成品素材网站&#xff0c;希望能对你有所帮助。 首先推荐的是蛙学网 作为国内用户首选的成品视频素材平台之一。这里提供丰富的视频素材库&…

大数据面试题之Spark(1)

目录 Spark的任务执行流程 Spark的运行流程 Spark的作业运行流程是怎么样的? Spark的特点 Spark源码中的任务调度 Spark作业调度 Spark的架构 Spark的使用场景 Spark on standalone模型、YARN架构模型(画架构图) Spark的yarn-cluster涉及的参数有哪些? Spark提交jo…

2.ROS串口安装和调试

首先安装串口依赖 sudo apt-get install ros-melodic-serial 其次安装串口调试助手 sudo apt-get install minicom 再赋予串口权限 sudo chmod 777 /dev/ttyTHS1 打开调试助手 sudo cutecom 硬件引脚图&#xff1a;

LangChain真的好用吗?谈一下LangChain封装FAISS的一些坑

最近在做一个知识库问答项目&#xff0c;就是现在大模型浪潮下比较火的 RAG 应用。LangChain 可以说是 RAG 最受欢迎的工具&#xff0c;因此我首选 LangChain 来快速构建我的应用。坦白来讲 LangChain 本身一套对于组件的定义已经让我感觉很复杂&#xff0c;为什么采用 f-strin…

Emp.dll文件丢失?理解Emp.dll重要性与处理常见问题

在繁多的动态链接库&#xff08;DLL&#xff09;文件中&#xff0c;emp.dll 可能不是最广为人知的&#xff0c;但在特定软件或环境中&#xff0c;它扮演着关键角色。本文旨在深入探讨 emp.dll 的功能、重要性以及面对常见问题时的解决策略。 什么是 emp.dll&#xff1f; Emp.d…