Как динамически установить ViewEncapsulation для веб-компонента?

#angular #web-component

#angular #веб-компонент

Вопрос:

Я пытаюсь инициализировать компонент с теневым DOM или без него на основе браузера (поскольку IE не поддерживает теневой DOM).

Я проверяю, является ли это IE11, и устанавливаю значение инкапсуляции Emulated для IE и ShadowDom для других браузеров.

 const agent = window.navigator.userAgent;
const isIe11 = agent.indexOf('MSIE') === -1 amp;amp; 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 , что подтверждает, что инкапсуляция эмулируется.

Ответ №1:

Это невозможно в том виде, в каком вы себе это представляете, потому что angular компилирует ваш код в режиме AOT, и на этапе компиляции браузер, очевидно, неизвестен.

Я могу придумать только один способ добиться этого. Вам нужно скомпилировать одно и то же приложение дважды. Один раз для ShadowDom несовместимого браузера, и тот, в котором это возможно.

Затем на вашем сервере вы обслуживаете то, что необходимо, на основе запроса браузера. Я полагаю, вы также можете найти хакерский способ сделать это внутри index.html , который загрузит правильные библиотеки angular на основе текущего браузера. Для этого потребуется некоторый ng build сценарий after.

Однако необходимую инкапсуляцию можно выполнить из файла среды, поэтому, если у вас две разные среды для совместимых и несовместимых браузеров, вы можете добавить свойство внутри своей среды:

 // 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
});