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 />
相关推荐
志尊宝11 分钟前
Vue3 零基础每日笔记(005):ref 响应式基础——为什么 script 里要 .value
前端·javascript·vue.js·笔记
海鸥两三16 分钟前
Mac电脑使用 Tabby 部署前端项目到阿里云服务器完整教程
前端·macos·阿里云
console.log('npc')24 分钟前
2026 实测:Grok 4.5 与 Grok 4.6 怎么选?前端开发、教程写作、Figma 还原选型指南
前端·大模型·ai编程·figma·grok
yyt36304584138 分钟前
一次鼠标交互触发两次 Vue flushJobs:把高频交互从 VDOM 里拆出来
前端·vue.js·计算机外设
YUJIANYUE1 小时前
查立得万用查分安卓版(web环境+查询系统免安装单文件一键运行包)
android·前端
慧都小项1 小时前
从 Figma 到 Qt:Qtitan 能减少哪些界面还原工作?
前端·qt·嵌入式·figma·图形界面·工业界面·qtitan
YWL1 小时前
OpenLayers导出功能:地图截图+GeoJSON导出完整方案,从Canvas合并到PDF生成
前端·vue·openlayers
苦瓜小生1 小时前
【前端】【力扣与手撕】十天带你刷完前端算法与手撕,全是最简单好记的最优解法!day4
前端·数据结构·算法·leetcode·面试
mayaairi2 小时前
Vue2 实战进阶:表单数据收集、指令系统与自定义指令全解析
前端·javascript·vue.js
计算机魔术师2 小时前
实测GPT-6 Astra后,我发现过去十年的专业门槛正在失效
前端