首页 > 解决方案 > 如何为 Web 组件动态设置 ViewEncapsulation?

问题描述

我正在尝试基于浏览器初始化带有或不带有 Shadow DOM 的组件(因为 IE 不支持 Shadow DOM)。

我检查它是否是 IE11 并将封装设置Emulated为 IE 和ShadowDom其他浏览器。

const agent = window.navigator.userAgent;
const isIe11 = agent.indexOf('MSIE') === -1 && agent.indexOf('Trident') > 0;

@Component({
   selector: 'my-web-component',
   templateUrl: '...html',
   styleUrls: ['...scss'],
   encapsulation: isIe11 ? ViewEncapsulation.Emulated : ViewEncapsulation.ShadowDom
})
export class NavbarComponent implements OnInit { ... }

根据浏览器检查的返回值,的值isIe11是正确的,但封装总是以ViewEncapsulation.Emulated.

我通过 DOM 检查器确认了这一点,因为我#shadow-root在 DOM 中看不到。相反,我看到_ngcontent-c0哪个确认封装是模拟的。

标签: angularweb-component

解决方案


这在您的设想中是不可能的,因为 Angular 在 AOT 模式下编译您的代码,并且在编译步骤期间浏览器显然是未知的。

我只能想到一种方法来实现这一点。您必须编译相同的应用程序两次。一次用于不ShadowDom兼容的浏览器,而在其中一种是可能的。

然后在您的服务器上,根据请求的浏览器提供所需的服务。我想您还可以在index.html其中找到一种 hacky 方法来执行此操作,该方法将根据当前浏览器加载正确的角度库。这将需要一些ng build脚本后。

不过,您可以在环境文件中处理所需的封装,因此如果您有两个不同的环境用于兼容和不兼容的浏览器,您可以在环境中添加一个属性:

// non shadow dom compatible env
export const environment = {
  // ...
  defaultEncapsulation: ViewEncapsulation.Emulated
}


// shadow dom compatible env
export const environment = {
  // ...
  defaultEncapsulation: ViewEncapsulation.ShadowDom
}

如果您有用于生产构建的这两个环境文件,则可以编辑您的bootstrapModule方法main.ts以读取值:

platformBrowserDynamic().bootstrapModule(AppModule, {
  defaultEncapsulation: environment.defaultEncapsulation
});

推荐阅读