AngularJS(一)——认识AngularJS之MVC架构
MVC及AngularJS
M(Module):
Module
在AngularJS中表示是数据模型层。- 在
AngularJS
中,模块是定义应用(Application)的最主要方式。模块包含了主要的应用代码。 - 一个应用(PC端、移动端)可以包含多个模块,每个模块都包含了定义具体功能的代码。
- 使用模块可以带来不少的好处,比如:
- 1、保持全局命名空间的清洁;
因为在JavaScript代码里面尽可能地少去使用全局变量的声明方式(JavaScript基础(一)),模块的引入很好地解决了AngularJS引入全局变量的问题(这样的解释Big-man自我感觉理解更好一些的);
- 2、编写测试代码更容易,并能保持其清洁,以便更容易找到相互隔离的功能;
- 3、易于在不同应用间复用代码;
- 4、使应用能够以任意顺序加载代码的各个部分。
AngularJS
允许我们使用angular.module()
方法来声明模块,这个方法能够接受两个参数,第一个是模块的名称,第二个是依赖列表,也就是可以被依赖注入到模块中的对象列表。angular.module('myApp', []);
注:Big-man这里所写下的方法相当于AngularJs模块的
setter
方法,是用来定义模块的。
(function () {
'use strict';
angular.module('hz.dashboard', [
'hz.dashboard.workflow',
'hz.dashboard.launch-instance',
'...',
])
})();
-
类似于上面代码中的实例,
hz.dashboard
就是这个模块的名称,[...]
中的内容就是这个模块所依赖的内容。 -
angular.module('myApp');
注:然而上面的这个方法是用户获取应用,相当于AngularJs的
getter
方法,用来获取对模块的引用。
- 参数说明
- 1、name(字符串)
- name是模块的名称,字符串变量。
- 2、requires(字符串数组)
- requires包含了一个字符串变量组成的列表,每个元素都是一个模块名称,本模块依赖于这些模块,依赖需要在本模块加载由注入器 进行预加载。
- 示例1:
<ul ng-app="myApp" ng-controller="myCtrl">
<li ng-repeat="x in items track by $index">
<strong>{{x}}</strong>
</li>
</ul>
<script>
//自定义模块
var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
$scope.items = ['fengfeng', 'I', 'love', 'you', '];
});
</script>
- 对应关系:
ng-app="myApp"
<——>angular.module('myApp', []);
ng-controller="myCtrl"
<——>app.controller('myCtrl', function ($scope)
ng-app指令的定义和用法:
ng-app指令用于告诉AngularJS应用当前这个元素是根元素。
所有AngularJS应用都必须需要一个根元素。
HTML文档中只允许有一个ng-app指令,如果有多个ng-app指令,则只有第一个会被使用。
- 输出:
fengfeng
I
love
you
!
- 示例2
<div class="alert alert-danger" ng-app="myApp" ng-controller="myCtrl">
{{a}}+{{b}}={{c}}
</div>
<script>
//自定义模块1,
angular.module('common', []).service('addition', function () {
this.add = function (a, b, c) {
return a + b + c;
}
});
//自定义模块2,依赖于模块一
var app = angular.module('myApp', ['common']);
app.controller('myCtrl', function ($scope, addition) {
$scope.a = 'rose';
$scope.b = 'jackdan9';
$scope.c = 'love';
$scope.c = addition.add($scope.a, $scope.b, $scope.c);
});
</script>
V(View):
-
中文翻译过来是视图、外表展示。
-
但是在AngularJS中的View表示的是视图层,负责展示。
-
AngularJS支持通过在单个页面上的多个视图的单页应用。要做到这一点AngularJS提供
ng-view
和ng-template
指令,以及$routeProvider
服务。接下来Big-man会一一进行分析其中的作用。 -
ng-view
-
ng-view
标记只是简单地创建一个占位符,是一个相应的视图(HTML或ng-template视图),可以根据配置来放置。
<div ng-app="mainApp">
...
<div ng-view>
<h2>Love Rose</h2>
</div>
</div>
-
**使用功能:**定义一个
div
与ng-view
在主模块中。 -
ng-template
-
ng-template
指令是用来创建使用script标签的HTML视图。它包含一个用于由**$routeProvider映射控制器视图“id”属性**。
<div ng-app="mainApp">
...
<script type="text/ng-template" id="loveRose.html">
<h2> Love Rose </h2>
{{message}}
</script>
</div>
-
**使用功能:**定义类型作为主模块中
ng-template
的脚本块。 -
$routeProvider
-
$routeProvider
是组网址的配置,将它们映射相应的HTML页面或 ng-template,并附加一个控制器使用相同键的服务。
<div ng-app="mainApp">
...
<script type="text/ng-template" id="loveRose.html">
<h2> Love Rose </h2>
{{message}}
</script>
</div>
- 使用功能:定义类型作为主模块中 ng-template 的脚本块。
var mainApp = angular.module("mainApp", ['ngRoute']);
mainApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/loveRose', {
templateUrl: 'loveRose.html',
controller: 'loveRoseController'
}).
when('/viewRose', {
templateUrl: 'viewRose.html',
controller: 'viewRoseController'
}).
otherwise({
redirectTo: '/loveRose'
});
}]);
-
使用功能: 定义主模块的脚本块,并设置路由配置。
-
结合上面的分析,Big-man总结出了以下 需要考虑的重要问题:
$routeProvider
被定义为使用关键字作为**’$routeProvider’**下mainApp模块的配置功能;$routeProvider
当定义了URL“/addStudent”映射到"addStudent.html"。 addStudent.html应存在于相同的路径主要的html 页面。如果htm页面没有定义,那么ng-template被**id=“addStudent.html”**使用。我们已经使用了ng-template;"otherwise"
是用来设置的默认视图;"conlloer"
是用来设置该视图对应的控制器;
-
完整实例:下面Big-man将会给出一个较为完整的实例,但是分析输出结果,还请大家进行分析。
<html>
<head>
<title>Angular JS Views</title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular-route.min.js"></script>
</head>
<body>
<h2>AngularJS Sample Application</h2>
<div ng-app="mainApp">
<p><a href="#loveRose">Love Rose</a></p>
<p><a href="#viewRose">View Rose</a></p>
<div ng-view></div>
<script type="text/ng-template" id="loveRose.html">
<h2> Love Rose </h2>
{{message}}
</script>
<script type="text/ng-template" id="viewRose.html">
<h2> View Rose </h2>
{{message}}
</script>
</div>
<script>
var mainApp = angular.module("mainApp", ['ngRoute']);
mainApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/loveRose', {
templateUrl: 'loveRose.html',
controller: 'LoveRoseController'
}).
when('/viewRose', {
templateUrl: 'viewRose.html',
controller: 'ViewRoseController'
}).
otherwise({
redirectTo: '/loveRose'
});
}]);
mainApp.controller('LoveRoseController', function($scope) {
$scope.message = "This page will be used to display jackdan9's love for rose";
});
mainApp.controller('ViewRoseController', function($scope) {
$scope.message = "This page will be used to display the girl";
});
</script>
</body>
</html>
C(Controller):
-
中文翻译过来是控制器、控制者;
-
但是在AngularJS中的Controlller表示的是业务逻辑和控制逻辑。
-
控制器在
Angularjs
中的作用是增强视图,它实际就是一个函数,用来向视图中的作用域添加额外的功能,Big-man用它来给作用域对象设置初始状态,并添加自定义行为。 -
当Big-man在页面上创建一个控制器时,
Angularjs
会生成并传递一个$scope
给这个控制器,由于Angularjs
会自动实例化控制器,所以Big-man只需要写构造函数即可。 -
下面的例子展示了控制器初始化:
function my Controller($scope){
$scope.msg="hello, jackdan9!";
}
- Big-man分析了上面的创建控制器的方法,Big-man个人认为这样的创建方式会污染全局命名空间,更合理的办法是创建一个模块,然后在模块中创建控制器,如下:
var myApp=angular.module("myApp",[]);
myApp.controller("myController",function($scope){
$scope.msg="hello, jackdan9!";
})
- Big-man采用内置指令
ng-click
可以将按钮、链接等其他任何DOM元素同点击事件进行绑定。ng-click
指令将浏览器中的mouseup事件,同设置在DOM元素上的事件处理程序绑定在一起(例如,当浏览器在某个DOM元素上触发了点击事件,函数就会被调用)。和前面的例子类似,绑定看起来是这样的:
<div ng-controller="FirstController">
<h4>The simplest adding machine ever</h4>
<button ng-click="add(1)" class="button">Add</button>
<a ng-click="subtract(1)" class="button alert">Subtract</a>
<h4>Current count: {{ counter }}</h4>
</div>
- 按钮和链接都被绑定在了内部
$scope
的一个操作上,当点击任何一个元素时AngularJS都会调用相应的方法。 - 注意,当设置调用哪个函数时,会同时用括号传递一个参数(add(1))
app.controller('FirstController', function($scope) {
$scope.counter = 0;
$scope.add = function(amount) { $scope.counter += amount; };
$scope.subtract = function(amount) { $scope.counter -= amount; };
});
Angularjs
与其他框架的最大区别在于,控制器并不适合来执行DOM操作、格式化或数据操作,以及除存储数据模型之外的状态维护操作,它只是视图和$scope之间的桥梁。
- 控制器嵌套(作用域包含作用域)
- AngularJS应用的任何一个部分,无论它渲染在哪个上下文中,都有父级作用域存在。对于
ng-app
所处的层级来讲,它的父级作用域就是$rootScope
。 - 默认情况下,AngularJS在当前作用域中无法找到某个属性时,便会在父级作用域中进行查找。如果AngularJS找不到对应的属性,会顺着父级作用域一直向上寻找,直到抵达
$rootScope
为止。如果在$rootScope
中也找不到,程序会继续运行,但视图无法更新。Big-man个人认为在这一点上,类似于js的作用域链,这一层无法找到的作用域会反馈到上一层的作用域上。 - 通过例子来看一下这个行为。创建一个ParentController,其中包含一个user对象,再创建一个ChildController来引用这个对象:
app.controller('ParentController', function($scope) {
$scope.person = {greeted: false};
});
app.controller('ChildController', function($scope) {
$scope.sayHello = function() {
$scope.person.name = 'Ari Lerner';
};
});
- 如果我们将ChildController置于ParentController内部,那ChildController的
$scope
对象的父级作用域就是ParentController的$scope
对象。根据原型继承的机制,我们可以在子作用域中访问ParentController的$scope
对象。
<div ng-controller="ParentController">
<div ng-controller="ChildController">
<a ng-click="sayHello()">Say hello</a>
</div>
{{ person }}
</div>
总结
- 理解清楚MVC及AngularJS能够对AnguarJS起到一个很好的入门作用。
JackDan Thinking.