React+TS前台项目实战(七)-- 全局常用组件Select封装

文章目录

  • 前言
  • Select组件
    • 1. 功能分析
    • 2. 代码+详细注释说明
    • 3. 使用方式
    • 4. 效果展示
    • (1)鼠标移入效果
    • (2)下拉框打开效果
    • (3)回调输出
  • 总结


前言

今天这篇主要讲全局select组件封装,可根据UI设计师要求自定义修改。


Select组件

1. 功能分析

(1)鼠标移入,选中时,选择框样式处理
(2)定义Option和props的类型,用于表示组件的相关属性
(3)添加onChange属性,用于定义选中选项时的回调函数
(4)添加defaultValue属性,用于定义默认选中的选项
(5)添加placeholder属性,用于定义选项为空时的占位符文本
(6)添加className属性,用于定义组件的自定义类名
(7)使用react-outside-click-handler插件,实现点击外部区域时收起下拉框的功能

2. 代码+详细注释说明

// @/components/Select/index.tsx
import { useState, FC } from "react";
import OutsideClickHandler from "react-outside-click-handler";
import classNames from "classnames";
import styles from "./index.module.scss";
import Arrow from "@/assets/arrowDown.png";
// 定义Option的类型,用于表示选项的属性
type Option = {
  label: string; // 选项的显示文本
  value: string; // 选项的值
};

// 定义Props的类型,用于表示组件的属性
type Props = {
  options: Option[]; // 选项数组
  onChange: (value: string) => void; // 选中选项时的回调函数
  defaultValue?: string; // 默认选中的选项值
  placeholder?: string; // 选项为空时的占位符文本
  className?: string; // 组件的自定义类名
};

// 定义Select的组件,用于实现下拉选择框的功能
const Select: FC<Props> = (props) => {
  // 解构组件的属性
  const { options, onChange, defaultValue, placeholder, className } = props;
  // 获取默认选中的选项的显示文本
  const defaultLabel = options.find((option) => option.value === defaultValue)?.label;
  // 定义状态变量
  const [isExpanded, setIsExpanded] = useState(false); // 是否展开下拉框
  const [value, setValue] = useState(defaultLabel); // 当前选中的选项的显示文本
  const [currentIndex, setCurrentIndex] = useState(1); // 当前选中的选项的索引
  // 切换下拉框的展开状态
  const toggleExpand = () => {
    setIsExpanded(!isExpanded);
  };
  // option选项点击事件
  const handlerOptionClick = (option: Option, index: number) => {
    setValue(option.label); // 更新当前选中的选项的显示文本
    onChange(option.value); // 调用回调函数,通知父组件选中的选项值
    setCurrentIndex(index); // 更新当前选中的选项的索引
    toggleExpand(); // 切换下拉框的展开状态
  };

  return (
    // 使用OutsideClickHandler组件包裹根元素,用于处理点击外部区域的事件
    <OutsideClickHandler onOutsideClick={() => setIsExpanded(false)}>
      <div className={classNames(styles.outsideContainer, className)}>
        <div className={classNames(styles.selectContainer, isExpanded && styles.isFocused)} onClick={toggleExpand}>
          <div className={classNames(styles.selectValue)}>
            <div className={classNames(styles.selectText)}>{value ?? placeholder}</div>
          </div>
          <img src={Arrow} alt="" data-is-flipped={isExpanded} />
        </div>
        {isExpanded && (
          // 如果下拉框展开,则渲染选项列表
          <ul className={classNames(styles.selectOption)}>
            {options.map((option, index) => (
              <li className={classNames(styles.selectOptionItem, index === currentIndex && styles.selected)} key={option.value} onClick={() => handlerOptionClick(option, index)}>
                <span className={classNames(styles.optionValue)}>{option.label}</span>
              </li>
            ))}
          </ul>
        )}
      </div>
    </OutsideClickHandler>
  );
};

export default Select;
------------------------------------------------------------------------------
// @/components/Button/index.module.scss
.outsideContainer {
  position: relative;
}

.selectContainer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 16px;
  min-height: 40px;
  border-radius: var(--cd-border-radius-base);
  background-color: var(--cd-fill-color-blank);
  transition: var(--cd-transition-duration);
  box-shadow: 0 0 0 1px var(--cd-border-color);
  cursor: pointer;
  user-select: none;
  position: relative;
  &.isFocused {
    box-shadow: 0 0 0 1px var(--cd-shadow-color) inset;
  }
  &:hover:not(.isFocused) {
    box-shadow: 0 0 0 1px var(--cd-border-color-hover) inset;
  }
  .selectValue {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    flex: 1;
    min-width: 0;
    position: relative;
    .selectText {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      width: 100%;
      text-align: left;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }
  img {
    width: 10px;
    transform: rotate(0);
    transition: var(--cd-transition-duration);
    &[data-is-flipped="true"] {
      transform: rotateX(180deg);
    }
  }
}
.selectOption {
  min-width: fill-available;
  padding: 6px 0;
  margin-top: 5px;
  border-radius: 4px;
  list-style: none;
  background-color: #ffffff;
  border: 1px solid #e4e7ed;
  box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
  position: absolute;
  .selectOptionItem {
    font-size: 14px;
    padding: 0 20px;
    position: relative;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: #606266;
    height: 34px;
    line-height: 34px;
    box-sizing: border-box;
    cursor: pointer;
    &:hover {
      background-color: #f5f7fa;
    }
    &.selected {
      color: var(--cd-shadow-color);
    }
  }
}

3. 使用方式

import { useState } from "react";
// 引入组件
import Select from "@/components/Select";
// 使用方式
const [options] = useState([
  {
    label: "标签1",
    value: "123",
  },
  {
    label: "标签2",
    value: "456",
  },
]);
const defaltValue = options[1].value
<Select options={options} onChange={onChange} defaultValue={defaltValue} placeholder="请选择"></Select>

// 选择变化
const onChange = (value: string) => {
  console.log("onChange", value);
};

4. 效果展示

(1)鼠标移入效果

在这里插入图片描述

(2)下拉框打开效果

在这里插入图片描述

(3)回调输出

在这里插入图片描述


总结

下一篇讲【全局模态框Modal组件、公共弹窗Dialog组件封装】。关注本栏目,将实时更新。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

力扣148. 排序链表

给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5] 示例 3&…

谷粒商城实战(036 k8s集群学习2-集群的安装)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第343p-第p345的内容 k8s 集群安装 kubectl --》命令行操作 要进入服务器 而且对一些不懂代码的产品经理和运维人员不太友好 所以我们使用可视化…

私域引流宝PHP源码 以及搭建教程

私域引流宝PHP源码 以及搭建教程

怎么防止源代码泄露?9种方法教会你!

怎么防止源代码泄露&#xff1f;首先要了解员工可以通过哪些方式将源代码传输出去&#xff01; 物理方法&#xff1a; — 网线直连&#xff0c;即把网线从墙上插头拔下来&#xff0c;然后和一个非受控电脑直连; — winPE启动&#xff0c;通过光盘或U盘的winPE启动&#xff0c;甚…

夏日炎炎 水域守护:北斗守护安全防线——为生命撑起智能保护伞

随着夏季的来临&#xff0c;炎热的天气让许多人纷纷寻求水的清凉。清凉的河流与广阔的海域成为了不少人消暑降温的向往之地。然而&#xff0c;私自下河、下海的行为却暗藏着巨大的安全隐患&#xff0c;每年夏季溺水事故频发&#xff0c;给无数家庭带来不可挽回的悲痛。为有效遏…

高考志愿填报,如何分析自己的优势特长?

据不完全统计&#xff0c;80%的高三学生&#xff0c;不清楚自己要报什么专业&#xff0c;以及将来从事哪种职业&#xff1f;有的人则是完全听从父母的安排&#xff0c;有人听老师的建议&#xff0c;有人追热门&#xff0c;有人查什么专业可以拿高薪.... 而现实就是&#xff1a…

构建汛期智慧水利新生态:EasyCVR视频汇聚监控综合管理方案解析

一、项目背景与目标 随着我国水利事业的不断发展&#xff0c;水利设施的管理与维护工作愈发重要。随着夏季汛期的到来&#xff0c;水利管理工作面临着巨大的挑战。为确保水利设施的安全运行&#xff0c;及时应对可能出现的汛情&#xff0c;建设一套高效、智能的视频监控可视化…

k8s之kubelet证书时间过期升级

1.查看当前证书时间 # kubeadm alpha certs renew kubelet Kubeadm experimental sub-commands kubeadm是一个用于引导Kubernetes集群的工具&#xff0c;它提供了许多命令和子命令来管理集群的一生周期。过去&#xff0c;某些功能被标记为实验性的&#xff0c;并通过kubeadm a…

【电子信息工程专业课】学习记录

数字信号处理 离散时间信号与系统 周期延拓 一个连续时间信号经过理想采样后&#xff0c;其频谱将沿着频率轴以采样频率Ωs 2π / T 为间隔而重复。 混频 各周期的延拓分量产生频谱交替的现象 奈奎斯特采样定理 fs > 2fh Z变换 收敛域&#xff1a;使任意给定序列x(n)的Z变…

钓鱼小助手 —— 借助文心智能体平台打造钓鱼佬神器

前言 &#x1f680;前方高能 &#x1f680;钓鱼小助手上线了 有没有喜欢钓鱼的程序猿呀&#xff0c;福利来了&#xff0c;特意整了一个钓鱼的小助手&#xff0c;以后钓鱼小技巧都可以咨询了。 走过路过&#xff0c;不要错过&#xff0c;快快体验吧~ &#x1f680;&#x1…

abap 多线程运行demo

SAP 提供多种多线程的方法去优化程序的执行效率 1.分别执行多个job 2.Call function STARTING NEW TASK 3.直接使用SAP 提供的SPTA 框架函数&#xff1a;SPTA_PARA_PROCESS_START_2 本次&#xff0c;我们着重来介绍一下三种方法中函数的使用方法 获取空闲线程数&#xff1a…

Calibre版图验证工具调用_笔记

Siemens EDA Calibre版图验证工具调用 采用Cadence Virtuoso Layout Editor直接调用Siemens EDA Calibre工具需要进行文件设置&#xff0c; 在用户的根目录下&#xff0c;找到.cdsinit文件&#xff0c; 在文件的结尾处添加以下语句即可&#xff0c;其中&#xff0c;calibre.skl…

随手记:uniapp图片展示,剩余的堆叠

UI效果图&#xff1a; 实现思路&#xff1a; 循环图片数组&#xff0c;只展示几张宽度就为几张图片边距的宽度&#xff0c;剩下的图片直接堆叠展示 点击预览的时候传入当前的下标&#xff0c;如果是点击堆叠的话&#xff0c;下标从堆叠数量开始计算 <template><…

某国资集团数据治理落地,点燃高质量发展“数字引擎”

​某国有资产经营控股集团为快速提升集团的内控管理能力和业务经营能力&#xff0c;以数字化促进企业转型的信息化建设势在必行。集团携手亿信华辰开启数据治理项目&#xff0c;在数据方面成功解决“哪里来、怎么盘、怎么管、怎么用”的问题&#xff0c;不断推动企业数字化转型…

【开发环境】PX4无人机实物使用视觉或运动捕捉系统进行位置估计

PX4无人机实物使用视觉或运动捕捉系统进行位置估计 PX4中关于外部位置信息的MAVLink话题参考坐标系EKF2调整配置参数调整EKF2_EV_DELAY参数 与ROS共同使用将OptiTrack MoCap系统提供的姿态数据导入ROSMotive MoCap软件的步骤将姿态数据导入ROS重新映射姿态数据 将姿态数据转发到…

GIS开发到底能应用在哪些行业 ?

GIS应用的领域到底有多广&#xff1f;恐怕很多GIS从业者都想不到。 尤其是近些年&#xff0c;互联网GIS的普及与发展&#xff0c;GIS技术的应用领域越来越多&#xff0c;涉及的范围也越来越广。很多我们以为跟GIS不相关的行业&#xff0c;都在悄悄用GIS技术。 从大类上分析&a…

【SkyWalking】启用apm-trace-ignore-plugin追踪忽略插件

背景 使用Agent采集追踪数据的时候&#xff0c;想排除某些路径&#xff0c;比如健康检查等&#xff0c;这样可以减少上报的数据&#xff0c;也可以去除一些不必要的干扰数据。 加载插件 在agent/optional-plugins目录中有个apm-trace-ignore-plugin-${version}.jar插件&…

flask南京市旅游景点信息可视化的设计与实现-计算机毕业设计源码02941

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对南京市旅游景点信息可视化等问题&#xff0…

TDengine Open Day 成功举办:洞察技术革新与职场策略!

随着时序数据库技术的迅速流行和广泛应用&#xff0c;行业对相关人才的需求急剧增长。为应对这一挑战&#xff0c;TDengine 特别举办了 “TDengine Open Day”技术沙龙&#xff0c;旨在为广大技术爱好者、学者及未来职场新星提供一个深入了解时序数据库及其应用的平台&#xff…

【Python】中的X[:,0]、X[0,:]、X[:,:,0]、X[:,:,1]、X[:,m:n]、X[:,:,m:n]和X[: : -1]

Python中 x[m,n]是通过numpy库引用数组或矩阵中的某一段数据集的一种写法,m代表第m维,n代表m维中取第几段特征数据。 通常用法: x[:,n]或者x[n,:] X[:,0]表示对一个二维数组,取该二维数组第一维中的所有数据,第二维中取第0个数据。 X[0,:]使用类比前者。 举例说明: x[:,0…