AngularJS视图和指令
AngularJS视图和指令简介
在本教程的第一篇文章中,我们了解了AngularJS如何将应用程序拆分为视图,控制器和模型(MVC)。本文将深入探讨如何创建AngularJS视图。
在开始之前,让我首先建立一个简单的AngularJS应用程序,我们可以使用它来处理本文中的示例:
<!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js"></script> </head> <body ng-app="myapp"> <div ng-controller="MyController" > <span></span> </div> <script> angular.module("myapp", []) .controller("MyController", function($scope) { //empty controller function }); </script> </body> </html>
AngularJS指令
AngularJS视图将模型中的数据混合到HTML模板中。我们可以使用AngularJS指令来告诉AnguluarJS如何将数据混合到HTML模板中。本文将介绍最常用的AngularJS指令。
插补指令
插值指令是AngujarJS中最基本的指令之一。插值指令将表达式的结果插入HTML模板。我们可以使用{{}}
标记来标记要其中插入表达式的位置。这是一个例子:
<div ng-controller="MyController" > <span>{{myData.text}}</span> </div>
HTML模板包含在具有ng-controller属性的div元素中。在HTML模板中是一个span
元素,其中是一个插值指令。该指令指示AngularJS在给定位置插入数据值" myData.text"。
插值指令还可以插入从模型对象的函数返回的数据。这是一个例子:
<div ng-controller="MyController" > <span>{{myData.textf()}}</span> </div> <script> angular.module("myapp", []) .controller("MyController", function($scope) { $scope.myData = {}; $scope.myData.textf = function() { return "A text from a function"; }; }); </script>
在此示例中,插值指令`{{myData.textf()}}将在$ scope模型对象上调用myData.textf()函数,并将该函数返回的文本插入HTML模板。
如示例所示,将textf()函数插入控制器函数内的$ scope.myData对象中。
ng-bind指令
ng-bind指令是插值指令的替代方法。我们可以通过在AngularJS想要插入数据的HTML元素中插入一个ng-bind属性来使用它。这是一个例子:
<div ng-controller="MyController" > <span ng-bind="myData.textf()"></span> </div>
这将从myData.text()函数返回的数据插入到span元素的主体中。请注意,在ng-bind
属性内的表达式周围,并不需要{{}}
。
从模型转义HTML
如果从模型获得的数据包含HTML元素,则在将它们插入HTML模板之前会对其进行转义。转义表示HTML显示为文本而不是HTML。
这样做是为了防止HTML注入攻击。例如,在聊天应用程序中,可能有人将带有JavaScript的<script>元素插入聊天消息中。如果未转义此元素,则任何看到聊天消息的人都可能执行了<script>元素。使用HTML转义时,<script>元素将仅显示为文本。
我们可以使用ng-bind-html-unsafe指令来禁用HTML转义,如下所示:
<div ng-controller="MyController" > <span ng-bind-html-unsafe="myData.textf()"></span> </div>
在禁用HTML转义时,我们应该非常小心。确保没有显示不受信任的HTML。
有条件的渲染
AngularJS可以显示或者隐藏HTML,具体取决于模型中数据的状态。我们可以使用为此目的专门创建的一组AngularJS指令来执行此操作。我将在以下各节中介绍这些指令。
ng-show + ng-hide指令
ng-show和ng-hide指令用于根据模型中的数据显示或者隐藏HTML元素。这两个指令执行相同的操作,但彼此相反。这是两个示例:
<div ng-controller="MyController" > <span ng-show="myData.showIt"></span> <span ng-hide="myData.showIt"></span> </div> <script> angular.module("myapp", []) .controller("MyController", function($scope) { $scope.myData = {}; $scope.myData.showIt = true; }); </script>
这个例子创建了两个span
元素。一个有一个ng-show指令,另一个有一个ng-hide指令。这两个指令均会查看" myData.showIt"布尔变量,以确定它们是否应显示或者隐藏" span"元素。如果模型值是true,则ng-show指令将显示该元素,如果模型值是false,则ng-show指令将隐藏该元素。 ng-hide指令将执行相反的操作:如果模型值为true,则隐藏span
元素,如果模型值为false,则显示它。
注意控制器功能如何将" myData.showIt"设置为" true"。这意味着上面的示例将显示第一个span元素,而隐藏第二个span元素。
HTML元素(在这种情况下为span
元素)是使用CSS属性display:none;
隐藏的。这意味着HTML元素仍然存在于DOM中。它们只是不可见。
ng-switch指令
如果要基于模型中的数据从DOM中添加或者删除HTML元素,则使用ng-switch指令。这是一个例子:
<div ng-controller="MyController" > <div ng-switch on="myData.switch"> <div ng-switch-when="1">Shown when switch is 1</div> <div ng-switch-when="2">Shown when switch is 2</div> <div ng-switch-default>Shown when switch is anything else than 1 and 2</div> </div> </div> <script> angular.module("myapp", []) .controller("MyController", function($scope) { $scope.myData = {}; $scope.myData.switch = 3; }); </script>
这个例子包含一个带有ng-switch属性和on属性的div元素。 " on"属性指示要打开模型中的哪些数据。
在div元素内部是三个嵌套的div元素。前两个嵌套的div
元素包含一个" ng-switch-when"属性。这个属性的值告诉父div的on属性中引用的模型数据应该具有什么值,以使嵌套的div可见。在此示例中,当myData.switch为1时,第一个嵌套的div是可见的;当myData.switch为2时,第二个嵌套的div是可见的。
第三嵌套div具有ng-switch-default属性。如果没有其他匹配的ng-switch-when指令,则显示具有ng-switch-default属性的div。
在上面的示例中,控制器功能将myData.switch设置为3. 这意味着将显示具有ng-switch-default属性的嵌套div。另外两个嵌套的div
元素将从DOM中完全删除。
ng-if指令
就像ng-switch指令一样,ng-if指令可以从DOM中包含/删除HTML元素,但是语法更简单。这是一个例子:
<div ng-controller="MyController" > <div ng-if="myData.showIt">ng-if Show it</div> </div> <script> angular.module("myapp", []) .controller("MyController", function($scope) { $scope.myData = {}; $scope.myData.showIt = true; }); </script>
ng-if和ng-show + ng-hide之间的主要区别是ng-if将DOM中的HTML元素完全删除,而ng-show + ng-hide则完全删除了DOM。只需将CSS属性display:none;
应用于元素即可。
ng-include指令
ng-include指令可用于将其他文件的HTML片段包含到视图的HTML模板中。这是一个例子:
<div ng-controller="MyController" > <div ng-include="'angular-included-fragment.html'"></div> </div>
此示例将文件angular-included-fragment.html包含在具有ng-include属性的div内的HTML模板中。请注意,文件名是如何被引用(单引号)的。
我们可以根据条件包括HTML片段。例如,我们可以在两个文件之间进行选择,如下所示:
<div ng-controller="MyController" > <div ng-include="myData.showIt && 'fragment-1.html' || 'fragment-2.html'"></div> </div> <script> angular.module("myapp", []) .controller("MyController", function($scope) { $scope.myData = {}; $scope.myData.showIt = true; }); </script>
如果myData.showIt为true,则此示例包含fragment-1.html;如果myData.showIt为false,则此示例包括fragment-2.html。
ng-repeat指令
ng-repeat指令用于遍历项目集合并从中生成HTML。初始生成后,ng-repeat
监视用于生成HTML进行更改的项目。如果项发生更改,则ng-repeat指令可能会相应地更新HTML。这包括重新排序和删除DOM节点。
这是一个简单的ng-repeat示例:
<ol> <li ng-repeat="theItem in myData.items">{{theItem.text}}</li> </ol> <script> angular.module("myapp", []) .controller("MyController", function($scope) { $scope.myData = {}; $scope.myData.items = [ {text : "one"}, {text : "two"}, {text : "three"} ]; }); </script>
这个例子将为myData.items数组中的每个项目创建一个li元素。
我们也可以遍历从函数调用返回的集合。这是一个例子:
<ol> <li ng-repeat="theItem in myData.getItems()">{{theItem.text}}</li> </ol> <script> angular.module("myapp", []) .controller("MyController", function($scope) { $scope.myData = {}; $scope.myData.items = [ {text : "one"}, {text : "two"}, {text : "three"} ]; $scope.myData.getItems = function() { return this.items; }; }); </script>
我们可以使用稍微不同的语法来遍历JavaScript对象的属性:
<ol> <li ng-repeat="(name, value) in myData.myObject">{{name}} = {{value}}</li> </ol> <script> angular.module("myapp", []) .controller("MyController", function($scope) { $scope.myData = {}; $scope.myData.myObject = { var1 : "val1", var2 : "val3", var3 : "val3"}; }); </script>
注意ng-repeat指令的((name,value))部分。这会通知AngularJS迭代对象的属性。 name参数将绑定到属性名称,value参数将绑定到属性值。正如上面的HTML模板所示," name"和" value"参数可以像其他任何JavaScript变量或者对象属性一样输出到HTML模板。
特殊的ng-repeat变量
ng-repeat指令定义了一组特殊变量,我们可以在迭代集合时使用它们。这些变量是:
- $index
- $first
- $middle
- $last
$ index变量包含被迭代元素的索引。
$ first,$ middle和$ last包含布尔值,具体取决于当前项是要迭代的集合中的first,middle还是last元素。如果项目不是第一个也不是最后一个,则该项目为"中间"。我们可以使用这些变量来生成不同的HTML,例如使用前面介绍的ng-show / ng-hide,ng-switch,ng-if和ng-include指令。
重复多个元素
到目前为止,我们仅了解了如何使用ng-repeat重复单个HTML元素。如果要重复多个HTML元素,则必须将这些元素嵌套在container元素内,并使container元素具有ng-repeat元素,如下所示:
<div ng-repeat="(name, value) in myData.myObject"> <div>{{name}}</li> <div>{{value}}</li> </div>
但是,并非总是可能将要重复的元素包装在根元素中。因此AngularJS具有ng-repeat-start和ng-repeat-end指令,它们标记开始和结束重复的元素。这是一个例子:
<ol> <li ng-repeat-start="(name, value) in myData.myObject">{{name}}</li> <li ng-repeat-end>{{value}}</li> </ol>
这个例子将为myData.myObject中的每个属性重复两个li元素。
筛选
上面介绍的某些指令支持过滤。本节将说明过滤的工作原理。
ng-repeat指令可以接受这样的过滤器:
<div ng-repeat="item in myData.items | filter: itemFilter"></div>
注意|过滤器:itemFilter
以上声明的一部分。那部分是过滤器定义。 `| filter:部分告诉AngularJS将过滤器应用于myData.items数组。 " itemFilter"是过滤器功能的名称。该函数必须存在于$ scope对象上,并且必须返回true或者false。如果过滤器函数返回true,则ng-repeat指令将使用数组中的元素。如果过滤器函数返回false,则忽略该元素。这是一个例子:
<script> angular.module("myapp", []) .controller("MyController", function($scope) { $scope.myData = {}; $scope.myData.items = [ {text : "one"}, {text : "two"}, {text : "three"}, {text : "four"} ]; $scope.itemFilter = function(item) { if(item.text == "two") return false; return true; } } }); </script>
格式化过滤器
AngularJS带有一组内置的格式过滤器,可以与插值指令和ng-bind结合使用。这是格式过滤器的列表:
过滤器 | 描述 |
---|---|
date | 根据给定的日期格式将变量格式化为日期 |
currency | 将变量格式化为带有货币符号的数字 |
number | 将变量格式化为数字 |
lowercase | 将变量转换为小写 |
uppercase | 将变量转换为大写 |
json | 将变量转换为JSON字符串 |
这是一个日期过滤器示例:
<span>{{myData.theDate | date: 'dd-MM-yyyy'}}</span>
此示例显示了"日期"过滤器,该过滤器可以根据在" |"之后给出的日期格式模式来格式化JavaScript日期对象。日期:部分。它是myData.theDate属性,将被格式化为日期。因此,它必须是一个JavaScript日期对象。
这是一个数字过滤器示例:
<span>{{myData.theNumber | number: 2}}</span>
这个例子将myData.theNumber
变量格式化为一个小数点后两位的数字。
这是一个小写和大写过滤器示例:
<span>{{myData.mixedCaseText | lowercase}}</span> <span>{{myData.mixedCaseText | uppercase}}</span>
阵列过滤器
AngularJS还包含一组过滤或者变换数组的数组过滤器。这些过滤器是:
数组过滤器:
过滤器 | 描述 |
limitTo | 将数组限制为给定的大小,从数组中的某些索引开始。limitTo 过滤器也适用于字符串。 |
filter | 通用过滤器。 |
orderBy | 根据提供的条件对数组进行排序。 |
这是一个" limitTo"示例:
<span>{{myData.theText | limitTo: 3}}</span>
这将$ scopemyData.theText变量的长度限制为3个字符。如果将此过滤器应用于数组,则该数组将限于3个元素。
"过滤器"过滤器是一种特殊的过滤器,可以做很多不同的事情。它以最简单的形式只是在$ scope对象上调用一个函数。该函数必须返回" true"或者" false"。如果过滤器接受传递给它的值,则返回True。如果过滤器不能接受该值,则返回False。如果过滤器不能接受该值,则该值不包含在由过滤产生的数组中。这是一个例子:
<ol> <li ng-repeat="item in myData.items | filter:filterArray"> {{item.text}} : {{$first}}, {{$middle}}, {{$last}} </li> </ol> <script> angular.module("myapp", []) .controller("MyController", function($scope) { $scope.myData = {}; $scope.myData.items = [ {text : "one"}, {text : "two"}, {text : "three"}, {text : "four"} ]; $scope.filterArray = function(item) { if(item.text == "two") return false; return true; } } ); </script>
这个例子调用了filterArray()
函数,该函数过滤掉具有text
属性值为'two'的项目。
这是一个" orderBy"示例:
<ol> <li ng-repeat="item in myData.items | orderBy:sortField:reverse"> {{item.text}} : {{$first}}, {{$middle}}, {{$last}} </li> </ol> <script> angular.module("myapp", []) .controller("MyController", function($scope) { $scope.myData = {}; $scope.myData.items = [ {text : "one"}, {text : "two"}, {text : "three"}, {text : "four"} ]; $scope.sortField = "text"; $scope.reverse = true; } ); </script>
orderBy
过滤器接受一个$ scope变量作为参数。在此示例中,该变量名为sortField
。此变量的值是用于对数据对象进行排序的已排序数据对象上的属性的名称。在此示例中," sortField"属性设置为" text",这意味着数据对象的" text"属性用于对数据对象进行排序。
orderBy
过滤器还可以使用第二个$ scope
变量作为参数。在此示例中,该变量名为" reverse"。此变量的值确定是否要按其自然顺序或者相反顺序对数据对象进行排序。在这种情况下," reverse"变量设置为" true",这意味着数据对象将以相反的顺序排序。
链式过滤器
可以通过在过滤器部分中依次放置更多过滤器来链接过滤器。链接过滤器时,一个过滤器的输出将用作链中下一个过滤器的输入。这是一个例子:
<span>{{myData.theText | limitTo: 5 | uppercase}}</span>
本示例首先使用limitTo过滤器将字符串myData.theText限制为5个字符,然后使用uppercase过滤器将5个字符转换为大写。
将过滤器输出分配给变量
可以将过滤器的输出分配给一个临时变量,然后可以在以后的视图中引用它。这是一个例子:
<ol> <li ng-repeat="item in filteredItems = ( myData.items | filter:filterArray) "> {{item.text}} : {{$first}}, {{$middle}}, {{$last}} </li> </ol> <div>{{filteredItems.length}}</div>
本示例将过滤的输出分配给filteredItems
变量。然后,该示例在ol
元素下的{{}}
指令内引用此变量。
实施自定义过滤器
我们可以实现自己的过滤器,以防AngularJS过滤器不适合需求。这是一个例子:
<div>Filtered: {{myData.text | myFilter}}</div> <script> var module = angular.module("myapp", []); module.filter('myFilter', function() { return function(stringValue) { return stringValue.substring(0,3); }; }); </script>
本示例向AngularJS注册了一个可以过滤字符串的过滤器。过滤器返回字符串的前3个字符。过滤器以名称" myFilter"注册。正如在过滤器开头所看到的那样,在引用过滤器时必须使用此名称。
如果过滤器需要更多的输入参数,请向过滤器功能添加更多的参数,并在过滤器名称和引用时在其后添加参数:。这是一个例子:
<div>Filtered: {{myData.text | myFilter:2:5}}</div> <script> var module = angular.module("myapp", []); module.filter('myFilter', function() { return function(stringValue, startIndex, endIndex) { return stringValue.substring(parseInt(startIndex), parseInt(endIndex)); }; }); </script>
请注意,过滤器引用(| myfilter:2:5
)现在在过滤器名称之后有两个值,每个值都用冒号分隔。这两个值将作为参数传递到过滤器。还请注意,过滤器函数现在如何接受两个名为startIndex
和endIndex
的额外参数。这两个参数用于确定字符串的哪一部分作为子字符串从过滤器返回。