如何使用UpgradeComponent升级依赖$attrs的AngularJS指令供Angular使用
解决方案
以下两种方案均不需要修改原遗留AngularJS指令,即可兼容$attrs依赖:
方案1:手动同步输入到DOM属性(适用多数动态场景)
原AngularJS指令的templateUrl编译逻辑、controller里的$attrs读取,本质是获取DOM元素上的属性/特性,而UpgradeComponent默认只会处理scope绑定,不会自动把Angular的@Input同步到DOM特性上,导致读不到值报错。
你可以修改桥接指令,在初始化时主动把输入同步到DOM:
import { Directive, Input, ElementRef, Injector, OnInit, OnChanges, SimpleChanges } from '@angular/core'; import { UpgradeComponent } from '@angular/upgrade/static'; @Directive({ selector: 'my-bridge' }) export class MyBridgeDirective extends UpgradeComponent implements OnInit, OnChanges { @Input() hasSomething?: boolean; @Input() anotherBinding?: string; constructor(elementRef: ElementRef, injector: Injector) { super('poorLegacy', elementRef, injector); } ngOnInit() { this.syncAttrsToDom(); // 调用父类UpgradeComponent的初始化逻辑,启动AngularJS指令编译 super.ngOnInit(); } ngOnChanges(changes: SimpleChanges) { this.syncAttrsToDom(); // 触发父类的变更检测逻辑 super.ngOnChanges(changes); } private syncAttrsToDom() { const nativeEl = this.elementRef.nativeElement; // 同步hasSomething,驼峰输入转成kebab-case的HTML特性,同时挂载DOM属性 if (this.hasSomething !== undefined) { nativeEl.setAttribute('has-something', String(this.hasSomething)); nativeEl.hasSomething = this.hasSomething; } // 同步anotherBinding if (this.anotherBinding !== undefined) { nativeEl.setAttribute('another-binding', this.anotherBinding); nativeEl.anotherBinding = this.anotherBinding; } } }
使用方式保持不变即可:
<my-bridge [hasSomething]="false"></my-bridge>
方案2:静态属性直接写DOM特性(适用固定值场景)
如果你的输入值是固定的,不需要动态变更,可以直接在使用桥接组件时,同时写Angular输入绑定和原生HTML特性,原指令的$attrs就能直接读到,不需要修改桥接代码:
<my-bridge [hasSomething]="false" has-something="false" another-binding="固定值"></my-bridge>
额外兼容方案(如果原指令用到$attrs高级特性)
如果原指令的controller用到了$attrs.$observe、$attrs.$set等AngularJS专属方法,你可以在桥接指令的注入器中自定义$attrs实例,模拟AngularJS的$attrs行为:
@Directive({ selector: 'my-bridge', providers: [{ provide: '$attrs', useFactory: (el: ElementRef, bridge: MyBridgeDirective) => { // 构造和AngularJS $attrs结构一致的对象 const observers: Record<string, Function[]> = {}; const attrs = { hasSomething: bridge.hasSomething, anotherBinding: bridge.anotherBinding, $observe: (key: string, callback: Function) => { observers[key] = observers[key] || []; observers[key].push(callback); }, $set: (key: string, value: any) => { attrs[key] = value; el.nativeElement.setAttribute(key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`), value); observers[key]?.forEach(cb => cb(value)); } }; return attrs; }, deps: [ElementRef, MyBridgeDirective] }] }) export class MyBridgeDirective extends UpgradeComponent implements OnInit, OnChanges { // 其余代码和方案1一致,在syncAttrsToDom时调用$set更新值触发监听即可 }
内容的提问来源于stack exchange,提问作者dev_054
相关产品推荐
相关产品推荐

