AngularJS in Action读书笔记1——扫平一揽子专业术语

时间:2022-04-22
本文章向大家介绍AngularJS in Action读书笔记1——扫平一揽子专业术语,主要内容包括前(fei)言(hua):、AngularJS的亮点:、2.功能模块易测试、3.双向绑定、4.弥补HTML的先天不足、AngularJS专业术语概览、书中的实例、2.Views和Controllers、3.Service、4.Directive、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

前(fei)言(hua):

  数月前,以一个盲人摸象的姿态看了一些关于AngularJS的视频书籍,留下了我个人的一点或许是指点迷津或许是误人子弟的读后感。自以为已经达到熟悉ng的程度,但是因为刚入公司,没法直接接触代码层面的编程,日子一天天过去,ng在我脑海的残留也一天天的模糊……

  数月后,我重返ng战场,艰难的收集之前留下的记忆碎片,一番拼接下来,没有让我对ng的理解串成一条线,反而支离破碎的片段scope、template、directive、controller、config、factory、service、provide、compile、link、this.$get,让我不得不重新正视它。

   简而言之,以前的理解是针对某个点或者面,但是如果只停留在这个角度,在阅读理解项目代码时经常犯晕,一个偶然的机会,我看到了《AngularJS in action》,虽然看到的是英文版,但是看了几页之后觉得思路清晰,讲解深入浅出,我就一路看下来,并且正在继续(就我所知,目前市面上应该还没有中文版本)。下面所写内容多数来源于此书。

  下载链接:http://download.csdn.net/detail/zhengjie_1990/9416066 

  有关AngularJS的介绍在前面系列文章《AngularJS入门心得1——directive和controller如何通信》篇中有提到,这里不再赘述。相较已经发展很成熟也很成功的jQuery来说,AngularJS是一门方便维护、高可扩展、可测试的前端开源框架。

AngularJS的亮点:

1.代码组织结构清晰

  AngularJS模块划分明确,不同的代码有其明确的存放处,可读性强,便于维护和扩展(后面会有代码组织结构图)。

2.功能模块易测试

  AngularJS的代码方便测试。虽然代码易测试不能成为一个框架闪光的决定性因素,但是反向思考,如果写出来的代码可测试性差将会使工作效率事倍功半。

3.双向绑定

  双向绑定的出现,无可争议的大大简化了你的代码量,与其说是技术的革新,不如说是一场思想上的颠覆与突破。回想jQuery还需要通过在DOM中找到需要的元素并在其上添加事件监听,通过触发事件(如点击等)才能解析获取DOM元素中的值。而在AngularJS中只需要将DOM中的元素与js的某个属性绑定,js属性值变化会同步到DOM元素上,同样的,DOM元素值得变化也会映射到js的属性上。夸张点说,一个是刀耕火种,一个是蒸汽驱动。

4.弥补HTML的先天不足

  HTML本身能呈现的很有限。举个例子:好比还没有解放的中国,那时只有小米加步枪,所以每一场战役都打的很艰辛,后来解放了,改革开放了,国民经济迅猛发展,靠我们自己勤劳的双手丰富了我们的武器库国防库,我们这时候有了航母、预警机、五代隐形战机等等,我们可以呈现的东西就更多更丰富了。

  这里的“小米加步枪”就是原生的HTML,局限性很大,只能打游击,很难正面交锋。但是勤劳智慧的人民就像AngularJS,我们可以创造更多种多样的指令(武器),来保卫我们的祖国,“呈现”更强大的民族。

AngularJS专业术语概览

名称

作用

Module

AngularJS中一切都是从Module模块开始的,模块是组织代码的容器,当然模块中还可以包含子模块

Config

Config是用在AngularJS application还未启动前的一些参数配置,比如路由或是一些service的配置

Routes

路由负责在应用中基于state进行页面的跳转

Views

Views是通过AngularJS编译后呈现的DOM

$scope

$scope是连接controller和view之间的桥梁,起到一种胶水的作用

Controller

定义一些属性和方法用于绑定到view的元素上,一般来说,controller是比较轻量的,它里面只放一些负责view呈现的属性和方法

Directive

指令使得AngularJS能够创建自定义的标签并实现相应的功能,可以将指令看成一种特殊的html标签

Service

Service负责提供一些通用的功能函数,比如有些数据在多个controller中都会用到,就可以定义在一个service中

书中的实例

  书中提供了一个实例Angello,托管在github上面,这也是我比较欣赏的地方,很方便,git pull下来只要几步就可以轻松运行起来。书中首先是提供了Angello的一个简化版本Angello-lite。

  托管地址:https://github.com/angularjs-in-action/angello-lite

  麻雀虽小,五脏俱全。对应于上图的AngularJS结构,该项目的组织结构如下

  图中:

  (1) index.html代表了view层,负责呈现;

  (2) story是一对标签,代表了指令层,其写在view的index.html中;

  (3) MainCtrl是controller层,其中定义了一些方法等;

  (4) AngelloModel是service层,其中定义了一些公用数据等;

  (5) $scope是view和controller之间的桥梁。

  下面一一介绍各个部分的作用

1. Module

  module是AngularJS中用来组织代码的逻辑单元。本例中,创建了一个Angello的模块并赋值给变量myModule。

  代码中第一行就是创建module

var myModule = angular.module('Angello', []);

app.js

var myModule = angular.module('Angello', []);

myModule.factory('AngelloHelper', function() {
    var buildIndex = function (source, property) {
        var tempArray = [];

        for (var i = 0, len = source.length; i < len; ++i) {
            tempArray[source[i][property]] = source[i];
        }

        return tempArray;
    };

    return {
        buildIndex: buildIndex
    };
});

myModule.service('AngelloModel', function() {
    var service = this,
        statuses = [
            {name: 'Back Log'},
            {name: 'To Do'},
            {name: 'In Progress'},
            {name: 'Code Review'},
            {name: 'QA Review'},
            {name: 'Verified'},
            {name: 'Done'}
        ],
        types = [
            {name: 'Feature'},
            {name: 'Enhancement'},
            {name: 'Bug'},
            {name: 'Spike'}
        ],
        stories = [
            {
                title: 'First story',
                description: 'Our first story.',
                criteria: 'Criteria pending.',
                status: 'To Do',
                type: 'Feature',
                reporter: 'Lukas Ruebbelke',
                assignee: 'Brian Ford'
            },
            {
                title: 'Second story',
                description: 'Do something.',
                criteria: 'Criteria pending.',
                status: 'Back Log',
                type: 'Feature',
                reporter: 'Lukas Ruebbelke',
                assignee: 'Brian Ford'
            },
            {
                title: 'Another story',
                description: 'Just one more.',
                criteria: 'Criteria pending.',
                status: 'Code Review',
                type: 'Enhancement',
                reporter: 'Lukas Ruebbelke',
                assignee: 'Brian Ford'
            }
        ];

    service.getStatuses = function () {
        return statuses;
    };

    service.getTypes = function () {
        return types;
    };

    service.getStories = function () {
        return stories;
    };
});

myModule.controller('MainCtrl', function(AngelloModel, AngelloHelper) {
    var main = this;

    main.types = AngelloModel.getTypes();
    main.statuses = AngelloModel.getStatuses();
    main.stories = AngelloModel.getStories();
    main.typesIndex = AngelloHelper.buildIndex(main.types, 'name');
    main.statusesIndex = AngelloHelper.buildIndex(main.statuses, 'name');

    main.setCurrentStory = function (story) {
        main.currentStory = story;
        main.currentStatus = main.statusesIndex[story.status];
        main.currentType = main.typesIndex[story.type];
    };

    main.createStory = function() {
        main.stories.push({
            title: 'New Story',
            description: 'Description pending.',
            criteria: 'Criteria pending.',
            status: 'Back Log',
            type: 'Feature',
            reporter: 'Pending',
            assignee: 'Pending'
        });
    };

    main.setCurrentStatus = function (status) {
        if (typeof main.currentStory !== 'undefined') {
            main.currentStory.status = status.name;
        }
    };

    main.setCurrentType = function (type) {
        if (typeof main.currentStory !== 'undefined') {
            main.currentStory.type = type.name;
        }
    };
});

myModule.directive('story', function() {
    return {
        scope: true,
        replace: true,
        template: '<div><h4>{{story.title}}</h4><p>{{story.description}}</p></div>'
    }
});

  (1) 其中第二个参数通过依赖注入的方式注入依赖的子模块,这样就可以在当前模块使用注入进来模块中的方法变量等。

  (2) 通过这种思想,我们可以针对不同的功能模块新建不同的Module,使得代码和项目结构更加清晰。

  (3) 从app.js中可以看出,Angello模块下定义了两个service AngelloModel和AngelloHelper,一个controller MainCtrl和一个directive story。

2.Views和Controllers

  为了方便起见,我们将AngularJS抽象成MVVM模型来讲解。

  从图中可以看出将view中的元素绑定到ViewModel上,Model会有一个提醒机制,当model值发生变化时,就会触发提醒ViewModel需要更新值了。当然,来自view端值发生改变时,也会通过ViewModel上的值改变,进而刷新model上的值。这就是双向数据绑定。

  需要注意的是,要定义一个controller,需要在页面中(index.html)通过AngularJS的内置指令ng-controller进行声明。如index.html中的<h1>{{main.tite}}</h1>对应定义在controller中的title,title的任何变化都会及时的相应在index.html上。

index.html

<!DOCTYPE HTML>
<html ng-app="Angello">
<head>
	<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
	<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
	<script type="text/javascript" src="app.js"></script>
	
	<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
	<link rel="stylesheet" href="app.css">

	<title>Angello Lite</title>
</head>
	<body>
		<div ng-controller="MainCtrl as main">
			<div class="col-md-4">
				<h2>Stories</h2>
				<story class="callout"
                       ng-repeat="story in main.stories"
                       ng-click="main.setCurrentStory(story)">
                </story>
				<br/>
				<a class="btn btn-primary" ng-click="main.createStory()">
                    <span class="glyphicon glyphicon-plus"></span>
                </a>
			</div>
			<div class="col-md-6 content">
				<h2>Story</h2>
				<form class="form-horizontal">
					<div class="form-group">
						<label class="control-label" for="inputTitle">Title</label>
						<div class="controls">
							<input type="text" class="form-control" id="inputTitle" placeholder="Title" ng-model="main.currentStory.title" />
						</div>
					</div>
					<div class="form-group">
						<label class="control-label" for="inputStatus">Status</label>
						<div class="controls">
							<select id="inputStatus" class="form-control" ng-model="main.currentStatus"
									ng-options="l.name for l in main.statuses"
									ng-change="main.setCurrentStatus(main.currentStatus)"></select>
						</div>
					</div>
					<div class="form-group">
						<label class="control-label" for="inputType">Type</label>
						<div class="controls">
							<select id="inputType" class="form-control" ng-model="main.currentType"
									ng-options="t.name for t in main.types"
									ng-change="main.setCurrentType(main.currentType)"></select>
						</div>
					</div>
					<div class="form-group">
						<label class="control-label" for="inputDescription">Description</label>
						<div class="controls">
							<textarea id="inputDescription" class="form-control" placeholder="Description" rows="3"
									  ng-model="main.currentStory.description"></textarea>
						</div>
					</div>
					<div class="form-group">
						<label class="control-label" for="inputAcceptance">Acceptance Criteria</label>
						<div class="controls">
							<textarea id="inputAcceptance" class="form-control" placeholder="Acceptance Criteria" rows="3"
									  ng-model="main.currentStory.criteria"></textarea>
						</div>
					</div>
					<div class="form-group">
						<label class="control-label" for="inputReporter">Reporter</label>
						<div class="controls">
							<input type="text" class="form-control" id="inputReporter" placeholder="Reporter" ng-model="main.currentStory.reporter" />
						</div>
					</div>
					<div class="form-group">
						<label  for="inputAssignee">Assignee</label>
						<div class="controls">
							<input type="text" class="form-control" id="inputAssignee" placeholder="Assignee" ng-model="main.currentStory.assignee" />
						</div>
					</div>
				</form>
			</div>
		</div>
	</body>
</html>

3.Service

  前面提到过,Service是一些公用的数据和方法的封装,可以用在不同的controller中。AngularJS可以使用依赖注入的方法将这些定义的service注入到相应的controller中,便可以使用service中的数据和方法。

4.Directive

  directive是angularjs的一大亮点。AngularJS自己有一些内置指令如ng-click、ng-if等,用户也可以自己定义指令,如这里的story。

  此篇旨在大致的了解了AngularJS的过人之处,如何构建项目,每个部分的作用。

  如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。