daisyUI 是一个基于 Tailwind CSS 的组件库,它为你提供了大量预设的、美观且高度可定制的 UI 组件,例如按钮、卡片、表单、导航栏等等。无需编写复杂的 CSS,也无需记忆成堆的 Tailwind 工具类,即可轻松构建现代化界面。
为什么选择 daisyUI?
- 极速开发 :通过预设组件,大幅减少编写 HTML 和 CSS 的时间,让你专注于业务逻辑。
- 纯净 HTML :告别冗长的 class 列表!daisyUI 的组件类名简洁明了,让你的 HTML 结构更清晰、更易维护。
- 高度可定制 :轻松通过 Tailwind CSS 的 tailwind.config.js 文件定制主题颜色、组件样式,完美契合你的品牌风格。
- 丰富主题 :内置多种精美主题,一键切换,省时省力。
- 轻量高效 :daisyUI 只会生成你实际用到的 CSS,保持最终产物的小巧。
- 语义化类名 :例如 .btn-primary ,直观易懂。
- 免费开源 :完全免费,并在 GitHub 上开源,拥有活跃的社区支持。
整体来说不管是响应式还是对 Tailwind CSS 的支持都非常完美,定制主题颜色、组件样式非常方便。也内置了多种精美主题。但是相对于antd、element-ui组件库,唯一不足之处,组件不是很丰富。部分组件需要自已扩展。
今天笔者分享的是 pin 码通用组件开发,费话不多说,直接上源码。
import React, { useEffect, useRef, useState } from "react";
interface PinInputProps {
isOpen: boolean;
onClose: () => void;
onComplete: (value: string) => void;
length?: 4 | 6;
title?: string;
}
const PinInput: React.FC<PinInputProps> = ({ isOpen, onClose, onComplete, length = 4, title = "请输入验证码" }) => {
const [pins, setPins] = useState<string[]>(Array(length).fill(""));
const inputRefs = useRef<(HTMLInputElement | null)[]>([]);
useEffect(() => {
if (isOpen) {
// 重置输入状态
setPins(Array(length).fill(""));
// 聚焦第一个输入框
setTimeout(() => {
inputRefs.current[0]?.focus();
}, 100);
}
}, [isOpen, length]);
const handleInputChange = (index: number, value: string) => {
if (value.length > 1) {
value = value.slice(-1);
}
const newPins = [...pins];
newPins[index] = value;
setPins(newPins);
// 自动跳转到下一个输入框
if (value && index < length - 1) {
inputRefs.current[index + 1]?.focus();
}
// 检查是否所有输入框都已填写
if (newPins.every((pin) => pin !== "")) {
onComplete(newPins.join(""));
}
};
const handleKeyDown = (index: number, e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Backspace" && !pins[index] && index > 0) {
// 如果当前输入框为空且按下退格键,则跳转到上一个输入框
inputRefs.current[index - 1]?.focus();
}
};
return (
<dialog className={`modal w-auto ${isOpen ? "modal-open" : ""}`}>
<div className="modal-box">
<h3 className="mb-8 text-lg font-bold">{title}</h3>
<div className="mb-8 flex justify-center gap-2">
{Array(length)
.fill(0)
.map((_, index) => (
<input
key={index}
ref={(el: HTMLInputElement | null) => {
inputRefs.current[index] = el;
}}
type="text"
inputMode="numeric"
pattern="[0-9]*"
maxLength={1}
className="input input-bordered h-12 w-12 text-center text-lg"
value={pins[index]}
onChange={(e) => handleInputChange(index, e.target.value)}
onKeyDown={(e) => handleKeyDown(index, e)}
/>
))}
</div>
<div className="modal-action">
<button className="btn" onClick={onClose}>
取消
</button>
</div>
</div>
<form method="dialog" className="modal-backdrop">
<button onClick={onClose}>关闭</button>
</form>
</dialog>
);
};
export default PinInput;
组件示例
import { useState } from "react";
import PinInput from "@/components/PinInput";
export default function MyProfile() {
const [isOpen, setIsOpen] = useState(false);
const handleComplete = (value: string) => {
console.log("验证码:", value);
setIsOpen(false);
};
return (
<>
<button onClick={() => setIsOpen(true)}>输入验证码</button>
<PinInput
isOpen={isOpen}
onClose={() => setIsOpen(false)}
onComplete={handleComplete}
length={6} // 可选:4 或 6
title="请输入6位验证码" // 可选:自定义标题
/>
</>
);
}
预览
