如何实现选中mobile appbar选项时在其上方添加curve效果
实现移动端AppBar选中项上方的曲线标识
问题描述
我正在开发一个移动端AppBar,想要实现当用户选中某个选项时,在该选项的上方显示一个曲线标识。尝试过创建单独的curve div,但没能达到预期效果,求正确的实现方法。

原代码
import { AiFillBell } from "react-icons/ai"; import { GoHomeFill } from "react-icons/go"; import { IoMdSettings } from "react-icons/io"; import { FaUser } from "react-icons/fa"; import { useState } from "react"; export default function App() { const [selectedItem, setSelectedItem] = useState("home"); const menuItems = [ { name: "notification", icon: <AiFillBell style={{ height: "24px", width: "24px" }} />, }, { name: "home", icon: <GoHomeFill style={{ height: "24px", width: "24px" }} />, }, { name: "settings", icon: <IoMdSettings style={{ height: "24px", width: "24px" }} />, }, { name: "user", icon: <FaUser style={{ height: "24px", width: "24px" }} />, }, ]; return ( <div style={{ background: "black", height: "100vh", padding: "50px" }}> <div style={{ background: "#0a0e18", height: "58px", borderRadius: "20px", display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0px 30px", border: "1px solid #2e3239", }} > {menuItems.map((item, index) => ( <div key={index} onClick={() => setSelectedItem(item.name)} style={{ opacity: selectedItem === item.name ? 1 : 0.2, cursor: "pointer", color: "#fff", }} > {item.icon} </div> ))} </div> </div> ); }
解决方案
核心思路是利用绝对定位结合动态计算位置,让曲线标识精准定位在选中项的正上方。具体步骤:
- 给AppBar容器添加
position: relative,作为曲线标识的定位参考 - 创建一个曲线元素,通过计算选中项的索引动态调整其
left值,使其居中对齐选中项 - 用CSS的
border-radius绘制曲线形状,匹配AppBar的风格
修改后的代码
import { AiFillBell } from "react-icons/ai"; import { GoHomeFill } from "react-icons/go"; import { IoMdSettings } from "react-icons/io"; import { FaUser } from "react-icons/fa"; import { useState } from "react"; export default function App() { const [selectedItem, setSelectedItem] = useState("home"); const menuItems = [ { name: "notification", icon: <AiFillBell style={{ height: "24px", width: "24px" }} />, }, { name: "home", icon: <GoHomeFill style={{ height: "24px", width: "24px" }} />, }, { name: "settings", icon: <IoMdSettings style={{ height: "24px", width: "24px" }} />, }, { name: "user", icon: <FaUser style={{ height: "24px", width: "24px" }} />, }, ]; // 获取选中项的索引 const selectedIndex = menuItems.findIndex(item => item.name === selectedItem); // 曲线的宽度 const curveWidth = 40; // 计算曲线的left位置,使其居中对齐选中项 const getCurveLeft = () => { const itemWidthPercent = 100 / menuItems.length; return `calc(${itemWidthPercent}% * ${selectedIndex} + (${itemWidthPercent}% / 2) - ${curveWidth}px / 2)`; }; return ( <div style={{ background: "black", height: "100vh", padding: "50px" }}> <div style={{ background: "#0a0e18", height: "58px", borderRadius: "20px", display: "flex", alignItems: "center", justifyContent: "space-around", // 改用space-around让菜单项均匀分布 padding: "0 10px", border: "1px solid #2e3239", position: "relative", // 添加相对定位 }} > {/* 曲线标识元素 */} <div style={{ position: "absolute", top: "-8px", // 向上偏移,显示在AppBar上方 left: getCurveLeft(), width: `${curveWidth}px`, height: "12px", background: "#0a0e18", borderTopLeftRadius: "20px", borderTopRightRadius: "20px", border: "1px solid #2e3239", borderBottom: "none", // 去掉底部边框,和AppBar无缝衔接 }} /> {menuItems.map((item, index) => ( <div key={index} onClick={() => setSelectedItem(item.name)} style={{ opacity: selectedItem === item.name ? 1 : 0.2, cursor: "pointer", color: "#fff", flex: 1, // 让每个菜单项占相同宽度 display: "flex", justifyContent: "center", }} > {item.icon} </div> ))} </div> </div> ); }
关键调整说明
- 将AppBar的
justifyContent从space-between改为space-around,同时给每个菜单项添加flex:1,确保所有项宽度均匀,方便计算曲线位置 - 曲线元素通过
calc动态计算left值,确保始终居中对齐选中项 - 曲线的背景色、边框与AppBar保持一致,通过
borderBottom: none实现无缝衔接
内容的提问来源于stack exchange,提问作者crust salty
相关产品推荐
相关产品推荐

