现在的前端开发都是单页面组件化模式, 也是就一个项目就一个页面, 通过ruter来切换组件, angular也不例外。
而每个组件都有他们自己的样式,虽然每个组件都有自己的样式,但是最终都会打包到一起,那么,问题来了,组件之间的样式会相互影响吗。
我们新建一个项目my-app,在这个项目的src目录下有一个app组件,这个组件就是项目的根组件,我们把它当作父组件用,在app.component.ts里写上这些代码
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: `
我是父组件
`, styles: [''] }) export class AppComponent { }父组件有了
我们再新建两个子组件a.component.ts和b.component.ts,也分别在ts文件里写上这些代码
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-a', template: `
我是子组件 a
`, styles: [''] }) export class AComponent implements OnInit { constructor() { } ngOnInit(): void { } }------------------------------------------------------------------------------
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-b', template: `
我是子组件 b
`, styles: [''] }) export class BComponent implements OnInit { constructor() { } ngOnInit(): void { } }再把他们用到父组件app中
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: `
我是父组件
`, styles: [''] }) export class AppComponent { } 启动项目,打开浏览器,页面上是这样子的
现在我在父组件的styles里给p标签加上样式
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: `
我是父组件
`, styles: ['p { color: red; }'] }) export class AppComponent { } 现在页面是这样的
我们按f12打开控制台,审查下元素看看
可以看到每个组件的元素都被动态的添加了一个属性,每个组件都不一样
再看下父组件里p元素的样式
可以看到选择器后面被动态的加了个属性选择器,而这个属性只有父组件里的元素有,这样就不会影响到别的组件了。
Angular就是这样给每个组件的元素动态的加上独有的属性,然后给这个组件的选择器后面也动态的加上这个独有属性选择器,而每个组件的动态属性都不一样,这样选择器就只会选到自己组件的dom元素,从而防止组件的样式污染,让它们互不影响
我现在给父组件的p标签选择器前面加上一个:host
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: `
我是父组件
`, styles: [':host p { color: red; }'] }) export class AppComponent { } 再来看下样式
可以看到 :host 会给选择器的前面加上一个自己组件的动态属性的属性选择器
这个动态属性只有当前这个组件有,从而保证选择器只能作用于自己的组件
把父组件里的:host 换成 ::ng-deep
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: `
我是父组件
`, styles: ['::ng-deep p { color: red; }'] }) export class AppComponent { } 然后页面变成这样
子组件被影响了,为什么我在父组件的样式会影响子组件,不是互不影响吗?因为加了::ng-deep
我们看下页面上p元素的样式
可以看到加了::ng-deep后,选择器后面的属性选择器没了,这样就是导致这个样式可以影响到别的组件,只要它是p标签, 因为都是在同一个页面
实际情况下就是这两个基本是一起配合使用,在一些使用了第三方组件,又想修改第三方组件里元素的样式时, 或者是项目里的通用组件,想在某个使用它的组件里单独修改它的样式,而不影响别的组件
我们现在新建一个通用组件c.component.ts
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-c', template: `
我是通用组件c`, styles: ['div { height: 200px; width: 200px; background-color: blue; }'] }) export class CComponent implements OnInit { constructor() { } ngOnInit(): void { } }通用组件c就是一个蓝色方块
我们把他用到a和b组件中
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-a', template: `
我是子组件 a
`, styles: [''] }) export class AComponent implements OnInit { constructor() { } ngOnInit(): void { } } ------------------------------------------------------------------------------
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-b', template: `
我是子组件 b
`, styles: [''] }) export class BComponent implements OnInit { constructor() { } ngOnInit(): void { } } 现在页面上是这样的
我现在想在a组件里把方块c改成绿色,而又不影响b组件里的方块c,这个时候就要用:host和 ::ng-deep 了
在组件a的styles里加上这些样式
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-a', template: `
我是子组件 a
`, styles: [':host ::ng-deep div { background-color: green !important; }'] }) export class AComponent implements OnInit { constructor() { } ngOnInit(): void { } } 页面如下
成功了
看下组件a里的c方块的样式
:host 在前面加了个本组件的动态属性的属性选择器,确保样式只生效于本组件和他的子组件,::ng-deep 把选择器后面的属性选择器去掉了,这样就能作用别的组件了。
组合在一起就是只有本组件和本组件的子组件里的div才能被选择到, 这样既能控制范围,又能影响到子组件
同理,第三方组件也是类似的用法
这就是我分享的一些关于 :host 和 ::ng-deep 的简单用法