ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Angular Material 双向文本方向(Bidirectionality)指南:用 CDK Bidi 让你的组件自动适配 LTR/RTL

Angular Material 双向文本方向(Bidirectionality)指南:用 CDK Bidi 让你的组件自动适配 LTR/RTL Angular Material 双向文本方向Bidirectionality指南用 CDK Bidi 让你的组件自动适配 LTR/RTL【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components本文基于 Angular Material 官方指南 guides/bidirectionality.md系统讲解如何在 Angular 应用中设置文本方向text-direction并利用angular/cdk/bidi提供的Directionality服务与Dir指令在自己的组件和 Angular Material 组件中感知、响应 LTR/RTL 切换。读完本文你将掌握dir属性的正确用法、Directionality的注入与订阅方式、auto值的解析规则以及背后的源码实现与测试验证逻辑。为你的应用设置文本方向Web 平台原生提供了dir全局属性 用于声明元素的文本方向。在 Angular 应用中最常见的做法是把dir设置到页面的html或body元素上从而为整个应用声明方向!-- 全局 RTL如阿拉伯语、希伯来语页面 -- html dirrtl也可以把dir用在页面内的任意元素上只为某个更小的子树指定方向div dirrtl !-- 这部分内容按从右到左布局 -- /div一个关键承诺是所有 Angular Material 组件都会自动反映其所在容器的 LTR/RTL 方向。也就是说你不需要为每个组件单独配置只要在容器上设置好dir内部的 Material 组件按钮、对话框、菜单、表单字段等的布局、对齐与图标方向就会随之适配。在自己的组件中读取文本方向如果你的组件也需要感知当前方向例如调整图标翻转、切换左右对齐angular/cdk/bidi提供了可注入的Directionality服务任何组件都可以直接消费它。使用时需要先从angular/cdk/bidi导入BidiModuleimport {BidiModule} from angular/cdk/bidi;Directionality对外暴露两个核心属性属性类型说明valueltr \| rtl当前的文本方向changeObservableDirection文本方向变化时发射事件的可观察流需要特别注意的是change只捕获 Angular 应用上下文内部dir属性的变化即通过Dir指令见下文管理的那部分 DOM。它不会因html或body上的dir改变而发射事件——因为全局方向被假定为静态的。官方示例订阅方向变化Component({ /* ... */ }) export class MyCustomComponent { private dir: Direction; constructor(directionality: Directionality) { this.dir directionality.value; directionality.change.subscribe(() { this.dir directionality.value; }); } }CDK 自带的组件示例中则展示了更完整的写法包括取消订阅和销毁钩子见 src/cdk/bidi/bidi.mdComponent({ ... }) export class MyWidget implements OnDestroy { /** Whether the widget is in RTL mode or not. */ private isRtl: boolean; /** Subscription to the Directionality change EventEmitter. */ private _dirChangeSubscription Subscription.EMPTY; constructor(dir: Directionality) { this.isRtl dir.value rtl; this._dirChangeSubscription dir.change.subscribe(() { this.flipDirection(); }); } ngOnDestroy() { this._dirChangeSubscription.unsubscribe(); } }注意Directionality.change底层是一个EventEmitter见 directionality.ts按惯例在使用后应取消订阅服务在ngOnDestroy时会调用change.complete()完成该流测试 directionality.spec.ts 对此有专门覆盖。源码深挖Directionality 是如何拿到方向的理解底层实现有助于你在边界场景下做出正确判断。Directionality的实现位于 src/cdk/bidi/directionality.ts核心逻辑如下读取文档方向构造函数通过注入DIR_DOCUMENTtoken 获取文档对象依次检查document.body.dir与document.documentElement.dir取第一个非空值若都为空则默认ltrdirectionality.ts。优先级body上的方向优先于html上的方向。这一点在测试中得到验证即使html设为ltr、body设为rtlvalue也返回rtldirectionality.spec.ts。方向解析_resolveDirectionality(rawValue)会把输入值转小写后归一化任何非法值都回退为ltrdirectionality.ts。测试同样覆盖了body.dir not-valid时默认返回ltr的场景directionality.spec.ts。DIR_DOCUMENT是一个独立的 InjectionToken定义在 dir-document-token.ts。之所以要单独抽象它是因为测试环境中不能使用真实document——修改真实 DOM 的dir会导致 Safari 中基于几何测量的测试失败同时单元测试代码自身也要用querySelector无法整体替换DOCUMENT。注入这个 token 后测试只需提供一个假的{body: {}, documentElement: {}}对象即可见 directionality.spec.ts。Dir 指令让任意子树拥有自己的方向上下文BidiModule还导出与选择器[dir]匹配的Dir指令其实现位于 src/cdk/bidi/dir.ts。它的设计非常巧妙Directive({ selector: [dir], providers: [{provide: Directionality, useExisting: Dir}], host: {[attr.dir]: _rawDir}, exportAs: dir, }) export class Dir implements Directionality, AfterContentInit, OnDestroy { // ... Output(dirChange) readonly change new EventEmitterDirection(); // ... }几个值得注意的实现细节自我提供为 DirectionalityDir通过useExisting把自己注册为Directionality。因此任何注入Directionality的后代组件拿到的一定是最近的祖先方向上下文而不是全局的html/body方向。测试验证了这一点在带dir的元素内部注入Directionality得到的value就是该元素的dir值directionality.spec.ts。API 与 Directionality 一致Dir同样暴露value与change并额外提供dirChange输出事件Output(dirChange)模板中可用(dirChange)监听局部方向变化。保留原始属性值_rawDir保存用户传入的原始值并作为宿主属性回写到 DOM因此dirauto之类的值会被保留在元素上而内部归一化后的value则是ltr/rtldir.ts。测试断言了dirauto元素同时满足DOM 上是auto、value是ltrdirectionality.spec.ts。大小写不敏感_resolveDirectionality会先做toLowerCase()所以[dir]RTL也能被正确解析为rtldirectionality.spec.ts。首次赋值不触发事件Dir在ngAfterContentInit时才把_isInitialized置为true避免初始值设置阶段就误发change事件dir.ts。测试中把dir从rtl切到ltr恰好只触发一次dirChangedirectionality.spec.ts。BidiModule本身非常简单只是导入并再导出Dirbidi-module.ts。使用时可按需在组件的imports中引入BidiModule或直接引入Dir指令。解读 auto 值CDK 与浏览器行为的差异原生dir支持auto值——由浏览器根据元素文本内容自动判定方向。CDK 也支持auto但出于性能考量采用了不同的解析方式见 bidi.md 的 Interpreting the auto value 一节CDK 的做法读取浏览器语言navigator.language与一组已知的 RTL 语言环境正则匹配命中则视为rtl否则为ltr。浏览器的做法基于元素的实际文本内容判定成本较高。这个差异在 directionality.ts 中体现得很清楚RTL_LOCALE_PATTERN是一个借鉴自goog.i18n.bidi.isRtlLanguage的正则覆盖阿拉伯语系ar、希伯来语he/iw、波斯语fa、乌尔都语ur等以及Adlm、Arab、Hebr、Nkoo、Rohg、Thaa等书写系统同时排除了带Latn/Cyrl的复合语言标签const RTL_LOCALE_PATTERN /^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*-_)(?!.*-_($|-|_))($|-|_)/i;之所以必须解析auto是因为 CDK 中像 overlay 浮动层、键盘导航这类功能需要明确知道元素处于 RTL 还是 LTR 布局才能正确工作而不能依赖浏览器的内容推断。如果你的业务代码同样需要确定性行为就应理解dirauto在 CDK 语境下解析为按浏览器语言判定而不是按内容判定。在 Material 组件中的实际应用Angular Material 组件确实在广泛消费Directionality。例如src/material/form-field/form-field.ts 中const dir inject(Directionality);用于感知方向以调整前缀/后缀、错误提示等元素的排布src/material/tooltip/tooltip.ts 中protected _dir inject(Directionality);用于决定 tooltip 的弹出方向与对齐。这印证了指南中的声明组件通过注入Directionality即可自动获得最近的祖先方向上下文。无论全局是 LTR 还是局部某个容器是 RTLMaterial 组件都会正确响应。你同样可以在自己的组件里采用这一模式并在模板中使用Dir指令的dirChange事件或直接订阅Directionality.change来响应方向切换。最佳实践小结全局方向在html或body上设置dirrtlMaterial 组件会自动适配。局部方向在任意元素上使用dir模板中推荐[dir]rtl或[dir]direction()后代组件会拿到最近的局部方向。自定义组件从angular/cdk/bidi导入BidiModule注入Directionality读取value、订阅change并在ngOnDestroy中取消订阅。理解事件边界change只响应 Angular 上下文内部的dir变化不监听html/body的静态方向改动。谨慎使用autoCDK 以浏览器语言而非元素内容解析auto需要确定性方向时应显式写ltr/rtl。了解回退规则body方向优先于html非法值一律回退为ltrDir的value与 DOM 上的原始dir属性值可不同如auto。如需查看完整测试用例以加深理解可阅读 src/cdk/bidi/directionality.spec.ts模块与指令的公开 API 汇总见 src/cdk/bidi/public-api.ts。【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表