自动化拉黑---->有什么办法可以 代码实现 触发 这个元素的显示吗?
问题
自动化拉黑---->有什么办法可以 代码实现 触发 这个元素的显示吗?
由大模型辅助整理,保留原意,优化结构与可读性。
问题概述
在自动化测试/脚本场景中,需要通过代码方式主动触发一个下拉组件(识别为 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 Design 的 Dropdown 组件;再通过阅读该组件的单元测试和源码,确认它本质上是基于 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)。 Dropdown与Tooltip的关系:Dropdown的渲染输出中直接使用了Tooltip组件,把内部生成的下拉内容(renderContent())作为Tooltip的content属性传入;DropdownProps类型继承自TooltipProps,因此很多控制弹出行为的配置项(position、trigger、spacing、closeOnEsc、onEscKeyDown、zIndex等)实际上都是转发给Tooltip使用的;Dropdown内部持有一个Tooltip的ref(this.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