react【实战】首页 -- 响应式导航栏(含带联动动画的搜索框)

最终效果

电脑/pad端

移动端



组件封装

技术栈: react19 + Tailwind CSS

src/components/Header.jsx

ts 复制代码
import Logo from "../assets/apple.svg?react";
import { AiOutlineMenu, AiOutlineSearch } from "react-icons/ai";
import { useState } from "react";

const Header = () => {
  const [isOpen, setIsOpen] = useState(false);
  const [isSearchEnable, setIsSearchEnable] = useState(false);
  const [searchValue, setSearchValue] = useState("");

  return (
    <nav className="flex gap-2 items-center justify-between px-4 h-16 shadow-md sticky top-0 z-50 bg-white/70 backdrop-blur-md">
      <a href="#" className="text-xl font-bold">
        <Logo className="w-6 h-6 hover:scale-105 transition-transform" />
      </a>

      <div className="gap-6 hidden md:flex mx-auto">
        <a href="#">商店</a>
        <a href="#">电脑</a>
        <a href="#">手机</a>
        <a href="#">智能家居</a>
        <a href="#">娱乐</a>
        <a href="#">技术支持</a>
      </div>
      {isSearchEnable && (
        <div className="relative">
          <input
            id="search-input"
            className="peer border border-gray-300 px-4 py-2 w-64 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition"
            placeholder=" "
            value={searchValue}
            onChange={(e) => setSearchValue(e.target.value)}
          />
          <label
            htmlFor="search-input"
            className="absolute left-2 -top-2 bg-white px-2 text-xs text-gray-500 transition-all duration-200 cursor-pointer
                    peer-placeholder-shown:top-2 
                    peer-placeholder-shown:text-sm
                    peer-focus:-top-2 
                      peer-focus:left-2 
                    peer-focus:text-blue-500
                    peer-focus:text-xs"
          >
            搜索
          </label>
          {searchValue && (
            <button
              onClick={() => setSearchValue("")}
              className="absolute right-4 top-2 text-gray-400 hover:text-gray-600 cursor-pointer peer-focus:text-blue-500"
            >
              ✕
            </button>
          )}
        </div>
      )}
      <div className="flex gap-2 ml">
        <button
          onClick={() => setIsSearchEnable(!isSearchEnable)}
          className="cursor-pointer"
        >
          <AiOutlineSearch size={24} />
        </button>
        <button
          className="md:hidden cursor-pointer"
          onClick={() => setIsOpen(true)}
        >
          <AiOutlineMenu size={24} />
        </button>
      </div>
      <div
        className={`md:hidden fixed top-0 right-0 h-full w-64
        ${!isOpen && "hidden"}
        `}
      >
        <div className="flex flex-col mt-17 space-y-6 bg-white text-center p-6 rounded-lg">
          <a href="#">商店</a>
          <a href="#">电脑</a>
          <a href="#">手机</a>
          <a href="#">智能家居</a>
          <a href="#">娱乐</a>
          <a href="#">技术支持</a>
        </div>
      </div>
      {/* 移动端,菜单展开时,导航栏添加模糊遮罩 */}
      {isOpen && (
        <div
          className="fixed inset-0 bg-black/50 backdrop-blur-md"
          onClick={() => setIsOpen(false)}
        ></div>
      )}
    </nav>
  );
};
export default Header;

使用

ts 复制代码
import Header from "./components/Header";
html 复制代码
<Header />
相关推荐
贾铭1 小时前
如何实现一个网页版的剪映(五)如何跳转到视频某一帧
前端·后端
Ruihong1 小时前
手写 React 对比 VuReact 编译:真正省下来的是维护成本
vue.js·react.js·面试
林恒smileZAZ1 小时前
CSS 滚动驱动动画(scroll-timeline):无 JS 实现滚动特效
前端·javascript·css
俺不会敲代码啊啊啊1 小时前
el-table实现行拖拽(包含展开项)
前端·vue.js·typescript
LIO1 小时前
React Router 极简指南(v6+)
前端·react.js
明月_清风1 小时前
从 AST 视角看透前端工程化:一条编译管线如何串联起所有工具
前端
架构源启1 小时前
2026 进阶篇:Spring Boot响应式编程 + Spring AI 1.1.4 流式实战 + Vue前端完整实现(避坑指南)
java·前端·vue.js·人工智能·spring boot·spring·ai编程
白开水都有人用1 小时前
前端 AES 加密 + 后端解密 + MD5 校验登录
前端
OpenTiny社区2 小时前
还在手写 AI 聊天页?这款 Vue3 气泡组件,直接搞定流式对话!
前端·vue.js·ai编程