为了账号安全,请及时绑定邮箱和手机立即绑定

使用Headless UI模式构建自定义React组件

为什么要用无头UI模式?

Headless UI 将组件的逻辑与其渲染分离,从而实现更高的灵活性和复用性。通过这种模式,开发人员可以专注于实现业务逻辑,同时让渲染保持完全的自定义性。

一些无头UI库的例子包括像Headless UI(由Tailwind Labs)这样的库,提供的组件无样式且可访问,以及专注于逻辑处理的React Query,不施加UI约束。

头less界面模式的主要好处
  1. 可重用性:逻辑可以在具有完全不同UI的多个组件之间重用。
  2. 可定制性:可以完全自由地设计组件的外观。
  3. 关注领域分离:将逻辑与渲染关注领域分开。
  4. 可访问性:由逻辑驱动的无界面组件通常很好地与ARIA标准集成。
制作一个自定义下拉列表,使用无头UI模式

我们来创建一个下拉组件,它内部处理所有逻辑,同时让你控制它的显示。

步骤 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>  
      );  
    };
主要要点
  1. 可重用性:将逻辑提取到钩子中使得组件在整个应用程序中高度可重用。
  2. 可定制性:渲染属性模式和钩子使您能够完全控制样式和行为。
  3. 可扩展性:基于逻辑的组件使设计扩展和满足不同需求变得轻松。

通过使用Headless UI模式,开发人员可以构建强大、灵活且可访问的React组件,以适应各种设计系统。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消