ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深入解析 Gutenberg components 中的 ExternalLink 组件:外链的渲染、锚点拦截与样式机制

深入解析 Gutenberg components 中的 ExternalLink 组件:外链的渲染、锚点拦截与样式机制 深入解析 Gutenberg components 中的 ExternalLink 组件外链的渲染、锚点拦截与样式机制【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenbergExternalLink是 WordPress Gutenberg 仓库wordpress/components包中用于指向外部资源的标准链接组件。它比原生a target_blank多做了三件事强制新标签页打开、自动追加新标签页打开的可访问性图标与 aria-label、以及对页内锚点链接#xxx做默认行为拦截。读完本文你可以准确使用该组件的children/href等 props理解其 forwardRef 实现、点击事件链与 SCSS 样式细节并了解它在当前仓库中已被标记为不推荐、应改用wordpress/ui的Link组件这一现状。基本用法与 Props 说明ExternalLink从wordpress/components导出见 packages/components/src/index.ts 中的export { default as ExternalLink } from ./external-link;。组件文档packages/components/src/external-link/README.md给出的标准用法如下import { ExternalLink } from wordpress/components; const MyExternalLink () ( ExternalLink hrefhttps://wordpress.orgWordPress.org/ExternalLink );组件接受的核心 props 定义在 types.ts 中Prop类型必填说明childrenReactNode是链接内展示的内容可以是文本、图标或任意 React 节点hrefstring是外部资源的 URL若以#开头则被视为页内锚点见下文拦截逻辑文档同时说明除上述 props 外其余 props 会透传到内部渲染的a元素上。从类型定义看index.tsx组件的 props 类型是OmitWordPressComponentProps ExternalLinkProps, a, false , target——即继承自 WordPressComponentProps 的 HTML 锚点全量属性但显式排除了target。这意味着业务方无法覆盖target的取值组件内部固定写入target_blank保证所有外链一律在新标签页打开同时通过/* eslint-disable react/jsx-no-target-blank */豁免了 ESLint 对relnoopener的告警见 index.tsx。源码级渲染结构contents 与 icon 两个 span组件通过forwardRef来自wordpress/element包装并将 ref 转发到根a元素上因此外部可以直接拿到锚点 DOMindex.tsx。其渲染产物是如下结构a classNamecomponents-external-link {自定义className} target_blank href{href} onClick{onClickHandler} span classNamecomponents-external-link__contents{children}/span span classNamecomponents-external-link__icon wp-exclude-emoji aria-label(opens in a new tab) / /a这里有几个值得注意的实现细节文本下划线只覆盖内容不覆盖图标children被包进components-external-link__contents下划线样式见下文样式小节只作用于该 span箭头图标保持独立。国际化 aria-label图标 span 的aria-label使用__()函数翻译为(opens in a new tab)因此屏幕阅读器的完整链接名是链接文本 (opens in a new tab)。这一可访问性表现被测试用例直接锁定测试中用screen.getByRole( link, { name: WordPress.org (opens in a new tab) } )定位元素test/index.jsdom.test.tsx。RTL 感知箭头图标内嵌字符通过isRTL()判断方向——RTL 布局下渲染\u2196↖LTR 下渲染\u2197↗index.tsx。wp-exclude-emoji类源码注释明确写道该类的作用是防止箭头被 Twemoji 替换成图片index.tsx即 WordPress 表情替换机制会跳过这个字符保证箭头始终是纯文本字符。className合并外部传入的className通过clsx与基础类components-external-link合并index.tsx。内部锚点拦截为什么点击#anchor不会打开编辑器这是ExternalLink最具 Gutenberg 特色的行为。组件会检查href是否以#开头若是则视为页内锚点并在onClick中调用event.preventDefault()// Anchor links are perceived as external links. // This constant helps check for on page anchor links, // to prevent them from being opened in the editor. const isInternalAnchor !! href?.startsWith( # ); const onClickHandler ( event ) { if ( isInternalAnchor ) { event.preventDefault(); } if ( props.onClick ) { props.onClick( event ); } };见 index.tsx从源码注释可以推断其动机Gutenberg 编辑器中target_blank的链接点击会被编辑器拦截并打开预览面板而页内锚点本应只是滚动定位不应该触发编辑器预览因此必须阻止默认行为。注意props.onClick无论是否锚点都会照常回调且回调位于preventDefault()之后所以业务代码拿到的事件对象上defaultPrevented已为true。这一行为由 4 个 jsdom 测试完整覆盖test/index.jsdom.test.tsx测试场景断言普通外链 onClick点击后onClickMock被调用 1 次#test锚点、无onClickprop直接挂到 DOM 上的onclick收到defaultPrevented: true#test锚点 onClickonClick被调用 1 次且defaultPrevented: true非锚点外链、无onClickpropdefaultPrevented: false不拦截其中无onClickprop的两个用例采用了巧妙写法直接向渲染出的a挂link.onclick onClickMock从而在不经过 React props 的情况下验证原生事件链上的defaultPrevented状态test/index.jsdom.test.tsx。样式实现WPDS 设计令牌与焦点环视觉样式定义在 style.scss全部基于 WordPress 设计系统WPDSCSS 变量.components-external-link { color: var(--wpds-color-foreground-interactive-brand); text-decoration: none; :hover, :active { color: var(--wpds-color-foreground-interactive-brand-active); } :focus { // Override style from wp-admin common.css. box-shadow: none; border-radius: 0; :not(:active) { include mixins.outset-ring__focus(); } } }链接本体components-external-link无下划线颜色取品牌交互色--wpds-color-foreground-interactive-brandvisited 状态保持同色hover/active 切换为--wpds-color-foreground-interactive-brand-active下划线被移到内容 span 上text-decoration: underline、text-underline-offset: 0.2em、text-decoration-thickness: from-fontstyle.scss焦点态用box-shadow: noneborder-radius: 0显式覆盖 wp-admincommon.css的默认外发光再在非 active 的 focus 上套用mixins.outset-ring__focus()输出统一的外接焦点环保证与编辑后台其余控件的焦点样式一致箭头图标 spancomponents-external-link__icon为inline-block、line-height: 1行内起始侧留--wpds-dimension-padding-xs的间距并使用默认字重style.scss。由于颜色与间距完全由--wpds-*变量驱动组件在 Gutenberg 的 Storybook/预览环境浅色/深色主题中会自动跟随主题变量取值无需额外配置。现状提示Storybook 中已被标记为不推荐需要注意一个当前仓库中的关键事实在 Storybook 元数据里ExternalLink的组件状态被标记为not-recommended官方备注建议改用wordpress/ui的Link组件并设置openInNewTabpropparameters: { componentStatus: { status: not-recommended, whereUsed: global, notes: Use Link from wordpress/ui instead, with the openInNewTab prop set., }, },见 stories/index.story.tsx这意味着存量代码中继续使用ExternalLink完全没问题其锚点拦截、aria-label 等行为的测试基线依然有效但新编写的 UI 代码按仓库当前指引应优先选择wordpress/ui的Link。Storybook 中该组件仍提供Components/Navigation/ExternalLink故事默认 args 为children: WordPress、href: https://wordpress.org见 stories/index.story.tsx可用于观察其渲染效果与可访问性命名。小结与速查关注点结论依据必填 propschildren: ReactNode、href: string其余透传至atypes.ts、READMEtarget不可覆盖类型上Omit..., target内部固定_blankindex.tsx#开头的 href点击被preventDefault()onClick仍会触发index.tsx可访问性名链接文本 (opens in a new tab)经 i18n 翻译index.tsx箭头方向LTR 为 ↗U2197RTL 为 ↖U2196index.tsx样式令牌--wpds-color-foreground-interactive-brand等 WPDS 变量style.scss新代码建议仓库内已标记 not-recommended推荐wordpress/ui的LinkopenInNewTabstories/index.story.tsx整体来看ExternalLink的实现规模很小单文件约 80 行但把新标签页外链在编辑器环境里需要处理的边界问题——目标页强制、锚点例外、可访问性命名、表情替换豁免、RTL 方向——都收敛到了明确的源码位置配合 4 个针对性 jsdom 测试是一篇很适合精读的组件级参考实现。【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表