react19【系列实用教程】实用组件封装

必要的全局样式

src/index.css

c 复制代码
@import "tailwindcss";
/* 当根元素有 class="dark" 时 → 激活 dark: 样式,用于在页面上切换主题为暗黑模式 */
@custom-variant dark (&:where(.dark, .dark *));

@theme {
  /* 主配色 */
  --color-apple-light: #f5f5f7;
  --color-apple-dark: #1d1d1f;
  /* 标准色 */
  --color-apple-black: #000000;
  --color-apple-white: #ffffff;
  /* 品牌配色 */
  --color-apple-blue: #0071e3;
  --color-apple-red: #b64400;
  /* 灰阶系统(Gray Scale) */
  --color-apple-gray-100: #f5f5f7;
  --color-apple-gray-200: #d2d2d7;
  --color-apple-gray-300: #86868b;
  --color-apple-gray-800: #424245;
  --color-apple-gray-900: #1d1d1f;
  /* 字体 */
  --font-sans: "Inter", "Roboto", "Open Sans", "Helvetica Neue", sans-serif;
  --font-display: "Poppins", "Inter", "sans-serif";
  --font-text: "Source Sans Pro", "Open Sans", "sans-serif";
  /* 文字颜色*/
  --color-apple-text-light: #1d1d1f;
  --color-apple-text-dark: #f5f5f7;
  /* 阴影 */
  --shadow-apple-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
  --shadow-apple-md: 0 4px 12px rgba(0, 0, 0, 0.08);
  --shadow-apple-lg: 0 8px 24px rgba(0, 0, 0, 0.06);
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--color-apple-text-light);
  background-color: var(--color-apple-light);
}

按钮

src/components/Button.tsx

c 复制代码
export interface ButtonProps {
  title?: React.ReactNode;
  variant?: "primary" | "outline";
  disabled?: boolean;
  onClick?: () => void;
}

const Button = ({
  title,
  variant = "primary",
  disabled = false,
  onClick,
}: ButtonProps) => {
  let className = `px-5 py-2 rounded-md border
                   transition-colors duration-200
                   inline-flex items-center justify-center gap-2`;
  if (variant === "primary") {
    className +=
      " bg-apple-blue text-white border-apple-blue hover:bg-apple-blue/90";
  } else if (variant === "outline") {
    className +=
      " bg-transparent text-apple-blue border-apple-blue hover:bg-apple-blue hover:text-white";
  }

  if (disabled) {
    className += " opacity-50 cursor-not-allowed pointer-events-none";
  }

  return (
    <button className={className} disabled={disabled} onClick={onClick}>
      {title}
    </button>
  );
};

export default Button;

使用

c 复制代码
<Button title="购买" variant="outline" />

图标按钮

src/components/IconButton.tsx

c 复制代码
import Button, { type ButtonProps } from "./Button.tsx";

export interface IconButtonProps extends ButtonProps {
  icon: React.ReactNode;
  ioconPosition?: "left" | "right";
}

const IconButton = ({
  icon,
  ioconPosition = "left",
  title,
  ...rest
}: IconButtonProps) => {
  return (
    <Button
      title={
        <span className="flex items-center gap-2">
          {ioconPosition === "left" && icon}
          <span>{title}</span>
          {ioconPosition === "right" && icon}
        </span>
      }
      {...rest}
    />
  );
};

export default IconButton;

使用

c 复制代码
import IconButton from "./IconButton.tsx";
import { MdOutlineNavigateNext } from "react-icons/md";
c 复制代码
          <IconButton
            icon={<MdOutlineNavigateNext />}
            ioconPosition="right"
            title="进一步了解"
            variant="primary"
          />
相关推荐
muddjsv11 分钟前
前端性能优化实战:从加载到渲染的全面提速指南
前端·性能优化
deli00700736 分钟前
JSON 树形查看器:粘贴即解析,折叠展开一目了然
前端·数据库·json·ai编程
guanguan0_041 分钟前
PageProxy:页面维度接口地图 + 一键场景切换
前端·ai编程·请求代理·proxy工具
liangshanbo12151 小时前
虚拟列表深度面试题整理
java·开发语言·前端
ZISHU_9871 小时前
用 TLabel 给 SynTouch BioTac 数据做语义标注:从原始信号到结构化标注
开发语言·人工智能·python·数据·机器人触觉
略略略咯咯1 小时前
C#Unity
开发语言·unity·c#
gugucoding1 小时前
59. 【Java】Spring Boot 入门:第一个 Web 应用
java·开发语言·spring boot
IT_陈寒2 小时前
Redis内存警告竟是因为这个不起眼的配置项
前端·人工智能·后端
lilian2332 小时前
Harmony os 技术实战|拼豆制图43:压缩字符矩阵上线前如何拦住错位图纸
开发语言·前端·华为·矩阵·harmonyos
进击ing小白2 小时前
Qt 无边框窗口进阶指南
开发语言·qt