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

React中实现带内容切换与隐藏的类标签页式复制菜单方案

React多Tab切换显示复制区域实现方案

需求说明

在React应用的多页面中,使用<CopyToClipboard>组件包裹若干(或单个)<TabIcon>子组件,需实现:

  • 点击某<TabIcon>时,显示其对应的复制内容区域;再次点击该图标则隐藏区域
  • 点击其他<TabIcon>时,直接切换显示对应类型的内容区域,再次点击该图标也可隐藏

现有问题分析

原<CopyToClipboard>组件存在以下问题:

  • 使用单一isOpen布尔状态,无法区分当前激活的是哪个类型的Tab
  • stringToCopy中的type变量未定义,无法根据Tab类型生成对应内容
  • 未实现handleCopyClick复制逻辑
  • 渲染子组件时未传递title属性

修改实现方案

1. 调整状态管理

将原isOpen状态替换为activeType,用于记录当前激活的Tab类型(值为'link'/'embed'/null),以此区分不同Tab的显示状态。

2. 修改点击事件逻辑

handleClick函数接收当前Tab的type参数,判断当前激活的是否为该类型:

  • 若一致,则将activeType设为null(隐藏内容区域)
  • 若不一致,则将activeType设为该type(切换显示对应内容)

3. 完善复制内容生成

根据activeType动态生成对应类型的复制内容,同时补充path和suffix变量的定义(可根据实际业务调整)。

4. 实现复制功能

添加handleCopyClick函数,使用浏览器原生navigator.clipboardAPI完成复制操作,并更新isCopied状态。

修改后的完整代码

<TabIcon>组件(无需修改)

const TabIcon = ({ title, type, onClick }: Props) => {
  const theme = useTheme();
  const styles = Styles({ theme });

  return (
    <li>
      <ButtonBase type="button" onClick={onClick} title={title} disableRipple>
        <span css={styles.icon}>{type === 'embed' ? <EmbedIcon /> : <LinkIcon />}</span>
      </ButtonBase>
    </li>
  );
};

<CopyToClipboard>组件(修改后)

import { useState } from 'react';
import ButtonBase from '@mui/material/ButtonBase';
import CheckIcon from '@mui/icons-material/Check';
import CopyIcon from '@mui/icons-material/ContentCopy';

interface Props {
  children: React.ReactElement<{ type: 'link' | 'embed'; title: string }>[];
  path?: string;
  suffix?: string;
}

const CopyToClipboard = ({ children, path = '', suffix = 'link' }: Props) => {
  const [activeType, setActiveType] = useState<'link' | 'embed' | null>(null);
  const [isCopied, setIsCopied] = useState(false);

  // 根据当前激活的类型生成复制内容
  const stringToCopy = activeType === 'link'
    ? `https://www.mysite${path}`
    : `<iframe>// iframe code etc here</iframe>`;

  // 处理Tab点击事件
  const handleClick = (type: 'link' | 'embed') => {
    setActiveType(prev => prev === type ? null : type);
    // 切换Tab时重置复制状态
    if (prev !== type) setIsCopied(false);
  };

  // 处理复制按钮点击事件
  const handleCopyClick = async () => {
    try {
      await navigator.clipboard.writeText(stringToCopy);
      setIsCopied(true);
      // 3秒后重置复制状态,优化用户体验
      setTimeout(() => setIsCopied(false), 3000);
    } catch (err) {
      console.error('复制失败:', err);
    }
  };

  return (
    <div>
      <ul>
        {children.map((item, index) => (
          <TabIcon
            key={index}
            type={item.props.type}
            title={item.props.title}
            onClick={() => handleClick(item.props.type)}
          />
        ))}
      </ul>
      {/* 仅当有激活的类型时显示内容区域 */}
      {activeType && (
        <div>
          <p>{stringToCopy}</p>
          <ButtonBase type="button" onClick={handleCopyClick} disableRipple>
            <span>{isCopied ? `${suffix} copied` : `Copy ${suffix}`}</span>
            <span>{isCopied ? <CheckIcon /> : <CopyIcon />}</span>
          </ButtonBase>
        </div>
      )}
    </div>
  );
};

export default CopyToClipboard;

关键逻辑说明

  • 状态管理:activeType既记录当前激活的Tab类型,又控制内容区域的显示(null为隐藏,非null为显示对应内容)
  • Tab切换:点击相同类型的Tab时关闭内容区域,点击不同类型时直接切换,同时重置复制状态
  • 复制功能:使用navigator.clipboard.writeText实现异步复制,成功后显示"已复制"状态并自动重置
  • 兼容性:支持单个或多个Tab的场景,无需额外修改调用方式

内容的提问来源于stack exchange,提问作者meez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 10:45:37