AngularJS简单的入门体验

AngularJS介绍

AngularJS 是 Angular1.x 的另一个名字罢了,从 Angular 2.0 版本开始,AngularJS 与 Angular2.0 及以上版本就已经不是同一个框架了。AngularJS诞生于2009年,后被Google收购,用于许多Google产品的开发。AngularJS框架让开发人员们更加关注于业务逻辑和数据,而并非将大量的时间去处理页面层级的操作。通过AngularJS我们可以快速构建SPA应用。

指令(Directive)

AngularJS有一套完整的、可扩展的、用来帮助Web开发的指令集,在建立DOM期间,和HTML相关联的指令会被执行。
在AngularJS中,前缀为ng-这种属性称之为指令,其作用就是为DOM元素调用方法、定义行为、绑定数据等。
总体来说就是 当一个Angular应用启动时,Angular就会遍历DOM树解析HTML,然后根据指令的不同,完成不同的操作。出了系统提供的一套内置指令外,用户还可以自定义指令。

常用内置指令

虽然官方没有将内置指令分类,根据我个人的理解,内置指令大概可以分为两大类,一类是基本指令,另一类是事件指令,例如ng-model就属于基本指令,ng-click就属于事件指令。

ng-app

ng-app用于标记一个Angular的应用程序的管辖范围,它标记在一个AngularJS的作用范围的根对象上面,系统在执行的时候会自动执行根对象范围内的其他指令。
尽管理论上一个页面中可以使用多个ng-app指令,但是官方并不推荐这么做,AngularJS在页面找到第一个ng-app后就不会再去往下找了,所以就算我们使用了多个,也不会起作用,例如下面的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ng-app</title>
</head>
<body>
    <div ng-app="app1" ng-controller="app1Controller">
        <input type="button" value="Button1" ng-click="do1()">
    </div>

    <div ng-app="app2" ng-controller="app2Controller">
        <input type="button" value="Button2" ng-click="do2()">
    </div>
    <script src="../bower_components/angular/angular.js"></script>
    <script>
        var app1 = angular.module("app1", []);
        app1.controller("app1Controller", ["$scope", function($scope) {
            $scope.do1 = function() {
                console.log(1);
            };
        }]);

        var app2 = angular.module("app2", []);
        app2.controller("app2Controller", ["$scope", function($scope) {
            $scope.do2 = function() {
                console.log(2);
            };
        }]);
    </script>
</body>
</html>

按照理论,我们点击Button1会控制台会输出1,点击Button2会输出2,然后实测点击Button1有效,点击Button2无效,这也证实了之前所说,angular找到第一个ng-app后就不会找第二个了,但是如果实在是想使用多个,怎么办,也不是没有办法,但是需要我们手动的让第二个Div让被app2管理。需要使用到angular提供的bootstrap方法了,我们加入如下一行JS代码:

angular.bootstrap(document.querySelector('[ng-app="app2"]'),["app2"]);

需要在方法中传入需要被管理的DOM元素以及来管理它的模块名。这样就可以同时使用多个模块了。
但是,这个方法并不是很好,我们通常的做法是把两个模块拼凑成一个模块,也就是说将这两个模块作为依赖注入到一个大的模块当中,然后在两个Div的父级节点 加上ng-app即可,所以我们的代码是这样的:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ng-app</title>
</head>
<body ng-app="app">
    <div ng-controller="app1Controller">
        <input type="button" value="Button1" ng-click="do1()">
    </div>
    <div ng-controller="app2Controller">
        <input type="button" value="Button2" ng-click="do2()">
    </div>
    <script src="../bower_components/angular/angular.js"></script>
    <script>
        var app1 = angular.module("app1", []);
        app1.controller("app1Controller", ["$scope", function($scope) {
            $scope.do1 = function() {
                console.log(1);
            };
        }]);

        var app2 = angular.module("app2", []);
        app2.controller("app2Controller", ["$scope", function($scope) {
            $scope.do2 = function() {
                console.log(2);
            };
        }]);

        var app = angular.module("app", ["app1", "app2"]);
    </script>
</body>
</html>
ng-bind

ng-bind指令将作用域(scope)中的值绑定到元素的innerHTML上,其效果会比表达式绑定的方式更加友好,如果绑定的内容包含html,会自动转义。如果想绑定一段html代码,可以使用ng-bind-html指令。
那么ng-bind{{}} 插值语法 有何区别?当网络环境不好的情况下,AngularJS文件还未加载完成,浏览器会将{{}}当成一段正常的字符串进行渲染,所以会产生闪烁的效果,但是ng-bind指令是作为属性插入元素中的,哪怕AngularJS还没加载完成,渲染的时候会被浏览器认为是无效属性,会忽略掉,所以并不会产生闪烁的情况。

ng-bind-html

因为ng-bind指令如果绑定了一段html代码,会进行自动转义,所以如果需要绑定html代码,我们可以使用ng-bind-html指令,代码如下:

<body ng-app ng-init="username='<h1>Angular<h1>'">
    <strong ng-bind-html="username"></strong>
    <script src="../bower_components/angular/angular.js"></script>
</body>

讲道理,这段代码应该没有问题,但是Angular会抛出如下错误:

angular.js:13920 Error: [$sce:unsafe] Attempting to use an unsafe value in a safe context.

它说我们正在尝试在一个安全的环境下使用一个不安全的数据,查阅了官方文档,是这样说的:
在这里插入图片描述

他说我们需要使用$sanitize这个服务,将angular-sanitize.js引入我们的应用中,并将ngSanitize注入到我们的模块中,用于检测清理不安全的因素。我们按照官方的文档修改代码如下(angular-sanitize.js需要自己单独下载):

<body ng-app="myApp" ng-init="username='<h1>Angular<h1>'">
    <strong ng-bind-html="username"></strong>
    <script src="../bower_components/angular/angular.js"></script>
    <script src="../bower_components/angular-sanitize/angular-sanitize.js"></script>
    <script>
        var myApp = angular.module("myApp", ['ngSanitize']);
    </script>
</body>

这样就可以正常使用ng-bind-html指令绑定html代码了,不过需要注意的一点的是:angular-sanitize的版本要和angular保持一致,否则可能导致一些问题不能正常使用。尽管官方提供了这样一种方式,但是绑定html代码仍然是一种非常不安全的操作。

ng-repeat

ng-repeat指令用来遍历一个数组来重复创建当前元素,是一个很常用的指令如:

<ul>
	<li ng-repeat="item in data track by $index">{{item}}</li>
</ul>

因为Angular默认不允许ng-repeat的数组中存在重复的元素,一般我们会使用track by $ index的方式解决这个问题。

ng-class

ng-class 指令用于给 HTML 元素动态绑定一个或多个 CSS 类。指令的值可以是字符串,对象,或一个数组。
字符串:多个类名使用空格分隔
对象:需要使用 key-value 对,key 为你想要添加的类名,value 是一个布尔值。只有在 value 为 true 时类才会被添加。
数组:可以由字符串或对象组合组成,数组的元素可以是字符串或对象。

ng-show、ng-hide、ng-if

ng-showng-hide指令都是动态改变元素是否显示,修改元素的display属性
ng-if是动态改变元素的Dom结构是否存在。

ng-src和ng-href

假如我们的模板下有一张这样的图片:

<img src="{{imgUrl}}"/>

那么当我们的页面加载到ng编译完成之前会一直显示找不到图片,因为我们图片的地址{{imgUrl}}还没有被替换,为了避免这种情况,我们使用ng-src指令,这样在路径被正确得到之前就不会显示找不到图片。同理,<a>标签的href属性也需要换成ng-href,这样页面上就不会先出现一个地址错误的链接。

ng-switch

ng-switch指令根据表达式显示或隐藏对应的部分,对应的子元素使用ng-switch-when指令,如果匹配成功则显示,否则移除,并且可以使用ng-switch-default指令设置默认选项,如果都没有匹配上,默认的选项就会显示。
一般ng-switch指令用于比较复杂的显示/隐藏逻辑。使用方法如下:

<select ng-model="selected">
	<option value="1">1</option>
	<option value="2">2</option>
	<option value="3">3</option>
</select>
<div ng-switch="selected">
	<span ng-switch-when="1">this is 1</span>
	<span ng-switch-when="2">this is 2</span>
	<span ng-switch-when="3">this is 3</span>
	<span ng-switch-default>you have no choice</span>
</div>

常用的事件指令

ng-change:发生改变
ng-copy:拷贝完成
ng-click:单击
ng-dblclick:双击
ng-blur:失去焦点
ng-focus:获得焦点
ng-commit:表单提交

自定义指令

自定义指令的目的是封装一些常用并且公用的东西,并且Angular仍然存在一些DOM操作的可能,这些DOM操作应该都集中在自定义指令中。
定义自定义指令和定义控制器方式一致,都在模块下定义就可以了,下面是一个最简单的自定义指令:

angular.module("myApp", [])
    .directive("myBtn", [function(){
        return {
            template:'<button>MyButton</button>'
        }
    }]);

需要注意的是,自定义指令的名字推荐使用驼峰命名法
除了返回有template属性,还有以下常用属性:
restrict:指令类型,E:element A:attribute M:comment C: class
templateUrl:指令模板地址
replace:是否使用模板替换原标签
transculde:是否使用ng-transculde来包含html中指令包含的原有的内容
scope:隔离父Scope
link:称为链接函数,可以在里面操作DOM,共三个参数scope,element,attrs

restrict
字母使用方式示例
E元素<my-button></my-button>
A属性<div my-button></div>
C样式类<div class=my-button></div>
M注释<!-- directive: my-button -->
template和templateUrl

在一个自定义的指令中,templatetemplateUrl只能选一个。
template为模板内容。即你要在指令所在的容器中插入的html代码。
templateUrl为模板内容的地址,当你的template超过10行,建议单独写一个模板文件,不然不易于后期的维护和阅读。

replace

replace:是否用模板替换当前元素。true : 将指令标签替换成temple中定义的内容,页面上不会再有<my-directive>标签;false :则append(追加)在当前元素上,即模板的内容包在<my-directive>标签内部。默认false。

transculde

是否使用ng-transculde来包含html中指令包含的原有的内容,接收一个参数true/false

scope

directive默认是可以共享父scope中定义的属性,例如在模版中直接使用父 scope 中的对象和属性,但是我们如果要创建一个需要重复使用的指令就不能依赖于父scope了,因为在不同的地方使用directive对应的父scope不一样。所以我们需要一个隔离的scope,我们可以这样定义我们的指令:

app.controller("myController", function ($scope) {
    $scope.name = "hello Angular";
}).directive("isolatedDirective", function () {
        return {
            scope: {},
            template: '{{name}}'
        }
});

使用隔离 scope 的时候,无法从父 scope 中共享属性。因此下面示例无法输出父 scope 中定义的 name 属性值。但是Angular为我们提供了三种方法同隔离之外的地方交互:

  • @ 可以当前dom元素上的属性值绑定到局部scope属性中,结果总是字符串,因为dom属性就是字符串
  • = 用法和@一致,不过@是单向的绑定,=是双向的绑定
  • & 能使direvtive可以在父scope中执行一个动作,可以是一个function。

@使用例子
定义指令如下:

angular.module("myApp", [])
    .controller("btnController",["$scope", function($scope) {
        $scope.name = "Angular";
    }]).directive("myButton", [function() {
        return {
         scope: {
            name: "@"
          },
          template: "Hello {{name}}"
         };
     }]);

html代码:

<my-button name="{{name}}"></my-button>

我们将父scope中的name属性通过属性的方式 传入my-button指令中,隔离scope通过@可以接受到这个参数,不过这是一个单向的绑定,父scope的name属性发生改变,隔离scope也会相应发生变化,不过隔离scope发生变化,父scope不会相应变化。

= 使用例子

angular.module("myApp", [])
    .controller("btnController",["$scope", function($scope) {
        $scope.name = "Angular";
    }]).directive("myButton", [function() {
        return {
         scope: {
            name: "="
          },
          template: "Hello {{name}}"
         };
     }]);

html代码:

<my-button name="{{name}}"></my-button>

如果使用 = 无论是改变父 scope 还是隔离 scope 里的属性,父 scope 和隔离 scope 都会同时更新属性值,因为它们是双向绑定的关系。

& 使用例子

var app = angular.module("myApp", []);
app.controller("btnController", ["$scope", function($scope){
        $scope.count = 0;
        $scope.add = function() {
            $scope.count ++;
    };
}]); 
app.directive("myButton", [function() {
        return {
            scope: {
                add:"&"
        },
        template: "<button ng-click='add()'>Add</button>"
    }
}]);

html代码:

<my-button ng-click="add()"></my-button>{{count}}

点击按钮就可以触发父scope中的add( )方法

link

如果想要在指令中操作DOM,我们就需要使用link参数,link参数要求申明一个函数,称之为链接函数
写法如下:

link: function(scope, element, attrs) {
  // 在这里操作DOM
}

双向绑定

其实,说起来,AngularJS最大的魅力就体现在数据的双向绑定上了,双向绑定意味着我们的viewmodel无论哪一边进行了数据更新,另一方都能同步的得到更新。
例子:

<body ng-app="myApp" ng-controller="appController">
    <input type="text" ng-model="name">
    <div>Hello <strong>{{name}}</strong></div>
    <script src="../bower_components/angular/angular.js"></script>
    <script>
        angular.module("myApp", []).controller("appController", ["$scope", function($scope) {
            $scope.name = "Lan";
        }]);
    </script>
</body>

效果如下:
在这里插入图片描述
当我们在输入框中输入数据的同时,也会对网页的内容进行修改。
我是用了{{}}实现了最简单的数据绑定,不过这个绑定是单向的,仅仅实现了数据的展示,然后我再input标签上加上了ng-model指令,实现了数据的双向绑定。双向绑定最常见的应用场景就是表单的处理,使用了双向绑定后,用户填写完表单,我们不需要任何操作就能拿到用户填写的所有内容。

ng双向绑定的优点

双向绑定最大的优点就在于数据发生改变后,我们不需要手动的去更新view上面的内容去更新视图,简化了我们的开发过程,让代码更有逻辑性并且增强了可阅读性。让开发人员可以更加专注于业务逻辑而并非数据的处理和繁琐的DOM操作。

ng双向绑定的缺点

当我们绑定的数据层次较深、数据量较大的时候,数据的双向绑定会占据一定的性能开销,因为AngularJS数据双向绑定的性能问题和AngularJS实现双向绑定的机制有关系。
关于AngualrJS双向绑定原理的分析可以参考我的另一篇博客
AngularJS数据双向绑定背后的秘密

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值