You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现选中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>
  );
}

解决方案

核心思路是利用绝对定位结合动态计算位置,让曲线标识精准定位在选中项的正上方。具体步骤:

  1. 给AppBar容器添加position: relative,作为曲线标识的定位参考
  2. 创建一个曲线元素,通过计算选中项的索引动态调整其left值,使其居中对齐选中项
  3. 用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 15:19:54