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

Ant Design Dropdown菜单stopPropagation失效问题(Next.js 13.4)

问题分析

Ant Design 的 Dropdown 菜单通过 Portal 挂载在 body 节点下,与包裹卡片的 Next.js Link 不在同一 DOM 层级——你在菜单点击事件中添加的 stopPropagation 和 preventDefault 无法阻止 Link 的跳转事件,因为事件冒泡路径不会经过 Link 所在的父元素。模态框关闭后页面跳转,本质是 Link 的点击事件已被触发,后续没有被正确拦截。

解决方案

不要将整个卡片嵌套在 Link 中,只把需要触发跳转的卡片主体部分放在 Link 里,页脚的操作菜单放在 Link 外部,从根源上隔离菜单点击与跳转事件:

// 外层卡片组件示例
import Link from 'next/link';

const AdCard = ({ adItem }) => {
  return (
    <div className="card-container">
      {/* 仅卡片主体包裹 Link */}
      <Link href={`/ad/${adItem.id}`}>
        <div className="card-body">
          {/* 卡片内容:标题、图片等 */}
        </div>
      </Link>
      {/* 页脚菜单独立于 Link 之外 */}
      <CardFooter adItem={adItem} />
    </div>
  );
};

如果必须将整个卡片放在 Link 内,可添加状态标记是否需要阻止跳转,在 Link 的点击事件中判断并拦截:

  1. 外层卡片组件添加状态与跳转拦截逻辑:
import { useState } from 'react';
import Link from 'next/link';

const AdCard = ({ adItem }) => {
  const [preventLinkJump, setPreventLinkJump] = useState(false);

  const handleLinkClick = (e) => {
    if (preventLinkJump) {
      e.preventDefault();
      e.stopPropagation();
      setPreventLinkJump(false); // 重置状态,不影响后续正常跳转
    }
  };

  return (
    <Link href={`/ad/${adItem.id}`} onClick={handleLinkClick}>
      <div className="card-container">
        {/* 卡片主体内容 */}
        <CardFooter 
          adItem={adItem} 
          onPreventJump={() => setPreventLinkJump(true)} 
        />
      </div>
    </Link>
  );
};
  1. 修改 ActionMenu 组件,点击菜单时触发阻止跳转标记:
// 更新 ActionMenuProps 类型
interface ActionMenuProps {
  onReport: () => void;
  onShare: () => void;
  onPreventJump: () => void;
}

const ActionMenu: FC<ActionMenuProps> = ({ onReport, onShare, onPreventJump }) => {
  const handleMenuClick: MenuProps['onClick'] = (e) => {
    e.domEvent.preventDefault();
    e.domEvent.stopPropagation();
    onPreventJump(); // 标记需要阻止 Link 跳转
    switch (e.key) {
      case 'report':
        onReport();
        break;
      case 'share':
        onShare();
        break;
    }
  };

  // 其余代码保持不变
};
  1. 更新 CardFooter 组件,传递阻止跳转的方法:
// 更新 CardFooterProps 类型
interface CardFooterProps {
  adItem: /* 你的 adItem 类型 */;
  onPreventJump: () => void;
}

const CardFooter: React.FC<CardFooterProps> = ({ adItem, onPreventJump }) => {
  // 其余代码保持不变
  return (
    <div className={`flex h-[32px] justify-between`}>
      <Space>
        <ActionMenu
          onShare={handleModalChange}
          onReport={() => console.log('reported')}
          onPreventJump={onPreventJump}
        />
        <ShareAd
          onChange={handleModalChange}
          openDialog={showShareDialog}
          adItem={adItem}
        />
      </Space>
    </div>
  );
};

使用 Next.js 的 useRouter,仅在卡片主体的点击事件中触发跳转,页脚菜单不绑定跳转逻辑:

import { useRouter } from 'next/navigation';

const AdCard = ({ adItem }) => {
  const router = useRouter();

  const handleCardBodyClick = () => {
    router.push(`/ad/${adItem.id}`);
  };

  return (
    <div className="card-container">
      <div className="card-body" onClick={handleCardBodyClick}>
        {/* 卡片主体内容 */}
      </div>
      <CardFooter adItem={adItem} />
    </div>
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 06:40:30