文档章节

Angular高级样式指南(V4+)

我是钟钟
 我是钟钟
发布于 2017/08/29 09:36
字数 2395
阅读 1633
收藏 10
点赞 1
评论 3

原文地址:https://medium.com/google-developer-experts/angular-advanced-styling-guide-v4-f0765616e635

同步发布在我的个人网站:http://www.codebe.org

了解如何使用Shadow DOM选择器,Light DOM,@HostBinding,ElementRef,Renderer,Sanitizer等。

输入图片说明

在这个指南中,我们将介绍Angular的组件和指令中可选的各种属性。会覆盖以下方面:

  • Angular的封装模式: emulated, native 和 disabled。
  • 浏览器支持, Shadow DOM 对比 Light DOM。
  • @Component的样式元数据: 内联, 模版内联和外部样式。
  • 使用ngClass和ngStyle指令。
  • Shadow DOM选择器::host, :host(), :host-context(), :host /deep/ selector,:host >>> selector。
  • 使用@Component.host 和@HostBinding。不安全的样式。
  • 使用ElementRef和nativeElement API(Web)。
  • 使用Renderer和setElementClass / setElementStyle API(Web,Server,WebWorker)。
  • CSS样式的特殊性和执行顺序。

您可以使用这个来浏览最终的代码Plnkr

介绍

Angular应用的样式使用从未如此灵活。Angular组件体系结构提供了一种新的样式模型,通过使用Web Component规范中的Shadow DOM(模拟或本机)隔离组件样式。每个组件的样式都是在组件范围内的,因此它们不会影响UI的其他区域。

对于这篇文章,我们将使用一个组件来渲染显示一些不同样式选项的歌曲曲目。这个组件将呈现一首歌曲的封面,标题和艺术家。

@Component({
  selector: 'song-track',   // <song-track></song-track>
})
export class SongTrack { }

请参考下面的最终效果:

输入图片说明

Angular封装模式

在进一步探索不同的样式方法之前,让我们快速查看所有可用的封装模式。

Emulated(仿真)(默认)

使用此模式时,Angular将使用两个独特的属性来识别每个组件:_nghost- *和_ngcontent- *。使用这些属性将任何组件样式添加到head,以隔离样式,如下面的示例所示。

<head>
  <style>
    .container[_ngcontent-ikt-1] { ... } 
  </style>
</head>
<body>
  <my-app>
    <song-track _nghost-ikt-1>
      <div _ngcontent-ikt-1 class="container"></div>
    </song-track>
  </my-app>
</body>

注意以粗体显示添加到组件的根和内容中的属性。您可以使用下面的代码显式激活此模式。

@Component({
  selector: 'song-track',
  encapsulation: ViewEncapsulation.Emulated
})

Emulated可以实现跨浏览器的最佳支持。

Native(本地)封装

此封装将设置Angular为特定组件使用Native Shadow DOM。根据浏览器,这将是v1规范(Chrome)。

@Component({
  selector: 'song-track',
  encapsulation: ViewEncapsulation.Native
})

这将显示以下内容。

<body>
  <my-app>
    <song-track>    
      ▾ #shadow-root (open)    
        <style>.container { ... }</style>   
        <div class="container"></div>
    </song-track>
  </my-app>
</body>

请注意,样式如何封装在#shadow-root下。稍后将介绍具体的样式选项。

某些浏览器不支持Native封装。检查当前的支持。

Disabling(禁用)封装

我们还可以为特定的组件完全禁用封装。

@Component({
  selector: 'song-track',
  encapsulation: ViewEncapsulation.None
})

通过使用此模式,Angular将向head添加任何定义的样式,因此可以使用此封装在组件之间共享样式。

Native Shadow DOM浏览器支持

此时,Native Shadow DOM仍然不被广泛支持。请参阅下面的仿真和本机浏览器支持比较。

仿真:

输入图片说明

本地:

输入图片说明

Shadow DOM与Light DOM

在对我们的组件进行样式化时,可以帮助区分Shadow DOM和Light DOM。

  • Shadow DOM:组件创建或管理的任何本地DOM元素。这也包括任何子组件。
<song-track title="No Lie" artist="Sean Paul..."></song-track>
@Component({
  selector: 'song-track',
  template: `        
     <track-title>{{track}}</track-title>
     <track-artist>{{artist}}</track-artist>`
})
export class SongTrack { }
  • Light DOM:组件的任何子DOM元素。也称为投影内容(ng-content)。
<song-track>
  <track-title>No Lie</track-title>
  <track-artist>Sean Paul, Dua Lipa</track-artist>
</song-track>
@Component({
  selector: 'song-track',
  template: `<ng-content></ng-content>`
})
export class SongTrack { }

@Component样式元数据

为了调整我们的组件,我们可以使用组件元数据。

Angular将按照下面使用的相同顺序添加标题中的样式。

使用内联样式

当我们将样式添加到与组件相同的文件中时。首先在顶部以数组的方式添加:

@Component({
  selector: 'song-track',
  styles: [`.container { color: white; }`]
})
export class SongTrack { }

使用模板内联样式

我们还可以使用此功能将我们的样式嵌入到我们的模板中。在顶部添加:

@Component({
 template: `
   <style>
   .container { color: deepskyblue; }
   </style>   
   <div class="container">...</div>
 `
})
export class SongTrack { }

使用外部文件

当我们的组件需要更复杂的样式时,我们可以使用外部文件。

//song-track.component.css
.container { ... }
//song-track.component.ts
@Component({
  styleUrls: ['./song-track.component.css'],
})
export class SongTrack { }

作为CSS规范的一部分,我们还可以使用@import从其他样式表导入样式。@import必须在样式表的第一行。

@import 'common.css';
.container { ... }

使用ngClass和ngStyle指令

我们可以使用ngClass和ngStyle指令来动态地调整我们的组件。我们来看一些常见的用法。

<song-track ngClass="selected" class="disabled"></song-track>
<song-track [ngClass]="'selected'"></song-track>   
<song-track [ngClass]="['selected']"></song-track> 
<song-track [ngClass]="{'selected': true}"></song-track>

请注意,ngClass可以与现有的类属性组合,也可以不使用任何绑定。要定位多个类,我们可以使用扩展语法和一些有趣的变体.

<song-track ngClass="selected disabled">             
<song-track [ngClass]="'selected disabled'">      
<song-track [ngClass]="['selected', 'disabled']">   
<song-track [ngClass]="{'selected': true, 'disabled': true}">
<song-track [ngClass]="{'selected disabled': true}">

对于ngStyle,我们可以做同样的事情,但是由于我们需要键值对,选项较少。

<song-track [ngStyle]="{'color': 'white'}" style="margin: 5px;"><song-track [ngStyle]="{'font-size.px': '12'}">
<song-track [ngStyle]="{'font-size': '12px'}">
<song-track [ngStyle]="{'color': 'white', 'font-size': '12px'}">

注意扩展单元语法匹配现有的CSS测量单位。要应用多种样式,您可以添加更多属性。

使用Shadow DOM选择器

当使用模拟或本机封装时,我们可以访问仅适用于Shadow DOM的一些有趣的CSS选择器。

装饰容器(又名宿主)

如果我们需要访问我们的容器或与其他选择器一起使用,我们可以使用:host伪类选择器。

:host { color: black; }          // <song-track>
:host(.selected) { color: red; } // <song-track class="selected">

第一个例子将匹配song-track元素并且增加color样式。第二个例子将匹配具有selected类的song-track元素并且增加color样式。

样式依赖于祖先元素

我们可以添加一个这样的样式,它会在组件的宿主元素的祖先元素中查找匹配的祖先元素直到文档的根。

:host-context(.theme) { color: red; }   
:host-context(#player1) { color: red; }

上面的例子只有当theme这个样式类在组件宿主元素的祖先元素中存在的时候,才会应用指定的样式。第二个例子是使用id=“player1”来匹配祖先元素。

装饰宿主元素或后代元素(跨边界)

这个选项将会覆盖任何封装的样式配置包括宿主元素的子元素。此选择器将适用于Shadow和Light DOM。

我们可以使用/deep/覆盖Shadow DOM的边界

:host  /deep/ .selected { color: red; }
:host   >>>   .selected { color: red; }

**注意:**在Angular-cli中使用/deep/而不是>>>。

使用@Component.host

通过使用这个属性,我们可以绑定DOM Properties,DOM Attributes和事件。查看以下不同选项的概述。

@Component({
 host: {
  'value': 'default',                    //'DOM-prop': 'value'  
  '[value]': "'default'",                //'[DOM-prop]': 'expr'   
  
  'class': 'selected',                   //'DOM-attr': 'value'
  '[class]': "'selected'",               //'[DOM-attr]': 'expr'
 
  '(change)': 'onChange($event)',        // (event) : ...   
  '(window:resize)': 'onResize($event)', // (target:event) : ...
 } 
})

让我们看一些使用类和样式DOM属性的例子。

@Component({
  host: {
    //setting multiple values
    'class': 'selected disabled',
    'style': 'color: purple; margin: 5px;',
    
    //setting single values (using binding)
    '[class.selected]': 'true',    
    '[class.selected]': '!!selected', //add class if selected = true
    '[style.color]': '"purple"'   //expression must be a string
  } 
})
export class SongTrack { }

注意使用方括号来创建绑定。这就是为什么'true'成为布尔值true。对于CSS属性color,我们需要传递一个字符串。

绑定不安全表达式

为避免滥用某些样式表达式可能被Angular标记为不安全。

@Component({
  host: {
    '[style]': '_hostStyle' //unsafe
  } 
})
export class SongTrack { }

如果遇到这个特殊问题,可以通过在Sanitizer上使用bypassSecurityTrustStyle API来将表达式标记为安全。

export class SongTrack {
  constructor(private sanitizer: Sanitizer){
    this._hostStyle = this.sanitizer
      .bypassSecurityTrustStyle('color: black;');
  }
}

使用@HostBinding

我们也可以使用@HostBinding装饰器来设置我们的样式。参见下面的一些例子。参见下面的一些例子。

export class SongTrack {   
  //<host class="selected"></host>   
  @HostBinding('class.selected') selected = true;
  //<host style="color: red;"></host>     
  @HostBinding('style.color') color = 'red';
}

@HostBinding装饰器被翻译成@ Component.host元数据。

使用ElementRef和nativeElement API(浏览器)

有时我们可能想要访问底层的DOM元素来操纵它的样式。为了做到这一点,我们需要注入ElementRef并访问nativeElement属性。这将使我们能够访问DOM API。

export class SongTrack {
  constructor(private element: ElementRef){
    let elem = this.element.nativeElement;
    elem.style.color = "blue";
    elem.style.cssText = "color: blue; ..."; // multiple styles
    elem.setAttribute("style", "color: blue;"); 
  }
}

请注意,此选项将适用于浏览器平台,但不适用于桌面或移动设备。

使用Renderer和setElementClass / setElementStyle API(Web,服务器,WebWorker)

比使用ElementRef来设置我们的样式的更安全的替代方法是使用Renderer的setElementClass和setElementStyle方法。

他们使用了抽象层次来克服由于使用ElementRef带来的跨平台的兼容性问题。

export class SongTrack {
  constructor(
     private element: ElementRef,
     private renderer: Renderer
  ){
    let elem = this.element.nativeElement;
    renderer.setElementStyle(elem, "color", "blue");
    renderer.setElementClass(elem, "selected", true);
  }
}

CSS样式的特殊性和执行顺序

所有样式遵循以下特殊性和顺序规则:

  • 越具体的样式优先级越高
  • 具有相同的特性,应用的最后一个样式规则将覆盖任何先前的样式规则

下面列出的是从低到高的样式优先级:

组件:

容器:

  • 内联样式。例如: <... style="">
  • ngClass 和 ngStyle

所以如果我们使用ngStyle,这将覆盖元素上定义的任何内联样式以及之前的任何内容。

作为Angular渲染执行和组件生命周期的一部分,样式能够静态和动态地应用。

请注意,根据执行顺序,我们可能会得到另一个覆盖的样式。例如,首先应用@ Component.host,然后应用@Hostbinding。

© 著作权归作者所有

共有 人打赏支持
我是钟钟
粉丝 52
博文 43
码字总数 40311
作品 1
深圳
高级程序员
加载中

评论(3)

鱼一样的享受
鱼一样的享受
赞赞赞
我是钟钟
我是钟钟

引用来自“WittBulter”的评论

`private renderer: Renderer` 现在已经可以用 `Renderer2` 了
嗯嗯,没错,新版本已经是REnderer2了
WittBulter
WittBulter
`private renderer: Renderer` 现在已经可以用 `Renderer2` 了
Angular 6正式版发布,都有哪些新功能

在Angular 5发布半年之后,Angular 6在昨天正式发布,那么在这个版本有哪些新功能呢?新版本重点关注工具链以及工具链在 Angular 中的运行速度问题。除此之外,这次更新还包括框架包(@angu...

code_xzh
05/05
0
0
Angular 6.0正式版发布,都有哪些新功能

点击关注异步图书,置顶公众号 每天与你分享IT好书 技术干货 职场知识 在Angular 5发布半年之后,Angular 6在昨天正式发布,那么在这个版本有哪些新功能呢?新版本重点关注工具链以及工具链在...

异步社区
05/08
0
0
Angular.js 相关记录

AngularJS作用域文档:http://docs.angularjs.org/api/ng.$rootScope.Scope ng-view 指令的角色是为当前路由把对应的视图模板载入到布局模板中。 AngularJS内置过滤器:http://code.angular...

彭博
2014/04/25
0
2
[Angular Material完全攻略] Day 02 - 环境设定 & 安装 & Hello World

今天我们将开始正式迈入Angular Material的世界,要学习使用Angular Material打造高品质及高质感的网页,当然要从安装Angular Material套件开始,本篇文章就来介绍基本的Angular Material安装...

readilen
05/21
0
0
Angular 6 正式发布:统一框架、Material 和 CLI 三大模块

Angular 6.0.0 已正式发布,新版本重点关注工具链以及工具链在 Angular 中的运行速度问题。Angular v6 是统一整体框架、Material 和 CLI 三大 Angular 组件的第一个版本,此次没有将重点放在...

雨田桑
05/04
0
30
AngularJS页面加载闪烁解决方案

AngularJS这个大杀器使得实现SPA(Single Page App)变得异常的简单,其双向绑定让页面内容的重新渲染无需编写大量JS代码,无需构造DOM字符串丑陋的,作为需要快速迭代,提高用户体现的下一代...

空心大白菜
2015/05/07
0
3
AngularJS 中文资料+工具+库+Demo 大搜集

中文学习资料: 中文资料且成系统的就这么多,优酷上有个中文视频。 http://www.cnblogs.com/lcllao/archive/2012/10/18/2728787.html 翻译的官方的Guide http://www.ituring.com.cn/miniboo...

liaolzy2
2015/05/31
0
0
[Angular Material完全攻略] Day 01 - 开始 & 简介

转载 从Angular第2版正式release后,根据全球最大工程师讨论区StackOverflow的统计,从2016开始的Angular讨论度就不断窜升,甚至超越了React,直到了2017年,甚至摆脱了前一代Angularjs的阴影...

readilen
05/21
0
0
简洁AngularJS框架后台管理系统bootstrap后台模板

最近在做一个后台管理的项目,但是没有设计图完全,所以就发现一款非常不错的模版。 这个模版是基于 AngularJS 和 bootstrap 的后台管理系统模版。 Minovate是 AngularJS 高级管理系统模板。...

VIP_web
06/26
0
0
AngularJS:跟随官方教程,一起构建一个简单的项目

AngularJS大白话简介: AngularJS是一个前端框架,和Bootstrap不同,他是一个为了构建 单页应用 而诞生的。Bootstrap是为了解决CSS样式和一些简单的互动(主要是提供了各种各样的样式,我们直...

那就远走
05/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

vue组件及路由理论知识

一、 组件component 1. 什么是组件? 组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码组件是自定义元素(对象) 2. 定义组件的方式 方式1:先创建...

一个yuanbeth
1分钟前
0
0
Saltstack配置之 nodegroups

#cd /etc/salt #mkdir master.d #vim node.conf //按组写入文件 nodegroups: client_all: 'L@192.168._._,192.168._._' clienta: 'L@192.168.192._' clientb: 'L@192.168.192._' #/etc/init......

硅谷课堂
8分钟前
0
0
expect(spawn) 自动化git提交和scp拷贝---centos(linux)

**在进行SCP文件拷贝中,往往需要进行用户密码的输入,即用户交互。若采用自动化脚本的方式进行,则可用以下方式: ** #!/usr/bin/expect #设置参数 set src [lindex $argv 0] set dest [lin...

helplove
12分钟前
1
0
用Build来构建对象的写法

如果一个类的属性过多,用构造器来构建对象很难写,因此我们时用Build方式来构建对象。写法大致如下。 import java.io.Serializable;import java.util.Date;public class Log impleme...

算法之名
14分钟前
11
0
利用 acme.sh 获取网站证书并配置https访问

acme.sh 实现了 acme 协议, 可以从 letsencrypt 生成免费的证书.(https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E) 主要步骤: 安装 acme.sh 生成证书 copy 证书到 nginx/ap...

haoyuehong
27分钟前
2
0
微擎框架内如何根据media_id获取到微信图片的路径

微擎的框架内,图片选择后,获取的是那个字符串是media_id,相当于你这张图片在微信的图片服务器里面的id 要求是:获取https://mmbiz.qpic.cn/mmbiz_jpg/…… 微信图片的路径 而微信并没有根据m...

老bia同学
31分钟前
2
0
Spring boot中日期的json格式化

Model 在model层中,类的日期属性上面添加如下注解: @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss") 参考 Jackson Date格式化教程...

亚林瓜子
33分钟前
2
0
Eclipse:Failed to load the JNI shared library

1.问题背景: 由于我之前使用jdk1.9学习,当使用Luke的时候发现jdk版本过高,需要向下配置jdk,就向朋友拷了一个安装包。重新配置路径后,便开始报错。 2.问题描述: Failed to load the JNI...

tinder_boy
35分钟前
1
0
少儿学习编程课程是否真的适合七八岁的低龄儿童[图]

少儿学习编程课程是否真的适合七八岁的低龄儿童[图]: 天下熙熙皆为利来,天下攘攘皆为利往。 这几年来,乐高教育机构在国内如同雨后春笋般出现,当然关闭/转手的也很多。从教师角度来看,部...

原创小博客
41分钟前
1
0
ES12-词项查询

1.词项查询介绍 全文查询将在执行之前分析查询字符串,但词项级别查询将按照存储在倒排索引中的词项进行精确操作。这些查询通常用于数字,日期和枚举等结构化数据,而不是全文本字段。 或者,...

贾峰uk
49分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部