Change detection and optimizations
Angular携带的change detection框架是用来在组件渲染时决定输入是否有改变的。组件需要对组件树中某处的改变做出反应。改变总是被一些异步活动所触发(例如用户和页面的交互),当改变发生时,应用的状态或数据就有机会发生改变。这种例子包括用户行为、interval/timer,回调函数等
JS中的setInterval和setTimeoutAPI在Angular的管理范围之外,所以Angular提供了可以检测的对应版本。类似的,Angular的事件绑定也可以被此机制检测到。当change detection机制被触发,它会从组件树的顶部向下检查每个节点,看是否组件模型是否改变和需要渲染。这就是为什么input属性必须被Angular知道,否则它在机制中无法被识别
Angular有两种实现机制的方式。Default模式总是检查在机制周期中改变的组件。Angular对此过程做了很多优化,所以效率很高。大多数情况下在毫秒级别。这在组件中的数据频繁变动是很有用的,但是很难保证哪些不变的数据。对于OnPush模式,它会告诉Angular,只有在组件的input被改变时才需要检查。这意味着如果一个父组件没有改变,那么子组件的input不会改变,所以直接跳过change detection。因为一个input改变并不代表组件本身发生改变:可能input是一个包含组件没有使用的改变了的属性的对象。所以保持对数据结构的关注可以帮助优化,当数据被传递并且change detection被触发

组件之间的交互
通过input可以将数据从父组件传送到子组件,通过事件绑定可以将数据和通知从子组件传送到父组件
给组件添加样式和encapsulation模式
总是会有一些全局的css来控制应用整体的样式,但是每个组件可以保持它们自己的样式,独立于其它组件而渲染。如果你为组件添加了css,这些样式不是全局暴露的。你应该避免在一个组件上尝试对其它组件的样式做修改。有很多方法给组件添加样式,最好在所有组件上以同样的方式添加样式,否则混合多种方法会带来意料之外的结果
你永远可以将CSS作为全局格式添加进组件,通过将css文件放在index.html或者在.angular-cli.json文件中的styles属性中引用文件。这些属性是全局的,会应用到每一个满足条件的元素上
要更好的隔离样式,作者提供了几个方法
- Inline CSS -- 组件模板可以有inline CSS或者style属性来设置元素属性,这个默认的HTML添加样式的方法
- Component-linked CSS -- 使用组件的
styleUrls属性来引用外部css文件 - Component inline -- 使用组件的
styles属性,通过CSS规则数组来让Angular注入样式
如果同样的css规则在多个地方声明,覆盖的顺序是(上覆盖下)
- Inline style attribute rules
- Inline style block rules in the template
- 组件的styles规则或者styleUrls规则,如果两个都有,则后面的优先级高
- Global CSS rules
当应用开始渲染,组件会被加载,这些样式会添加到文档的head部分,依赖于encapsulation模式,这些样式被渲染的方法会改变这些样式被处理的方法。上述结论都是在使用CLI构建工具的情况下建立的
Angular希望你可以构建模块化的组件,一个关键在于保证CSS样式不会影响其它部分的样式,这叫做styling encapsulation。一般是用指定特殊的类名,再根据类名来写样式。但是类名(第三方库)会影响同样的类名在其它地方的使用。Shadow DOM提供了一系列特性保证样式不会影响组件外的内容(可能不适用于老的浏览器)
Angular有三种encapsulation模式处理view,之前的例子中使用的都是Emulated模式
- None -- 在渲染过程中不使用encapsulation,组件DOM遵循CSS的一般规则。在注入到App之后模板不会被修改,只会将模板中style块的内容移到文档head中
- Emulated -- 通过运行时添加独特的CSS选择器给你的CSS规则来模拟样式,CSS可以轻松从全局规则应用到组件上
- Native -- 使用原生的Shadow DOM来提供样式和标记处理,提供了最好的encapsulation。所有的样式被注入到shadow root,因此适用于组件。所有的模板或者样式不会被组件外看到
No Encapsulation Mode
它将组件渲染成为HTML文档。这个没有任何样式的组件的默认模式。要设置这个模式,通过在组件元数据中指定encapsulation: ViewEncapsulation.None(要提前从core中引入ViewEncapsulation)。此模式下,所有组件的样式会被放在HTML文档的head中。这是注入全局CSS规则的方式。以下是你应该使用或者避免使用这个模式的理由
- style bleed out -- 有时通过css库设计的应用对于组件内部的样式是没有必要处理或者不希望处理,那么不需要设置encapsulation模式
- Global styles bleed in -- 全局的样式由于没有encapsulation,所以会暴露出去
- Templates are unmodified -- 因为这个模式就是将模板按照它的样子注入,所以DOM元素不会有任何数据改变的应用
在使用这个模式的情况下,不能使用任何Shadow DOM的选择器,例如:host/::shadow
Emulated Shadow DOM Encapsulation Mode
这种模式通过向HTML标记和CSS规则添加独特的属性来应用样式,增加了CSS规则的指向性。因为这并不是真正的encapsulation,所以叫做emulated(模拟),但是有很多好处,它是Angular定义样式的组件的默认模式
这个模式主要是为了不让组件内部的样式流出到全局规则。为此,view会渲染模板,然后通过独特的属性来添加样式来增加组件中CSS规则的指向性。encapsulation: ViewEncapsulation.Emulated显示指定此模式。在渲染时,样式首先从组件模板或属性中抽出来,然后加上独特的前缀,这些元素就可以使用独特的CSS选择器(同一个组件的多个实例的属性名称相同)。使用或者不使用它的理由
- Styles are isolated -- 独特的属性名可以让CSS规则不与全局规则冲突
- Styles bleed in -- 全局的规则仍然可以影响组件,这样可以使通用的样式有效
- Unique selectors -- 渲染后的DOM得到了独特的属性,如果你你想在全局控制这些样式,则需要使用特殊的选择器
Native Shadow DOM Encapsulation Mode
使用Shadow DOM,模板和样式能真正和应用的其余部分分离。兼容性问题。在组件渲染时,它创建了shadow root(在组件中),模板被注入到shadow root中,伴随着样式和各种父组件。当文档越来越多,shadow root保护内容不让组件外面的部分看到。Angular希望嵌套的组件应该可以共享样式,通过shadow root,Angular让这些样式通过注入到shadow root的方式来让组件可用。使用或者不使用的理由
- Uses Shadow DOM -- 对于真正的encapsulation,native是最好的选项
- Parent and sibling styles bleed in -- 由于Angular的渲染组件的方式,它会将父和兄弟组件的样式都注入到shadow root,所以会有向内影响的问题
- Limited support -- 浏览器支持有限
Dynamically rendering components
应用有时需要根据状态动态渲染组件。一些需要动态渲染的例子
- Modal,动态弹出的内容
- 有条件弹出的alert
- 动态内容的展示
- 之后会被折叠的内容
这些例子的共同特点是它们不总是需要显示。Angular提供了API来让我们渲染不是一直存在于模板的内容
当我们想动态渲染组件,Angular需要知道什么组件将被渲染,在哪渲染,在哪可以得到它的一份拷贝。这些发生在任何模板的编译过程中。我们要调用的API包括
- ViewContainerRef -- 引用应用中Angular理解的元素,在这个元素上渲染组件
- ViewChile -- 在controller中可以引用ViewContainerRef类型的对象,以此获得访问渲染组件API的能力
- ComponentFactoryResolver -- 一个Angular的服务,获取组件工厂(可以渲染的组件)
浙公网安备 33010602011771号