AngularJS学习笔记

1. 介绍

AngularJS是一款由Google公司开发维护的前端MVC框架,其克服了HTML在构建应用上的诸多不足,从而降低了开发成本提升了开发效率。

1.1 特点

AngularJS与jQuery有什么区别?

jQuery更准确来说只一个类库(类库指的是一系列函数的集合),是以DOM做为驱动。
而AngularJS则一个框架(诸多类库的集合)是以数据和逻辑做为驱动。

框架对开发的流程和模式做了约束,开发者遵照约束进行开发,更注重的实际的业务逻辑。

AngularJS有着诸多特性,最为核心的是:模块化双向数据绑定语义化标签依赖注入等。

1.2 MVC

MVC是一种开发模式,把网页分成模型(Model)、视图(View)、控制器(Controller)3部分构成。

模型(Model)用来处理数据(读取/设置),一般指操作数据库。
视图(View)用来展示数据,比如通过HTML展示。
控制器(Controller)用做连接模型和视图的桥梁。

MVC更多应用在后端开发程序里,后被引入到前端开发中,由于受到前端技术的限制便有了一些细节的调整,进而出现了很多MVC的衍生版(子集)如MVVM、MVW、MVP、MV*等。

2. AngularJS的模块化

使用AngularJS构建应用(App)时是以模块化(Module)的方式组织的,即将整个应用划分成若干模块,每个模块都有各自的职责,最终组合成一个整体。采用模块化的组织方式,可以最大程度的实现代码的复用。

2.1 使用AngularJS的HTML基本结构

2.1.1 定义应用

通过为任一HTML标签添加ng-app属性,可以指定一个应用,表示此标签所包裹的内容都属于应用(App)的一部分。




2.1.2 定义模块

AngularJS提供了一个全局对象angular,在此全局对象下存在若干的方法,其中angular.module()方法用来定义一个模块。

// 通过module方法定义模块
// 有两个参数
// 第一个:表示模块的名称
// 第二个:表示此模块依赖的其他模块
var app = angular.module( 'app', [] );

2.1.3 定义控制器

控制器(Controller)作为连接模型(Model)和视图(View)的桥梁存在,所以当我们定义好了控制器以后也就定义好了模型和视图。

// app是一个模块实例对象
// 通过这个实例对象定义控制器
// 传入两个参数
// 第1个:定义控制器的名称
// 第2个:一个数组,数组的最后一项是函数,其余是字符串,写明此控制器的依赖关系
app.controller('StarController', ['$scope', function($scope){
    $scope.students = [
        {name: '周杰伦', gender: '男', age: 39},
        {name: '刘德华', gender: '男', age: 60},
        {name: '孙燕姿', gender: '女', age: 36},
        {name: '王力宏', gender: '男', age: 38},
        {name: '陈小春', gender: '男', age: 42},
    ]
}]);

2.1.4 在视图中关联控制器

模型(Model)数据是要展示到视图(View)上的,所以需要将控制器(Controller)关联到视图(View)上,通过为HTML标签添加ng-controller属性并赋值相应的控制器(Controller)的名称,就确立了关联关系。


姓名 性别 年龄
{{student.name}} {{student.gender}} {{student.age}}

2.1.5 整个HTML文档的结构




    
    AngularJS的基本结构


    
姓名 性别 年龄
{{student.name}} {{student.gender}} {{student.age}}
AngularJS学习笔记_第1张图片
效果

3.指令

3.1 常用内置指令

ng-app 指定应用根元素,至少有一个元素指定了此属性。不能互相嵌套。

ng-controller 指定控制器

ng-show 控制元素是否显示,true显示、false不显示

ng-hide 控制元素是否隐藏,true隐藏、false不隐藏

ng-if 控制元素是否“存在”,true存在、false不存在(DOM元素存在与否)。

ng-src 增强图片路径。如果图片路径是src = {{path}}这种形式,并且模型写在文档下面,浏览器从上至下依次解析代码到这里时,还没有解析到模型,当快速刷新网页时,就会显示图片没有请求到。如果是ng-src={{path}},执行到这里会强制先解析模型中的path,就不会出现未请求到的问题,并且解决了重复请求的问题。

ng-href 增强地址

ng-class 控制类名。它的值可以有两种形式。ng-class = {{active}}ng-class = {{active : true}},boolen值控制该类名是否存在。

ng-include 引入模板。可以加载一个外部文件。应用时,可以把一些公共部分抽离成一个独立文件,然后用ng-include = 'src'引入。在没用AngularJS之前,用的是。但是,要注意的是,ng-include的地址要是同域的,这是因为,js本身读取不了本地文件,需要借助请求的方式,并且这种请求不能是跨域的。

ng-disabled 表单禁用。值为boolen值。ng-disabled = true表单禁用。

ng-readonly 表单只读

ng-checked 单/复选框表单选中,值为boolen值。checked是一个无值属性,ng-checked = true时,就会存在checked这个属性。

ng-selected 下拉框表单选中。selected也是一个无值属性,ng-selected = true时,选中。

ng-repeat 遍历

3.2 自定义指令

AngularJS允许根据实际业务需要自定义指令,通过angular全局对象下的directive方法实现。


    

4.数据绑定

AngularJS是以数据做为驱动的MVC框架,所有模型(Model)里的数据经由控制器(Controller)展示到视图(View)中。

所谓数据绑定指的就是将模型(Model)中的数据与相应的视图(View)进行关联,分为单向绑定和双向绑定两种方式。

4.1 单向绑定

单向数据绑定是指将模型(Model)数据,按着写好的视图(View)模板生成HTML标签,然后追加到DOM中显示。

4.2 双向绑定

双向绑定则可以实现模型(Model)数据和视图(View)模板的双向传递。




    
    数据绑定


    

您输入的是:{{msg}}

4.3 相关指令

{{}} 和 ng-bind
在AngularJS中通过{{}}或者ng-bind指令来实现模型(Model)数据向视图模板(View)的绑定,模型数据通过一个内置服务$scope来提供,这个$scope是一个空对象,通过为这个对象添加属性或者方法便可以在相应的视图(View)模板里被访问。

{{}}ng-bind的简写形式,但是它们还有区别。
第1个区别ng-bind不能绑定多个数据,如ng-bind = 'name age'这种写法是错误的。可以写成{{name}}{{age}}。通过ng-bind-template可以绑定多个数据。
第2个区别。通过{{}}绑定数据时会有“闪烁”现象,ng-bind不会有闪烁现象。{{}}使用方便,为标签添加ng-cloak并将script标签移到上面可以解决“闪烁”现象。原理:页面载入时,载入到引入angular的script标签时,会自动在页面中添加style,为添加了ng-cloak的标签设置display=none,隐藏了添加了ng-cloak的标签,解析完写了模型的script后再将其显示。

ng-model
通过为表单元素添加ng-model指令实现视图(View)模板向模型(Model)数据的绑定。

ng-init
通过ng-init可以初始化模型(Model)也就是$scope。


    

{{title}}{{info}}

事件处理
AngularJS对事件也进行了扩展,无需显式的获取DOM元素便可以添加事件,易用性变的更强。通过在原有事件名称基础上添加ng-做为前缀,然后以属性的形式添加到相应的HTML标签上即可。如ng-click、ng-dblclick、ng-blur等。


    
  • 单击事件
  • 双击事件
  • 悬停事件
  • 离开事件
  • ng-repeat
    通过ng-repeat可以将数组或对象数据迭代到视图模板中,ng-switch on配合ng-switch-when可以对数据进行筛选。

    
        
    • {{item}}
    • {{key}}:{{val}}
    {{key}} {{val}}

    一个Tab栏切换小demo

    
    
    
        
        Tab 标签
        
    
    
    
        
    1. 国内新闻
    1. 国际新闻
    1. 体育新闻
    1. 娱乐新闻

    5.作用域

    通常AngularJS中应用(App)是由若干个视图(View)组合成而成的,而视图(View)又都是HTML元素,并且HTML元素是可以互相嵌套的,另一方面视图都隶属于某个控制器(Controller),进而控制器之间也必然会产生嵌套关系。

    每个控制器(Controller)又都对应一个模型(Model)也就是$scope对象,不同层级控制器(Controller)下的$scope便产生了作用域。

    可以参考JavaScript中函数的作用域来理解。

    5.1 全局作用域(根作用域)

    一个AngularJS的应用(App)在启动时会自动创建一个根作用域$rootScope,这个根作用域在整个应用范围(ng-app所在标签以内)都是可以被访问到的。

    5.2 子作用域

    通过ng-controller指令可以创建一个子作用域,每当有一个控制器就有一个子作用域,新建的作用域可以访问其父作用域的数据。

    例子

    
    
    
        
        AngularJS 作用域
    
    
    
        
    {{name}}
    1200
    {{name}}
    1100
    {{name}}
    1000

    6.过滤器

    在AngularJS中使用过滤器格式化展示数据,在“{{}}”中使用“|”来调用过滤器,使用“:”传递参数。

    6.1 内置过滤器

    1. currency将数值格式化为货币格式
    2. date日期格式化,年(y)、月(M)、日(d)、星期(EEEE/EEE)、时(H/h)、分(m)、秒(s)、毫秒(.sss),也可以组合到一起使用。
    3. filter在给定数组中选择满足条件的一个子集,并返回一个新数组,其条件可以是一个字符串、对象、函数
    4. json将Javascrip对象转成JSON字符串。
    5. limitTo取出字符串或数组的前(正数)几位或后(负数)几位
    6. lowercase将文本转换成小写格式
    7. uppercase将文本转换成大写格式
    8. number数字格式化,可控制小位位数
    9. orderBy对数组进行排序,第2个参数布尔值可控制方向,true倒序

    例子

    
    
    
        
        AngularJS 过滤器
        
    
    
        
    使用过滤器将数据处理成一定的格式再进行展示
    当前时间为: {{now|date:'yyyy-MM-d h:m:s EEEE'}}
    价格: {{price|currency:'¥':3}}
    介绍: {{info|uppercase}}
    介绍2: {{brief|lowercase}}
    介绍3: {{brief|lowercase|uppercase}}
    limitTo: {{info|limitTo:4}}
    limitTo: {{info|limitTo:-4}}
    limitTo: {{list|limitTo:2}}
    limitTo: {{list|limitTo:-2}}
    number: {{num|number:2}}
    number: {{num1|number}}
    json: {{list|json}}
    json: {{obj|json}}
    orderBy: {{list|orderBy}}
    orderBy: {{list|orderBy:'':false}}
    orderBy: {{list|orderBy:'':true}}
    orderBy: {{students|orderBy:'score':true}}
    filter: {{list|filter:'s'}}
    filter: {{students|filter:{sex:'男'} }}

    6.2 自定义过滤器

    通过模块对象实例提供的filter方法自定义过滤器。

    
    
        
    {{str|uppercase}} {{str|yell:'我是一个参数':123456}} {{str|slice:3}}

    {{str|capitalize}}

    7. 依赖注入

    AngularJS采用模块化的方式组织代码,将一些通用逻辑封装成一个对象或函数,实现最大程度的复用,这导致了使用者和被使用者之间存在依赖关系。

    所谓依赖注入是指在运行时自动查找依赖关系,然后将查找到依赖传递给使用者的一种机制。

    常见的AngularJS内置服务有$http、$location、$timeout、$rootScope等

    依赖注入有两种方式:推断式注入和行内注入。

    7.1 推断式注入

    没有明确声明依赖,AngularJS会将函数参数名称当成是依赖的名称。

    这种方式会带来一个问题,当代码经过压缩后函数的参数被压缩,这样便会造成依赖无法找到。

    // 这个控制器依赖$scope, $http服务
    // 未明确声明依赖,这时会自动将函数传入的参数名当成依赖对待
    App.controller('DemoCtrl', function ($scope, $http) {
        
    });
    

    7.2 行内注入

    以数组形式明确声明依赖,数组元素都是包含依赖名称的字符串,数组最后一个元素是依赖注入的目标函数。

    推荐使用这种方式声明依赖

    App.controller('DemoCtrl', ['$scope', '$http', function ($scope, $http) {
    
    }]);
    

    8.服务

    服务是一个对象或函数,对外提供特定的功能。

    8.1 内建服务

    8.1.1 $location

    $location是对原生Javascript中location对象属性和方法的封装。

    
    

    8.1.2 $timeout&$interval

    $timeout&$interval对原生Javascript中的setTimeout和setInterval进行了封装。

    var App = angular.module('App', []);
    
    App.controller('DemoCtrl', ['$scope', '$timeout', '$interval', function ($scope, $timeout, $interval) {
    
        // 延时执行
        $timeout(function () {
            console.log('延时了3秒')
        }, 3000);
    
        // 取消延时
        $timeout.cancel();
    
        // 间歇函数
        $interval(function () {
            console.log(1);
        }, 500);
    
        // 一秒刷新一下时间
        var timer = $interval(function () {
            $scope.now = new Date();
        }, 1000);
    
        $scope.stop = function () {
            $interval.cancel(timer);
        }
    
    }]);;
    

    8.1.3 $filter

    $filter在控制器中格式化数据。

    var App = angular.module('App', []);
    
    // $filter是过滤器,过滤器可以在视图中使用{{|}},也可在模型中使用
    
    App.controller('DemoCtrl', ['$scope', '$filter', function ($scope, $filter) {
    
        // AngularJS 自带的过滤器有9种
    
        // $filter是一个函数,传递不同的参数会返回不同具体功能的过滤器
    
        // $filter('date') 其返回值就是一个格式化时间的过滤器
        // $filter('currency') 其返回值就是一个格式化货币的过滤器
        // $filter('uppercase')、$filter('limitTo') ....
    
        // 原始数据
        var now = new Date;
        // 时间过滤器
        var date = $filter('date');
        // 格式化数据
        now = date(now, 'yyyy-MM-dd H:m:s');
        $scope.now = now;
    
        var list = ['html', 'css', 'js', 'php', 'node'];
        var limitTo = $filter('limitTo');
        list = limitTo(list, 3);
        $scope.list = list;
    
        // 原始信息
        var content = 'my name is xiaoming';
        // 创建过滤器
        var uppercase = $filter('uppercase');
        // 格式化数据
        $scope.content = uppercase(content);
    
    }]);
    

    8.1.4 $log

    $log打印调试信息。

    App.controller('DemoCtrl', ['$scope', '$log', function ($scope, $log) {
    
        // $log 是一个对象
    
        $log.log('调试信息');
    
        $log.info('调试信息');
    
        $log.error('调试信息,错了吗?');
    
        $log.warn('调试信息,警告');
    
        $log.debug('调试信息');
    
    }]);
    

    8.1.5 $http

    $http用于向服务端发起异步请求。

    App.controller('DemoCtrl', ['$scope', '$http', function ($scope, $http){
        // 发起异步请求
        $http({
            method: 'post',
            url: 'demo.php',
            data: {name: 'xule', age: 10},
            headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        }),success(function (info){
            // 可以把服务端返回的数据绑定到模型上
            $scope.result = info;
        }),error(function (info)){
        };
    }]);
    

    要注意的是,请求方式不同,传递的数据格式也不同。

    (1)当请求方式为post时,有两种写法。

    数据为key=val&key1=val1格式时,需要通过Content-Type告知其类型为application/x-www/form-urlencoded。

    数据为{key: val, key1: val1}格式时,需要通过Content-Type告知其类型为application/json。但是AngularJS默认使用这种格式,这里的headers可以写也可以不写。

    $http({
        url: 'example.php',
        method: 'post',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        data: {'name=ming&age=11'}
    });
    
    $http({
        url: 'example.php',
        method: 'post',
        // 这里的headers可以写也可以不写,默认就是这种形式
        headers: {
            'Content-Type': 'application/json'
        },
        data: {name: 'ming', age: 11}
    });
    

    (2)当请求为get方式,使用params专门传递get方式的数据

    $http({
        url: 'example.php',
        method: 'get',
        params: {age: 11},
    });
    

    如何处理跨域请求呢

    通过get方式传递一个事先定义好的函数名,这里有固定的写法:params: {callback: 'JSON_CALLBACK'},JSON_CALLBACK即为"事先定义好的函数名",JSON_CALLBACK是一个占位符,AngularJS 也会像jQuery一样动态创建一个函数,但是动态创建的函数名不固定,先使用一个占位符JSON_CALLBACK占一个位,当动态函数创建成功后再将这个JSON_CALLBACK进行替换。后台接收函数名的时候也用JSON_CALLBACK

    $http({
        url: ' ',
        params: {callback: 'JSON_CALLBACK'},
        method: 'jsonp'
    }).success(function (info) {
        
    });             
    

    使用AngularJS的$http服务的跨域获取天气信息

    这里用的是百度车联网API中的天气查询 - 车联网API

    注意下面两种传递callback的方法,都是可以的。

    
    
    
        
        Document
    
    
        
        
    {{item.date}} {{item.temperature}} {{item.weather}} {{item.wind}} ![]({{item.dayPictureUrl}}) ![]({{item.nightPictureUrl}})
    
    
    
        
        Document
    
    
        
        
    {{weather.date}} {{weather.temperature}} {{weather.weather}} {{weather.wind}} ![]({{weather.dayPictureUrl}}) ![]({{weather.nightPictureUrl}})

    8.2 自定义服务

    通过上面例子得知,所谓服务是将一些通用性的功能逻辑进行封装方便使用,AngularJS允许将自定义服务。

    8.2.1 factory方法

    
    

    8.2.2 service方法

    特点:不需要return

    
        
    {{now}}

    8.2.3 value方法定义常量

    
        
    {{author}} {{ver}}

    9.模块加载

    AngularJS模块可以在被加载和执行之前对其自身进行配置。我们可以在应用的加载阶段配置不同的逻辑。

    先来看一下Angular的执行过程。

    AngularJS学习笔记_第2张图片
    AngularJS执行过程.png

    只需要明白一点,我们可以通过配置块和运行块可以影响后面的执行。

    9.1 配置块

    通过config方法实现对模块的配置,AngularJS中的服务大部分都对应一个“provider”,用来执行与对应服务相同的功能或对其进行配置。

    比如$log、$http、$location都是内置服务,相对应的“provider”分别是$logProvider、$httpProvider、$locationPorvider。

    
        

    {{info|capilize}}

    9.2 运行块

    服务是模块形式存在的,对外提供特定功能,一般都是将服务做为依赖注入进去的,然后再进行调用,除了这种方式外我们也可以直接运行相应的服务模块,AngularJS提供了run方法来实现。

    不但如此,run方法还是最先执行的,利用这个特点我们可以将一些需要优先执行的功能通过run方法来运行,比如验证用户是否登录,未登录则不允许进行任何其它操作。

    App.run(['$http', '$rootScope', function ($http, $rootScope) {
        $http({
            method: 'post',
            url: 'example.php'
        }).success(function (info) {
            // 在根作用域上定义date,相当于在ng-init = '' 中定义
            // 如果要在根作用域上定义多个属性,使用ng-init = '' 会比较麻烦
            // 此时就可以用$rootScope.xxx
            $rootScope.date = info;
        });
    }]);
    

    10. 路由

    网站在切换各个页面时,网站主域名后的改变的,就是路由。改变一个路由,就会切换一个页面。一个应用是由若个视图组合而成的,根据不同的业务逻辑展示给用户不同的视图,路由则是实现这一功能的关键。通过监听路由的改变,可以实现单页面应用(单页面应用也是有路由的)。

    10.1 单页面应用(SPA)

    SPA(Single Page Application)
    单页面应用就是指将所有的功能通过一个页面展示。

    在PC端也有广泛的应用,通常情况下使用Ajax异步请求数据,然后实现内容局部刷新,局部刷新的本质是动态生成DOM,新生成的DOM元素并没有真实存在于文档中,所以当再次刷新页面时新添加的DOM元素会“丢失”,通过单页面应可以很好的解决这个问题。

    由于页面没变,内容变了。可以使用XMLHttpRequest向服务器获取数据,并将获取到的数据以DOM操作的方式添加到页面中去。采用这种方式可以增强用户体验,还可以减轻服务器压力。

    10.2 路由

    在后端开发中通过URL地址可以实现页面(视图)的切换,但是AngularJS是一个纯前端MVC框架,在开发单页面应用时,所有功能都在同一页面完成,所以无需切换URL地址(即不允许产生跳转),但Web应用中又经常通过链接(a标签)来更新页面(视图),当点击链接时还要阻止其向服务器发起请求,通过锚点(页内跳转)可以实现这一点。

    实现单页面应用需要具备:
    a、只有一页面
    b、链接使用锚点

    
        
        

    通过上面的例子发现在单一页面中可以通过hashchange事件监听到锚点的变化,进而可以实现为不同的锚点准不同的视图,单页面应用就是基于这一原理实现的。

    AngularJS对这一实现原理进行了封装,将锚点的变化封装成路由(Route),这是与后端路由的根本区别。

    在1.2版前路由功能是包含在AngularJS核心代码当中,之后的版本将路由功能独立成一个模块,下载angular-route.js

    8.2.1 如何使用路由

    (1)引入angular-route.js
    (2)实例化模块(App)时,当成依赖传进去(模块名称叫ngRoute)
    (3)配置路由模块
    (4)布局模板。通过ng-view指令布局模板,路由匹配的视图会被加载渲染到些区域。

    
        
        

    8.2.2 路由参数

    (1)提供两个方法匹配路由,分别是whenotherwisewhen方法需要两个参数,otherwise方法做为when方法的补充只需要一个参数,其中when方法可以被多次调用。
    (2)第1个参数是一个字符串,代表当前URL中的hash值。
    (3)第2个参数是一个对象,配置当前路由的参数,如视图、控制器等。
    1. template 字符串形式的视图模板
    2. templateUrl 引入外部视图模板
    3. controller 视图模板所属的控制器
    4. redirectTo 跳转到其它路由
    (4)获取参数,在控制中注入$routeParams可以获取传递的参数

    
    
    
    

    9.其他

    9.1 在AngularJS中使用jQuery

    在没有引入jQuery的前提下AngularJS实现了简版的jQuery Lite,通过angular.element不能选择元素,但可以将一个DOM元素转成jQuery对象,如果引提前引入了jQuery则angular.element则完全等于jQuery。

    // 原生DOM对象
    var box = document.querySelector('.box');
    var btn = document.querySelector('button');
    // 转成jQuery对象
    box = angular.element(box);
    btn = angular.element(btn);
    

    你可能感兴趣的:(AngularJS学习笔记)