为什么要用无头UI模式?
Headless UI 将组件的逻辑与其渲染分离,从而实现更高的灵活性和复用性。通过这种模式,开发人员可以专注于实现业务逻辑,同时让渲染保持完全的自定义性。
一些无头UI库的例子包括像Headless UI
(由Tailwind Labs)这样的库,提供的组件无样式且可访问,以及专注于逻辑处理的React Query,不施加UI约束。
- 可重用性:逻辑可以在具有完全不同UI的多个组件之间重用。
- 可定制性:可以完全自由地设计组件的外观。
- 关注领域分离:将逻辑与渲染关注领域分开。
- 可访问性:由逻辑驱动的无界面组件通常很好地与ARIA标准集成。
我们来创建一个下拉组件,它内部处理所有逻辑,同时让你控制它的显示。
步骤 1:利用 Hooks 来定义逻辑部分 import { useState } from "react";
type DropdownOption = {
value: string;
label: string;
};
export function useDropdown(options: DropdownOption[]) {
const [isOpen, setIsOpen] = useState(false);
const [selectedOption, setSelectedOption] = useState<DropdownOption | null>(null);
const toggleDropdown = () => setIsOpen((prev) => !prev);
const closeDropdown = () => setIsOpen(false);
const selectOption = (option: DropdownOption) => {
setSelectedOption(option);
closeDropdown();
};
return {
isOpen,
selectedOption,
toggleDropdown,
selectOption,
closeDropdown,
options,
};
}
这个钩子(或组件)负责下拉列表的状态逻辑,使其能够跨组件复用。
第二步:创建 Render Props 组件渲染属性模式能让你定义下拉菜单的外观。
import React from "react";
type 下拉菜单属性 = {
子元素: (属性: {
isOpen: 是否展开;
selectedOption: 下拉选项 | null;
toggleDropdown: () => void;
selectOption: (option: 下拉选项) => void;
options: 下拉选项[];
}) => React.ReactNode;
};
export const 下拉菜单: React.FC<下拉菜单属性> = ({ 子元素 }) => {
const dropdown = useDropdown([
{ value: "选项1", label: "选项1" },
{ value: "选项2", label: "选项2" },
]);
return <>{子元素(dropdown)}</>;
};
步骤三:利用下拉菜单
这里教你如何使用自定义风格和Tailwind CSS来展示下拉列表。
import React from "react";
import { Dropdown as 下拉菜单 } from "./Dropdown";
const 自定义下拉菜单 = () => {
return (
<下拉菜单>
{({ isOpen, selectedOption, toggleDropdown, selectOption, options }) => (
<div className="relative inline-block text-left">
<button
className="px-4 py-2 bg-blue-500 text-white rounded"
onClick={toggleDropdown}
>
{selectedOption ? selectedOption.label : "请选择选项"}
</button>
{isOpen && (
<ul className="absolute mt-2 bg-white border rounded shadow-lg">
{options.map((option) => (
<li
key={option.value}
className="px-4 py-2 cursor-pointer hover:bg-gray-200"
onClick={() => selectOption(option)}
>
{option.label}
</li>
))}
</ul>
)}
</div>
)}
</下拉菜单>
);
};
export default 自定义下拉菜单;
使用无头UI技术创建模态
第一步:模态逻辑入门
import { useState } from "react";
/**
* 使用useModal函数来管理模态框的打开和关闭状态。
* isOpen表示模态框是否打开。
* openModal方法用于打开模态框。
* closeModal方法用于关闭模态框。
*/
export function useModal() {
const [isOpen, setIsOpen] = useState(false);
const openModal = () => setIsOpen(true);
const closeModal = () => setIsOpen(false);
return { isOpen, openModal, closeModal };
}
步骤 2:渲染模态组件
type ModalProps = {
children: (props: { isOpen: boolean; closeModal: () => void }) => React.ReactNode;
};
export const Modal: React.FC<ModalProps> = ({ children }) => {
const modal = useModal();
return <>{children(modal)}</>;
};
步骤 3:使用模态框
const 自定义弹窗 = () => {
return (
<Modal>
{({ isOpen, 关闭弹窗, 打开弹窗 }) => (
<>
<button
className="px-4 py-2 bg-green-500 text-white rounded"
onClick={打开弹窗}
>
打开弹窗
</button>
{isOpen && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center">
<div className="bg-white p-4 rounded">
<h2 className="text-lg">这是一个弹窗</h2>
<button className="mt-4 px-4 py-2 bg-red-500 text-white rounded" onClick={关闭弹窗}>
关闭弹窗
</button>
</div>
</div>
)}
</>
)}
</Modal>
);
};
主要要点
- 可重用性:将逻辑提取到钩子中使得组件在整个应用程序中高度可重用。
- 可定制性:渲染属性模式和钩子使您能够完全控制样式和行为。
- 可扩展性:基于逻辑的组件使设计扩展和满足不同需求变得轻松。
通过使用Headless UI模式,开发人员可以构建强大、灵活且可访问的React组件,以适应各种设计系统。
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦