自动化拉黑---->有什么办法可以 代码实现 触发 这个元素的显示吗?

思否 问答 含 AI 优化版

问题

自动化拉黑---->有什么办法可以 代码实现 触发 这个元素的显示吗?

在 SegmentFault 查看原问题 →

由大模型辅助整理,保留原意,优化结构与可读性。

问题概述

在自动化测试/脚本场景中,需要通过代码方式主动触发一个下拉组件(识别为 Semi Design 的 Dropdown)的显示状态,而不是依赖真实的鼠标 hover 操作。

涉及技术(如有)

  • Semi Design Dropdown / Tooltip 组件源码分析
  • 组件单元测试写法(simulate 事件)
  • Foundation 模式(业务逻辑与 UI 分离)

期望结果

理解 Dropdown 组件底层依赖 Tooltip 实现弹出逻辑的原理,并找到一种代码层面主动触发其显示的方法。

回答

原始回答

1 月 1 日由 class 可以看出来是 semi-ui 的 dropdown 组件再然后找到了对应的测试代码 https://github.com/DouyinFE/semi-design/blob/main/packages/semi-ui/dropdown/__test__/dropdown.test.js然后找到如下代码 it('Dropdown-trigger-hover', async () => {

let props = {

trigger: 'hover',

};

const dropdown = getDD(props);

// Before hover, dropdown is not displayed

expect(dropdown.exists(el_portal_inner)).toEqual(false);

// After trigger, dropdown content will show

dropdown.find(.${BASE_CLASS_PREFIX}-tag).simulate('mouseEnter', {});

expect(dropdown.exists(el_portal_inner)).toEqual(true);

expect(dropdown.find(el_item)).toHaveLength(3);

await sleep(1000);

// auto hide

dropdown.find(.${BASE_CLASS_PREFIX}-tag).simulate('mouseLeave', {});

await sleep(1000);

expect(dropdown.exists(el_portal_inner)).toEqual(false);

expect(dropdown.find(el_item)).toHaveLength(0);

});

it('Dropdown-trigger-click', () => {

let props = {

trigger: 'click',

};

const dropdown = getDD(props);

// Before click

expect(dropdown.exists(el_portal_inner)).toEqual(false);

expect(dropdown.exists(el_item)).toEqual(false);

// After click

dropdown.find(.${BASE_CLASS_PREFIX}-tag).simulate('click', {});

expect(dropdown.exists(el_portal_inner)).toEqual(true);

expect(dropdown.find(el_item)).toHaveLength(3);

});原则上看,只要找对了元素,然后触发事件就好了我们再去找找 Dropdown 源码 https://github.com/DouyinFE/semi-design/blob/658b28361f0737df59519e08a669455944c8b93b/packages/semi-ui/dropdown/index.tsx#L237这个 Dropdown 组件是基于 Tooltip 来展示下拉内容的。关键证据和行为(来自你贴出的代码):Dropdown 的 UI 输出在 render() 中直接使用了 Tooltip 组件:<Tooltip ... content={pop} ...>,把由 renderContent() 生成的下拉内容传给了 Tooltip 的 content 属性。Dropdown 的 props 类型继承自 TooltipProps(export interface DropdownProps extends TooltipProps),因此很多控制弹出层行为的选项(如 position、trigger、spacing、closeOnEsc、onEscKeyDown、zIndex 等)都是传递给 Tooltip 使用的。Dropdown 会把菜单(menu)或者 render 的内容包装成下拉卡片(renderContent / renderMenu / renderPopCard),再交给 Tooltip 去弹出显示。Dropdown 保持了一个对 Tooltip 的 ref(this.tooltipRef),用于获取 popup id 并通过 foundation adapter 通知/控制可见性。渲染时会 clone children,给触发元素添加 aria 属性和展示态 class(例如 ${prefixCls}-showing),并把 visible 状态(来自 Tooltip)用于样式/键盘事件处理。补充:Dropdown 自身使用了 Foundation(业务逻辑层)来处理可见性、键盘等交互,UI 层则交由 Tooltip 负责弹出与定位。有个 renderPopCard 方法用于直接渲染传入的 render 节点(同样包在 DropdownContext 中),但最终还是作为 Tooltip 的 content 被展示。结论:Dropdown 是一个以 Tooltip 为弹出层实现的封装组件,Tooltip 负责弹出/定位/动画等细节,Dropdown 负责把菜单内容构造好并处理额外的交互逻辑。然后又分析到hover / focus 模式是通过给触发元素绑定 mouseEnter/mouseLeave(及 focus/blur)事件,事件触发后调用 Foundation 的 delayShow/delayHide(基于 mouseEnterDelay/mouseLeaveDelay 的定时器),最终调用 show/hide 完成 portal 的插入与销毁;同时有若干竞态保护(如插入后再检查是否仍然 :hover)和可控(props.visible)支持最后得出一个拦截 Foundation hide 的方案 const showDropdown2 = () => {

// 方法1: 通过 Dropdown ref 访问 tooltipRef,然后调用 foundation.delayShow() + 拦截 hide()

if (

AI 优化 · 回答整理

解答思路

通过 DOM class 特征判断出目标元素是 Semi DesignDropdown 组件;再通过阅读该组件的单元测试和源码,确认它本质上是基于 Tooltip 组件实现弹出展示的,进而找到通过 ref 调用内部 Foundation 方法来主动触发显示的思路。

示例代码(如有代码)

参考 Semi Design 官方单元测试中的触发方式(dropdown.test.js):

it('Dropdown-trigger-hover', async () => {
  const props = { trigger: 'hover' };
  const dropdown = getDD(props);

  // hover 之前,下拉内容未展示
  expect(dropdown.exists(el_portal_inner)).toEqual(false);

  // 触发 hover 后,下拉内容展示
  dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('mouseEnter', {});
  expect(dropdown.exists(el_portal_inner)).toEqual(true);
  expect(dropdown.find(el_item)).toHaveLength(3);

  await sleep(1000);

  // 移出后自动隐藏
  dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('mouseLeave', {});
  await sleep(1000);
  expect(dropdown.exists(el_portal_inner)).toEqual(false);
  expect(dropdown.find(el_item)).toHaveLength(0);
});

it('Dropdown-trigger-click', () => {
  const props = { trigger: 'click' };
  const dropdown = getDD(props);

  expect(dropdown.exists(el_portal_inner)).toEqual(false);
  expect(dropdown.exists(el_item)).toEqual(false);

  dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('click', {});
  expect(dropdown.exists(el_portal_inner)).toEqual(true);
  expect(dropdown.find(el_item)).toHaveLength(3);
});

注:原始回答在给出「拦截 Foundation hide() 的代码片段」时被截断(止于 const showDropdown2 = () => { ... if (),后续具体实现未能完整保留。

详细说明

  • 定位组件来源:通过目标元素的 class 前缀,判断出这是 Semi Design 的 Dropdown 组件,随后直接去官方仓库查阅对应的单元测试和源码(dropdown/index.tsx)。
  • DropdownTooltip 的关系
    • Dropdown 的渲染输出中直接使用了 Tooltip 组件,把内部生成的下拉内容(renderContent())作为 Tooltipcontent 属性传入;
    • DropdownProps 类型继承自 TooltipProps,因此很多控制弹出行为的配置项(positiontriggerspacingcloseOnEsconEscKeyDownzIndex 等)实际上都是转发给 Tooltip 使用的;
    • Dropdown 内部持有一个 Tooltiprefthis.tooltipRef),用于获取弹出层 id,并通过 Foundation adapter 通知/控制显示状态。
  • Foundation 模式Dropdown 自身使用 Foundation(业务逻辑层)处理可见性、键盘交互等逻辑,UI 展现则完全交给 Tooltip 负责弹出定位与动画,这是 Semi Design 组件库常见的架构分层方式(Foundation 负责逻辑,UI 层负责渲染,方便跨端复用逻辑)。
  • hover/focus 触发机制:通过在触发元素上绑定 mouseEnter/mouseLeave(以及 focus/blur)事件,触发后调用 Foundation 的 delayShow/delayHide(基于 mouseEnterDelay/mouseLeaveDelay 的定时器)实现延迟显示/隐藏,最终调用 show/hide 完成弹出层(Portal)的插入与销毁,期间还有一些竞态保护逻辑(比如插入后再次确认鼠标是否仍处于 hover 状态)。
  • 代码层面主动触发的思路:既然显示/隐藏最终由 Foundation 的 delayShow/hide 控制,理论上可以通过组件的 ref 拿到 tooltipRef,进而调用底层 Foundation 暴露的方法(如 delayShow()),并对其原本会自动调用的 hide() 进行拦截/劫持,从而实现代码层面主动、可控地触发下拉显示,而不依赖真实的鼠标事件。

小结

Semi Design 的 Dropdown 本质上是基于 Tooltip 实现弹出展示的封装组件,触发逻辑由 Foundation 层的 delayShow/hide 控制。要在代码层面(而非真实鼠标操作)触发其显示,思路是通过组件 ref 访问内部 Foundation 方法并主动调用/拦截,具体的完整实现代码在原始资料中被截断,实现时需要结合源码进一步补全。

由大模型辅助整理,保留原意,补充结构与代码格式。

回答转载自 SegmentFault

评论

评论功能即将开放。你也可以通过 邮件GitHub Issue 反馈。