Angular动态创建Div的CSS样式不生效问题求助
我正尝试为动态创建的Div元素添加类名并应用样式,但即使在浏览器开发者工具中能看到类名已成功应用,CSS样式仍未生效。我已将创建元素的代码从ngOnInit移至ngAfterViewInit,但问题依旧。调试时通过document.getElementsByClassName('indent')可获取到对应的元素集合,说明类名已正确添加,但样式未生效。
以下是我的相关代码:
index.html
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Integrar</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r81/three.js"></script> <!-- AMI --> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/ami.js/0.0.22/ami.min.js"></script> </head> <body> <app-root></app-root> </body> </html>
AppComponent
import {AfterViewInit, Component} from '@angular/core'; declare var AMI: any; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements AfterViewInit { ngAfterViewInit(): void { /* globals AMI*/ // element to contain the progress bar var container; container = document.getElementById('container'); // instantiate the loader var loader; loader = new AMI.VolumeLoader(container); var t2; t2 = ['36444280', '36444294', '36444308', '36444322', '36444336']; var files; files = t2.map(function (v) { return 'https://cdn.rawgit.com/FNNDSC/data/master/dicom/adi_brain/' + v; }); loader .load(files) .then(function () { // merge files into clean series/stack/frame structure var series = loader.data[0].mergeSeries(loader.data); loader.free(); loader = null; // series/stacks/frames are ready to be used window.console.log(series); // Display some content on the DOM var seriesIndex = 1; for (var mySeries of series) { var seriesDiv = document.createElement('div'); seriesDiv.className += 'indent'; seriesDiv.insertAdjacentHTML('beforeend', '<div> SERIES (' + seriesIndex + '/' + series.length + ')</div>'); seriesDiv.insertAdjacentHTML( 'beforeend', '<div class="series"> numberOfChannels: ' + mySeries.numberOfChannels + '</div>' ); container.appendChild(seriesDiv); // loop through stacks var stackIndex = 1; for (var myStack of mySeries.stack) { var stackDiv = document.createElement('div'); stackDiv.className += 'indent'; stackDiv.insertAdjacentHTML( 'beforeend', '<div> STACK (' + stackIndex + '/' + mySeries.stack.length + ')</div>' ); stackDiv.insertAdjacentHTML( 'beforeend', '<div class="stack"> bitsAllocated: ' + myStack.bitsAllocated + '</div>' ); seriesDiv.appendChild(stackDiv); // loop through frames var frameIndex = 1; for (var myFrame of myStack.frame) { var frameDiv = document.createElement('div'); frameDiv.className += 'indent'; frameDiv.insertAdjacentHTML( 'beforeend', '<div> FRAME (' + frameIndex + '/' + myStack.frame.length + ')</div>' ); frameDiv.insertAdjacentHTML( 'beforeend', '<div class="frame"> instanceNumber: ' + myFrame.instanceNumber + '</div>' ); stackDiv.appendChild(frameDiv); frameIndex++; } stackIndex++; } seriesIndex++; } }) .catch(function (error) { window.console.log('oops... something went wrong...'); window.console.log(error); }); } }
组件模板 (app.component.html)
<div id="container"></div>
组件样式 (app.component.css)
body{ font-family: source-code-pro, sans-serif; color:#F9F9F9; background-color: #353535 } .indent{ padding-left: 8px; } .series{ color: #F44336; } .stack{ color:#8BC34A; } .frame{ color:#FFEB3B; }
这个问题的核心是Angular的默认样式封装机制。Angular会为组件的CSS添加唯一的属性选择器(比如[_ngcontent-xxx]),确保组件样式只作用于该组件模板内的元素。而你通过document.createElement动态创建的DOM元素,并没有被添加这个属性,所以组件的样式规则无法匹配到它们。
下面给你三种可行的解决方法:
方法1:使用::ng-deep穿透样式封装
在组件CSS中,给需要作用于动态元素的样式加上::ng-deep前缀,这样可以让样式突破组件的封装限制,作用到子元素甚至动态创建的元素上:
修改你的app.component.css:
body{ font-family: source-code-pro, sans-serif; color:#F9F9F9; background-color: #353535 } ::ng-deep .indent{ padding-left: 8px; } ::ng-deep .series{ color: #F44336; } ::ng-deep .stack{ color:#8BC34A; } ::ng-deep .frame{ color:#FFEB3B; }
注意:虽然
::ng-deep目前在大多数Angular版本中仍可用,但它属于已弃用的特性,未来可能会被移除。不过在没有更好替代方案的场景下,它依然是常用的临时解决办法。
方法2:将样式移到全局样式文件
Angular项目默认有一个全局样式文件(比如src/styles.css或src/styles.scss),放在这里的样式不会被封装,会作用于整个应用的所有DOM元素。
把你的样式从app.component.css移到全局样式文件中即可,不需要做任何修改,动态创建的元素就能正常应用样式。
方法3:关闭组件的样式封装
在组件装饰器中设置encapsulation: ViewEncapsulation.None,这样该组件的样式会变成全局样式,不再受封装限制:
修改AppComponent的装饰器:
import {AfterViewInit, Component, ViewEncapsulation} from '@angular/core'; declare var AMI: any; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], encapsulation: ViewEncapsulation.None }) // ... 其余代码不变
注意:关闭样式封装后,该组件的样式可能会影响到应用中的其他组件,所以要确保你的类名是唯一的,避免样式冲突。
你可以根据自己的项目需求选择其中一种方法,推荐优先考虑方法2(全局样式)或者方法3(关闭封装,注意命名冲突),如果只是临时需求可以用方法1。
内容的提问来源于stack exchange,提问作者Yone

