建议和反馈

请填写你的反馈内容

深入了解ANGLE 2架构和功能-1

2019-10-04 ·2045次阅读 ·读完需要27分钟

Angular 1基于MVC体系结构,而Angular 2基于组件和服务体系结构。Angular 1和Angular 2在架构和API方面完全不同,因此以前对Angular 1的了解不太可能对您学习Angular 2有很大帮助。在本文中,我们将在不将Angular 2与Angular 1进行比较的情况下学习Angular 2。会造成混乱,这是不必要的。即使您不了解Angular 1,也可以继续阅读本文。

我们将涵盖以下主题:

  1. Web组件

  2. Angular 2架构

  3. 范本语言

  4. 组件输入和输出

  5. 组件生命周期

  6. 大事记

  7. 形式

  8. 服务

  9. 更多…

Angular 2架构

Angular 2是一个基于服务和组件体系结构构建Web应用程序客户端的框架。

Angular 2应用程序由视图和各种服务组成。服务是保存应用程序逻辑和状态的简单JavaScript对象。服务应该是可重用的。视图消耗服务,并且服务也可以彼此交互。
视图和服务是松散耦合的,因此Angular 2视图可与其他任何体系结构(例如Flux)一起使用。同样,服务可以与其他任何视图一起使用,例如React。
Angular 2视图基于面向组件的体系结构。在面向组件的体系结构中,应用程序UI分为可重用的组件。组件的UI带有用于更新UI并处理UI上的用户操作的代码。自定义标签与组件相关联,并且每当自定义标签出现时,都会创建并呈现该组件的新实例。因此,可以说面向组件的体系结构是针对应用程序视图的体系结构。实际上,组件消耗服务。

这是来自Angular 2官方网站(https://angular.io)的图表,显示了Angular 2的完整体系结构:

角度2概述

 

在这里,您可以看到Component的UI 是使用Template定义的模板是使用模板HTML(即HTML和许多其他标记的组合)编写的。组件还保存UI的状态和UI的事件处理程序。
我们不应该在组件内部存储应用程序逻辑和状态,因为它会影响代码的可重用性并在开发大型复杂应用程序时引起问题。应用程序状态和逻辑应存储在服务中。
Angular 2仅实现单向数据绑定。这使得大型复杂的应用程序更易于调试。服务被注入到需要它们的特定组件中,而不是全部
组件中。

Web组件介绍

在学习Web组件之前,您需要知道为什么我们要学习它们。好吧,我们正在学习Web组件,因为Angular 2组件利用了影子DOM和模板,它们是Web组件的一部分。
简而言之,Web组件是四个不同浏览器规范的集合,这些规范使能够在Web页面中创建可重用组件。这四个规范是HTML导入shadow DOM模板自定义元素它们可以一起使用,也可以分开使用。
Web组件提供了面向组件的体系结构的本地实现。使用Web组件创建的组件也称为Web组件。
在学习Web组件之前,让我们考虑一个用于演示目的的项目。创建一个名为web-components的目录,然后在其中创建一个名为index.html的文件。Web组件对浏览器的支持很差,因此让我们下载webcomponents.js polyfill。从https://github.com/webcomponents/webcomponentsjs下载webcomponents.js文件,并将其放置在web-components目录中。
现在,将此代码放在index.html文件中:
<!doctype html> 
<html> 
<head> 
<title> Web组件演示</ title> 
<script src =“ webcomponents.js”> </ script> 
</ head > 
<body> 
<script> 
//在此处放置JavaScript代码
<


现在,通过构建一个组件来显示具有图像,标题和描述的卡片,来概述阴影DOM,模板和自定义元素。

范本

模板用于定义可重用的代码。使用
<template>标签定义模板。模板的代码位于此标记内。我们可以放置任何标签,例如<script>和<style>。
<template>标记内的代码仅被解析,而不呈现。
这是如何创建模板的示例。将此代码放在body标签中:
<template id =“ cardTemplate”> 
<style type =“ text / css”> 
.container 

width:250px; 向左飘浮; 
右边距:10px; 
}

img 

宽度:100%; 

</ style> 
<div class =“ container”> 
<img src =“” /> 
<div> 
<h3> </ h3> 
<p> </ p> 
</ div> 
</ div> 
</ template> 
在这里,模板包含卡组件的UI代码。现在,如果您在浏览器中打开index.html文件,您将看不到任何内容,因为<template>标签仅被解析而不呈现。


自定义元素

通过自定义元素,我们可以定义HTML元素的新类型(即
HTML标签的新类型)。当我们使用浏览器无法识别的标签名称时,浏览器只是将其视为<span>标签。但是,当我们注册一个自定义标签时,它会被浏览器识别。它可以继承其他元素,让我们在元素生命周期的不同阶段执行不同的操作,等等。
让我们为组件创建一个自定义元素。无论标签出现在何处,都会显示该组件的新实例。
这是显示自定义元素的代码。将其放在<body>标记中:
<custom-card data-img =“ http://placehold.it/250x250” data- title =“标题1” data-description =“描述1”
<custom-card data-img =“ http://placehold.it/250x250” data- title =“标题2” data-description =“描述2”> </ custom-card> 
我们必须在其中使用-字符自定义元素名称。这是强制性的,因为此限制允许解析器将自定义元素与常规元素区分开,并确保将新标签添加到HTML时的向前兼容性。在这里,我们将组件的属性作为数据属性传递。
现在,让我们将<custom-card>定义为自定义元素,并在创建<custom-card>的新实例时将模板代码放在标签中。为此,请将此代码放在<script>标记中:
var customCardProto = Object.create(HTMLElement.prototype); customCardProto。
var template = document.querySelector(“#cardTemplate”); template.content.querySelector(“ img”)。src = this.getAttribute(“ data-img”); template.content.querySelector(“ h3”)。innerHTML = this.getAttribute(“ data-title”); template.content.querySelector(“ p”)。innerHTML = this.getAttribute(“ data-description”);

var clone = document.importNode(template.content,true); this.appendChild(clone)

var customCard = document.registerElement(“ custom-card”,{prototype:customCardProto 
});

代码的工作方式如下:

  1. 默认情况下,自定义元素继承HTMLElement的方法和属性。

  2. 要注册自定义元素,我们需要使用文档。registerElement方法。第一个参数是自定义标记名称,第二个参数是可选对象。这个可选对象可以采用称为prototype的属性prototype属性定义了它继承的HTML元素,即它继承的HTML元素的属性和方法。默认情况下,它被分配给Object.create(HTMLElement。prototype)。

  3. 我们还可以通过向分配给原型属性的对象添加新的属性和方法,来向自定义元素添加新的属性和方法。

  4. 在这里,我们添加了一个名为createdCallback的方法,该方法在创建自定义元素的实例(即使用JavaScript或HTML创建的实例)时被调用。

  5. 在createdCallback内部,我们将检索模板并设置图像源,标题和说明,然后通过创建其副本将其附加到自定义元素,因为许多自定义元素将共享同一模板。

现在,如果在浏览器中打开index.html,将看到以下输出:
学习角度js

 

影子DOM

Shadow DOM允许HTML元素获得一种与之关联的称为影子根的新型节点。具有与之关联的影子根的元素称为影子主机。影子主机的内容未渲染;而是渲染阴影根的内容。影子根可以在其下具有另一个影子根。
影子DOM的好处在于,在影子根内部定义的CSS样式不会影响其父文档,而在影子根外部定义的CSS样式不会影响影子根内部的元素。这对于定义特定于组件的样式很有用。简而言之,我们可以说影子DOM提供了样式封装。
样式封装不是影子DOM的唯一好处。防止阴影根内部的HTML受到JavaScript的意外修改。我们仍然可以在浏览器开发人员工具中检查影子根。
许多本机元素(例如<video>和<audio>)都有一个影子根,但是当您检查它时,您将看不到影子根。默认情况下,浏览器会隐藏这些元素的阴影根。要查看其影子根,您需要更改特定于浏览器的设置。
让我们修改前面的自定义元素代码,以在阴影DOM中渲染模板。将此替换为以前的
createdCallback 方法:customCardProto.createdCallback = function(){
var template = document.querySelector(“#cardTemplate”); template.content.querySelector(“ img”)。src = this.getAttribute(“ data-img”); template.content.querySelector(“ h3”)。innerHTML = this.getAttribute(“ data-title”); template.content.querySelector(“ p”)。innerHTML = this.getAttribute(“ data-description”);

var clone = document.importNode(template.content,true); var shadow = this.createShadowRoot(); 
shadow.appendChild(clone); 

在这里,而不是直接附加模板代码到自定义元件,我们创建了使用createShadowRoot阴影根和所附模板代码给它。

设置Angular 2项目

Angular 2代码可以用JavaScript,TypeScript或Dart编写。如果您使用TypeScript或Dart编写Angular 2代码,则需要先将代码转换为JavaScript,然后再提供给客户端。我们将使用JavaScript编写Angular 2代码。
创建一个名为angular2-demo的目录。然后,在目录内创建应用程序。js和package.json文件。然后,创建一个名为public的目录,并在该目录内创建另外四个名为html,js,componentTemplates和componentStyles的目录。现在,创建一个名为index.html的文件并将其放置在html目录中。
然后,下载angular2-polyfills.js,Rx.umd.js和angular2-all.umd。来自https://cdnjs.com/libraries/angular.js/的js,并将其放置在angular2-demo / js目录中。这些文件听起来像。如果需要,您也可以直接将CDN链接排队。
在index.html文件中,放置以下起始代码:
<!doctype html> 
<html> 
<head> 
<title> Angular 2 Demo </ title> 
</ head> 
<body>

<script src =“ / js / angular2-polyfills.js”> </ script> 
<script src =“ / js / Rx.umd。js”> </ script> 
<script src =“ / js / angular2-all。 umdn.js“> </ script> 
<script> 
//此处是应用代码
</ script> 
</ body> 
</ html> 
在app.js文件中,放置以下代码:
var express = require(” express“); var app = express(); 
app.use(express.static( 目录名+“ / public”)); app.get( “/”,函数(的HttpRequest,HttpResponse对象,下一个){ 
httpResponse.sendFile( 目录名+ “/public/html/index.html”); 
})

app.listen(8080);


这是服务器端代码。这是不言自明的。
现在,在package.json文件中,放置以下代码并运行npm install以下载快递包:

“ name”:“ Angular2-Demo”,“ dependencies”:{ 
“ express”:“ 4.13.3” 


To启动服务器,运行节点app.js。然后,使用localhost:8080作为浏览器中的地址打开应用程序。

Angular 2基础

Angular 2应用程序已完全拆分为多个组件。从技术上讲,Angular 2组件是一个可重用的自定义标签,该标签是可变的并封装有嵌入状态,即,对状态或属性的更改将使UI发生变化。

该应用程序的所有组件都以树结构排列,其中一个组件为根节点。
这是如何创建组件的示例。它创建一个显示图像,标题和描述的卡片组件。将此代码放在<script>标记中:
var Card = ng.core.Component({选择器:“ card”,
输入:[“ src”,“ title”,“ desc”],templateUrl:“ templates / card-template .html“,styleUrls:[” templateStyles / card-style.css“] 
}). 
Class({ 
构造函数:function(){ 

})

 

然后,创建一个名为card-template.html的文件,并将其放置在
componentTemplates目录中。将此代码放在文件中:
<style> 
.container 

width:250px; 向左飘浮; 
右边距:10px; 
}

img 

宽度:100%; 

</ style> 
<div class =“ container”> 
<img src =“ {{src}}”“ /> 
<div> 
<h3> {{title}} </ h3> 
<p> {{desc}} < / p> 
</ div> 
</ div> 
之后,创建一个名为card-style.css的文件并将其放置在componentStyles 
目录中。将此代码放在文件中:
.container 

width:250px; 向左飘浮; 
右边距:10px; 
}

img 

宽度:100%; 

这是这三个代码片段是如何工作的:

  1. 需要通过链接属于ng.core对象的Component和Class方法来创建组件。

  2. Component方法采用具有各种属性的配置对象,而Class方法采用具有组件生命周期方法,构造函数和UI操作处理程序的对象。

  3. 在这里,我们提供的配置属性是选择器,输入,templateUrl和styleUrls。selector属性用于定义组件的自定义标签。输入属性用于定义定制标记采用的属性。templateUrl属性用于定义包含组件模板的文件。如果要内联模板代码,也可以使用模板。最后,styleUrls用于定义包含组件样式的CSS文件。您也可以使用styles属性内联CSS代码,也可以使用

模板本身内的<style>标记。以这三种方式中的任何一种定义的CSS都不会影响其他组件,也就是说,它封装在组件本身中。

  1. 在Class方法中,即使不执行任何操作,我们也必须提供构造方法。在构造组件的新实例期间调用它。所谓组件的构造,是指在内存中构造组件,而不是解析属性,解析其子级,渲染其视图等等。构造函数方法的主要用途是将服务注入到组件中。无法自动注入服务,因为有时我们可能需要为每个组件初始化服务,并且Angular不知道如何执行此操作。构造方法可以访问组件的状态,但不能访问其属性。在这里,我们不应该做任何繁重的工作或其他会减慢速度的事情

或导致组件构造失败。构造函数不是组件生命周期方法。

  1. 然后,我们有了组件模板代码。在此模板文件中,我们只是呈现传递给组件的属性。要呈现处于组件状态的任何内容,我们需要使用{{}}令牌。

 

让我们创建另一个名为Cards的组件,它显示一个卡列表。它从服务获取有关卡的信息。
将此代码放在index.html文件的<script>标记中:
var CardsService = ng.core.Class({构造函数:function(){ 
},
getCards:function(){return [{ 
src:“ http:// placehold.it/350x150”,标题:“标题1”,
描述:“描述1” 
},

src:“ http://placehold.it/350x150”,标题:“标题2”,
描述:“描述2” 
},
{


 

 


});


src:“ http://placehold.it/350x150”,标题:“标题3”,
desc:“描述3” 
}]


var Cards = ng.core.Component({选择器:“ cards”,viewProviders:[CardsService],指令:[Card],
templateUrl:“ componentTemplates / cards-template.html” 
})。Class({ 
构造函数:[CardsService,函数(cardsService){this.getCards = cardsService.getCards; 
}],
ngOnInit:函数(){this.cards = this.getCards(); 

})

var App = ng.core.Component({选择器:“ app”,指令:[Cards],
templateUrl:“ componentTemplates / app-template.html” 
})。Class({ 
构造函数:function(){


}

ng.platform.browser.bootstrap(App); 
现在,在componentTemplates 
目录中创建一个名为cards-template.html的文件,并将此代码放在其中:
<card * ngFor =“#card of cards” title =“ {{{card.title}}” src =“ {{card .src}}“ desc =” {{card.desc}}“> </ card> 
现在,在componentTemplates目录中创建一个名为app-template.html的文件,并将此代码放入其中:
<cards> </ cards> 
现在,在index.html文件的<body>标记中,放置以下代码:
<app> </ app> 
这是这四个代码段的工作方式:

  1. 要创建服务,我们需要使用ng.core.Class方法。它使用带有构造函数方法和服务公开的其他方法或属性的对象。将服务注入其他服务或组件时,将创建并注入服务的新实例。创建服务的新实例时,将调用构造方法。即使它没有任何作用,我们也必须提供此方法。此方法的主要目的是注入该服务所依赖的服务。在这里,我们的CardsService方法不依赖于任何其他服务,因此构造函数方法中没有代码。然后,我们定义了一个getCards

方法,该方法返回要显示的三个不同卡的数据。

  1. 然后,我们创建了一个Cards组件。它从CardsService获取数据,并为每个卡数据呈现一个Card组件。在创建Cards组件时,我们为配置对象提供viewProviders和伪指令属性。viewProviders是组件的服务列表

依赖,并且伪指令是此组件提供的其他组件的列表。在这里,您可以看到,我们没有直接向构造函数属性分配函数,而是为数组分配了组件依赖的服务列表,最后一个数组项作为实际函数。这是将服务注入组件的格式。在构造函数方法内部,我们存储对组件所需的服务的方法或属性的引用,也就是说,可以在构造函数方法内部使用服务。稍后我们将了解有关viewProviders的更多信息。
传递给Class方法的任何方法中的this关键字均指向
到组件的状态。创建组件实例后,只要组件状态改变,模板绑定就会更新。我们这里还有另一个方法,叫做ngOnInit。这是一个生命周期方法,在创建组件的新实例并解析其属性后会调用该方法。在其中,我们调用getCards方法并将返回的值存储在状态的cards属性内。请注意,在创建组件实例之后,可以使用this关键字访问传递到组件标签的属性。

  1. 在CardsComponent模板的内部,我们使用* ngFor指令显示卡。稍后我们将学习有关指令的更多信息。

  2. 然后,我们创建一个App组件,该组件充当我们组件的根。在此组件内部,我们将显示“卡片”组件。

  3. 最后,我们初始化应用程序。Angular 2应用程序已显式初始化。在初始化它时,我们需要提供对根组件的引用。这样做是为了确保应用程序始终由嵌套组件组成。根组件是添加到<body>标签的组件。将其他组件的标签添加到body标签将不会执行任何操作。

现在,如果您在浏览器中刷新localhost:8080页面,您将看到以下输出:
学习角度js

样式化组件和阴影DOM

之前,我们看到了三种定义组件特定样式的方式(封装在组件模板范围中的样式)。组件的CSS甚至不会影响它拥有的组件。
默认情况下,Angular 2不使用影子DOM。相反,它使用另一种技术来实现样式封装。这是由于缺乏浏览器支持。
默认情况下,Angular 2修改CSS选择器的方式仅使其定位到组件中的元素,然后将CSS放置在页面的<head>标记中。如果使用浏览器开发人员工具检查我们当前的应用程序,则会看到以下内容:
学习角度js

在这里,您可以看到CSS已被修改并插入到<head>标记中。为了强制Angular 2使用阴影DOM,我们需要将组件配置对象的encapsulation属性分配给ng.core.ViewEncapsulation。本机。默认情况下,它已分配给ng.core.ViewEncapsulation.Emulated。
将Card和Cards组件的封装属性分配给ng.core.ViewEncapsulation.Native后,当您检查应用程序时,您将看到类似以下内容:
学习角度js

在这里,您可以看到阴影DOM用于实现样式封装。

Angular 2变化检测

变化检测是检测组件状态变化的过程。组件的状态使用this关键字进行存储和操作。因此,Angular 2没有直接的方法来检测状态何时改变。因此,Angular 2使用复杂的算法和第三方库来检测状态变化。
Angular 2用于检测状态更改的第一件事是,它假装所有更改都是异步发生的。然后,它使用zone.js库监视浏览器事件,计时器,AJAX请求,WebSocket和zone.js支持的其他异步内容。
现在,无论何时发生任何这些异步活动,它都会检查可能更改的所有内容,包括对象属性和根节点中所有组件的this关键字的array元素;如果检测到任何更改,则将更新组件的模板绑定。Angular 2不仅可以重新渲染整个组件。相反,它将检查已更改的绑定,并专门选择和更新它们。
某些组件可能具有很多状态数据,并且如果每个组件的状态未更改,则检查每个异步操作的状态将不必要地影响应用程序性能。因此,Angular 2提供了一个标记此类组件的选项,以便除非组件本身告诉Angular 2在下一个检测周期(即下一个异步活动发生时)检查其状态,否则它不会检查其状态。让我们看一个例子来证明这一点。
将此代码放在索引的<script>标记中的App组件代码上方。html文件:
var SampleComponent1 = ng.core.Component({选择器:“ sampleone”,
模板:“ {{value}}”,
viewProviders:[ng.core.ChangeDetectorRef],changeDetection:ng.core。
})。Class({ 
构造函数:[ng.core.ChangeDetectorRef,function(cd){this.cd = cd; 
}],
ngOnInit:function(){this.value = 1; setInterval(function(){ 
this.value ++ ; this.cd.markForCheck(); 
} .bind(this),2000)

})
然后,将SampleComponent1添加到App组件的指令数组中。因此,现在,App组件的代码应为:
var App = ng.core.Component({选择器:“ app”,
指令:[Cards,SampleComponent1],
templateUrl:“ componentTemplates / app-template.html” 
})。 ({ 
构造函数:function(){ 

})
现在,将此代码添加到app-template.html文件的末尾:
<br style="clear: both"> 
<sampleone> </ sampleone> 
这三个代码段的工作方式如下:

  • 在此示例中,我们显示的值每2秒增加一次,然后重新渲染模板以显示更新的值。

  • 首先,我们创建一个名为SampleComponent1的组件。它只是显示价值。我们已将changeDetection属性设置为ng.core。ChangeDetectionStrategy.Detached,它告诉Angular 2不要检查其状态更改。默认情况下,changeDetection属性分配给ng.core.ChangeDetectionStrategy.Default,它告诉Angular 2在每个更改检测周期内检查其状态更改。然后,我们将ng.core.ChangeDetectorRef服务注入该组件,该服务提供了与更改检测相关的各种API。然后,在ngOnInit方法中,我们每2秒增加value的值,此后我们调用ng.core.ChangeDetectorRef的markForCheck方法,该方法告诉Angular 2在下一次更改期间检查组件状态的更改-检测周期。

  • 然后,我们仅在App组件中显示SampleComponent1。

如果组件仅依赖于其输入和/或UI事件,或者想要更改组件的状态,则仅检查其输入是否已更改或事件是否已触发;然后,您可以将changeDetection分配给ng.core。ChangeDetectionStrategy.OnPush。

 



评论(0)问答(0)
请先登录或注册

请先登陆或注册

相关推荐

捷报频传!SVT和GA强势上线FCion交易所,领涨市场!

科技的发展日新月异,信息的交替层出不穷。2019年,区块链技术自诞生至此,已走过了十余年。在其发展过程中,造就了几次风口:第一次风口,大约在2013年,主要研究加密数字货币在各领域的应用,最后诞生了R......
eason1688 · 2019-11-11
258阅读 · 0赞赏 · 0问答

加密货币钱包现状和未来发展

在区块链应用场景中,钱包是第一个落地应用的项目,也是加密货币的关键基础设施,同时,每一种加密货币的交易方式都是仰仗钱包进行。目前,加密钱包种类繁多,据调查发现,有近4亿美元资金流向加密钱包业务,其中以......
smallfish · 2019-11-11
193阅读 · 0赞赏 · 0问答

BitDATA纽约大会强势来袭,Spinach带你亮点抢先看!

2019年,区块链行业热闹非凡。随着中国提出把区块链作为核心技术自主创新重要突破口,指出区块链技术应用已经延伸到数字金融、物联网、智能制造、供应链管理、数字资产交易等多个领域。在此背景之下,一场区块链......
eason1688 · 2019-11-09
526阅读 · 0赞赏 · 0问答

热钱包与冷钱包解决方案

随着市值的加密货币一天一天地增长,越来越多的人正在寻找更好的解决方案以将其硬币存储在加密钱包中。在谈论钱包时,更容易获得带有优惠券,美元钞票,旧收据,硬币等的破损皮革钱包的图像。但是,加密钱包是一种更......
老虎or猫咪 · 2019-11-08
231阅读 · 0赞赏 · 0问答

技术领先,合作共赢!Spinach的品牌崛起之路!

王兴在做美团成功后,曾经分享过一个“四纵三横”理论。讲解他当时是如何屡次踩对风口。纵轴就是关于技术的进化,而横轴是该技术对四个领域(游戏、资讯、社交、商务)的波及。当区块链的新技术兴起,在这四个领域的......
eason1688 · 2019-11-07
507阅读 · 0赞赏 · 0问答

GFC是什么,如何安装、注册GFC钱包?

什么是GFC?GFC是由Masternodes加入的开源对等 权益证明 加密货币。GFC货币使用与Dash&PivX相同的技术,但使用的算法已针对re仪业进行了重组。GFC的设计和开发使其成为支付全球......
呼近乎出 · 2019-11-06
352阅读 · 0赞赏 · 0问答

Moon

2176

LK币

16

粉丝

37

笔记

感谢"Moon"

这篇精彩的笔记,目前已经帮助

  • 0
  • 2
  • 0
  • 4
  • 5
喜欢0
链客社群 加入

微博进入

商务合作>

广告投放>

公司名称:北京链客行科技有限公司

联系方式:010-67707199

ICP备案号:京ICP备18032136号

Copyright:链客区块链技术问答社区 版权所有

感谢您的提问,问题被社区永久收入以便新人查看。一定要记得采纳最佳答案哦!加油!

感谢您的善举,每一次解答会成为新人的灯塔,回答被采纳后获得20算力和相应的LK币奖励

您将赞赏给对方2LK币的奖励哦!感谢您的赞赏!

您将赞赏给对方2LK币的奖励哦!感谢您的赞赏!