问题1:ng-app指令的使用以及自定义指令
我们看看指令本身的代码是如何定义的
- <!doctype html>
- <!--这里的ng-app的属性值就是模块的名称,也就是 angular.module("MyModule",[])中的MyModule-->
- <html ng-app="MyModule">
- <head>
- <Meta charset="utf-8">
- </head>
- <body>
- <hello></hello>
- <!--这个标签被完全替换为'<div>Hi everyone!</div>',这一点很重要的-->
- </body>
- <script src="js/angular-1.3.0.js"></script>
- <!--引入指令-->
- <script src="HelloAngular_Directive.js"></script>
- </html>
问题2:我们来理解一下angularjs的MVC模式
下面是控制器的代码
- <!doctype html>
- <!--这里的ng-app指令表明下面的所有的指令全部让angularjs处理,只有被具有ng-app属性的DOM元素包含的元素才会受到angularjs的影响-->
- <html ng-app>
- <head>
- <Meta charset="utf-8">
- </head>
- <body>
- <!--这里指定了一个controller,这个controller是view视图和数据之间的桥梁-->
- <div ng-controller="HelloAngular">
- <!--这里指定的视图,也就是用于显示的view-->
- <p>{{greeting.text}},Angular</p>
- </div>
- </body>
- <script src="js/angular-1.3.0.js"></script>
- <script src="HelloAngular_MVC.js"></script>
- </html>
问题3:通用controller是通过$scope来完成继承的,但是我们不建议使用通用controller,而是使用服务
- function HelloAngular($scope) {
- $scope.greeting = {
- text: 'Hello'
- };
- }
下面是三个controller的代码
- <!doctype html>
- <html ng-app>
- <head>
- <Meta charset="utf-8">
- </head>
- <body>
- <!--这里是CommonController的部分,这个controller指定了内部两个controller共有的逻辑-->
- <div ng-controller="CommonController">
- <!--这里是内部第一个controller-->
- <div ng-controller="Controller1">
- <p>{{greeting.text}},Angular</p>
- <button ng-click="test1()">test1</button>
- </div>
- <!--这里是内部第二个controller-->
- <div ng-controller="Controller2">
- <p>{{greeting.text}},Angular</p>
- <button ng-click="test2()">test2</button>
- <button ng-click="commonFn()">通用</button>
- </div>
- </div>
- </body>
- <script src="js/angular-1.3.0.js"></script>
- <script src="MVC3.js"></script>
- </html>
- //这个通用的controller指定的是两个controller都具有的方法
- function CommonController($scope){
- $scope.commonFn=function(){
- alert("这里是通用功能!");
- };
- }
- //这里是第一个controller指定了其特有的功能
- function Controller1($scope) {
- $scope.greeting = {
- text: 'Hello1'
- };
- $scope.test1=function(){
- alert("test1");
- };
- }
- //这里是第一个controller指定了其特有的功能
- function Controller2($scope) {
- $scope.greeting = {
- text: 'Hello2'
- };
- $scope.test2=function(){
- alert("test2");
- }
- }
注意:其实$scope是一个POJO(plain Old JavaScript Object);$scope提供了一些工具方法,如$watch,$apply等;$scope是表达式执行环境,也就是作用域;$scope是树形结构和DOM标签平行;子$scope继承父$scope的所有的属性和方法;每一个angular应用只有一个根$scope,一般位于ng-app上;$scope可以用于传播事件,类似DOM可以往上也可以往下;可以用angular.element($0).scope进行调试。总之,$scope不仅仅是MVC的基础,而且也是双向数据绑定的基础!
问题4:ng-repeat的使用,同时指定了$scope会继承$rootScope,就像原型链一样
下面是两个controller,同时注意这时候$scope会继承$rootScope的属性
- <!doctype html>
- <html ng-app>
- <head>
- <Meta charset="utf-8">
- <link rel="stylesheet" type="text/css" href="Scope1.css" />
- </head>
- <body>
- <div class="show-scope-demo">
- <!--这里是第一个controller,是GreetCtrl-->
- <div ng-controller="GreetCtrl">
- Hello {{name}}!
- </div>
- <!--这里是第二个controller,是ListCtrl-->
- <div ng-controller="ListCtrl">
- <ol>
- <!--ng-repeat指令的使用-->
- <li ng-repeat="name in names">
- {{name}} from {{department}}
- </li>
- </ol>
- </div>
- </div>
- </body>
- <script src="js/angular-1.3.0.js"></script>
- <script src="Scope1.js"></script>
- </html>
问题5:我们来看看$emit和$broadcast用于事件触发的不同
下面是控制器的代码
- <!doctype html>
- <html ng-app>
- <head>
- <Meta charset="utf-8">
- <link rel="stylesheet" type="text/css" href="Scope1.css" />
- </head>
- <body>
- <!--第一个控制器EventController-->
- <div ng-controller="EventController">
- Root scope
- <tt>MyEvent</tt> count: {{count}}
- <ul>
- <!--这里是内部的controller,也是通过EventController来控制的-->
- <li ng-repeat="i in [1]" ng-controller="EventController">
- <!--这里是调用$emit-->
- <button ng-click="$emit('MyEvent')">
- $emit('MyEvent')
- </button>
- <!--这里是调用$broadcast-->
- <button ng-click="$broadcast('MyEvent')">
- $broadcast('MyEvent')
- </button>
- <br>
- Middle scope
- <tt>MyEvent</tt> count: {{count}}
- <!--EventController-->
- <ul>
- <li ng-repeat="item in [1,2]" ng-controller="EventController">
- Leaf scope
- <tt>MyEvent</tt> count: {{count}}
- </li>
- </ul>
- </li>
- </ul>
- </div>
- </body>
- <script src="js/angular-1.3.0.js"></script>
- <script src="Scope2.js"></script>
- </html>
通过测试我们发现$emit触发事件会导致从同级作用域不断往上传播,但是$broadCast会使得事件从同级作用域不断往下传播。但是不管是$emit还是$broadcast都会在同级作用域之间传播。
- function EventController($scope) {
- $scope.count = 0;
- //这个$scope具有$on方法来监测具体的事件,这里是监测'MyEvent'事件,每次监听到这个事件就把count++
- $scope.$on('MyEvent',function() {
- $scope.count++;
- });
- }
问题6:我们看看如何让angularjs实现了站内路由,其本质还是通过hash来完成的
- <!doctype html>
- <html ng-app="bookStoreApp">
- <head>
- <Meta charset="UTF-8">
- <title>BookStore</title>
- <!--当express直接访问/的时候被重定向到这里,然后静态资源文件如js等都是在public目录下进行加载的-->
- <script src="1.3.0.14/angular.js"></script>
- <script src="1.3.0.14/angular-route.js"></script>
- <script src="1.3.0.14/angular-animate.js"></script>
- <!--然后加载app.js,这是一个模块,定义了该模块依赖的一些如控制器,过滤器,服务,指令等-->
- <script src="app.js"></script>
- <script src="controllers.js"></script>
- <script src="filters.js"></script>
- <script src="services.js"></script>
- <script src="directives.js"></script>
- </head>
- <body>
- <!--这里是视图显示区域-->
- <div ng-view>
- </div>
- </body>
- </html>
我们再来看看app.js中如何指定了依赖模块,同时是如何实现站内路由的。注意:ng-view是由ngRouter模块提供的一个特殊指令,他的独特之处是在HTML中给$router对应的视图内容占位,他会创建自己的作用域并将模版嵌套在内部。ng-view是一个优先级为1000的终极指令,angularjs不会运行同一个元素上的低优先级指令。ngView指令遵循下面的规则:
。每次触发$routeChangeSuccess事件视图都会更新
。如果某个模版和当前的路由相关联:
(1)创建一个新的作用域;(2)移除上一个视图,同时上一个作用域也会被清除;(3)将新的作用域和当前模版关联在一起;(4)如果路由中有相关的定义,那么就把对应的控制器和当前作用域关联起来;(5)触发$viewContentLoaded事件;(6)如果提供了onload属性,调用该属性指定的函数。
很显然是通过模块的config方法来完成的,同时实现了注入$routeProvider对象,最后通过这个对象的when...otherwise方法来实现路由的。记住,上面的ng-view是指定了视图的显示区域。其站内路由还是通过hash来完成的:
- //定义了一个模块bookStoreApp,第二个参数是该模块依赖的模块。其中<bookStoreCtrls>是一个模块,其中封装了两个控制器分别为bookStoreCtrls,BookListCtrl
- //其中模块<bookStoreFilters>是一个过滤器
- //模块<bookStoreServices>定义了一个服务
- //模块<bookStoreDirectives>定义了一个指令集合
- var bookStoreApp = angular.module('bookStoreApp',[
- 'ngRoute','ngAnimate','bookStoreCtrls','bookStoreFilters','bookStoreServices','bookStoreDirectives'
- ]);
- //在这个app模块中我们配置了路由,如果是访问了hello就会重定向到http://localhost:3008/hello这个视图文件
- //同时这个视图文件通过HelloCtrl这个控制器进行渲染
- bookStoreApp.config(function($routeProvider) {
- $routeProvider.when('/hello',{
- templateUrl: 'http://localhost:3008/hello',controller: 'HelloCtrl'
- }).when('/list',{
- //如果是list那么渲染视图http://localhost:3008/bookList,同时渲染工作由BookListCtrl来完成
- templateUrl:'http://localhost:3008/bookList',controller:'BookListCtrl'
- }).otherwise({
- redirectTo: '/hello'
- })
- });
我们谈谈ajax:ajax的页面浏览器回退按钮会失效;无法分享页面,也就无法加书签;SEO无法起作用,于是就有了前端路由的观点。前端路由的原理:通过hash值#;HTML5提供的API也可以完成;路由的核心是给应用定义"状态";使用路由会影响应用整体的编码方式(预先定义好状态);考虑兼容性问题与优雅降级。
问题7:我们建议在定义controller时候不是在函数中直接定义,而是在模块中定义:
第一种方式直接在函数中定义:
第二种方式是首先定义模块,然后在模块中定义控制器,这是我们推荐的方式:
- function HelloAngular($scope) {
- $scope.greeting = {
- text: 'Hello'
- };
- }
- var helloModule=angular.module('HelloAngular',[]);
- helloModule.controller('helloNgCtrl',['$scope',function($scope){
- $scope.greeting = {
- text: 'Hello'
- };
- }]);
我们推荐下面的编码逻辑:
问题7:使用ng-bind防止页面快速刷新或者网速较慢的时候看到源代码{{greeting.text}}
控制器代码如下(建议用模块来定义):
- <!doctype html>
- <html ng-app>
- <head>
- <Meta charset="utf-8">
- </head>
- <body>
- <!--引用一个控制器HelloAngular-->
- <div ng-controller="HelloAngular">
- <!--ng-bind用于绑定,之所有使用ng-bind而不是使用{{greeting.text}}是因为在网速慢的时候或者快速刷新的时候会看到{{greeting.text}}这个源代码-->
- <p><span ng-bind="greeting.text"></span>,Angular</p>
- </div>
- </body>
- <script src="js/angular-1.3.0.js"></script>
- <script src="HelloAngular_MVC.js"></script>
- </html>
问题8:使用ng-class来添加class,而不是使用为$scope添加属性这种方式
- function HelloAngular($scope) {
- $scope.greeting = {
- text: 'Hello'
- };
- }
同时相应的点击事件来修改数据模型中的值,进而使得视图内容能够动态改变,而视图的样式通过ng-class来修改了。除了ng-class另外一种使用 细说Angular ng-class
- <!doctype html>
- <html ng-app="MyCSSModule">
- <head>
- <Meta charset="utf-8">
- <link rel="stylesheet" href="NgClass.css">
- </head>
- <body>
- <!--这里是控制器HeaderController,如果isError为true那么添加error类,如果isWarning为true那么谈价类warning就可以了-->
- <div ng-controller='HeaderController'>
- <!--这里是视图,其类名和提示信息都是动态添加的,这一点要弄清楚-->
- <div ng-class='{error: isError,warning: isWarning}'>{{messageText}}</div>
- <button ng-click='showError()'>Simulate Error</button>
- <button ng-click='showWarning()'>Simulate Warning</button>
- </div>
- </body>
- <script src="js/angular-1.3.0.js"></script>
- <script src="NgClass.js"></script>
- </html>
问题8:使用ng-show来控制元素的隐藏和显示
- var myCSSModule = angular.module('MyCSSModule',[]);
- //定义一个模块MyCSSModule
- myCSSModule.controller('HeaderController',//为模块定义个控制器HeaderController
- function($scope) {
- $scope.isError = false;
- $scope.isWarning = false;
- $scope.showError = function() {
- $scope.messageText = 'This is an error!';
- $scope.isError = true;
- $scope.isWarning = false;
- };
- $scope.showWarning = function() {
- $scope.messageText = 'Just a warning. Please carry on.';
- $scope.isWarning = true;
- $scope.isError = false;
- };
- }
- ])
控制器内部通过非表达式来实现开关效果
- <!doctype html>
- <html ng-app="MyCSSModule">
- <head>
- <Meta charset="utf-8">
- </head>
- <body>
- <div ng-controller='DeathrayMenuController'>
- <!--点击的时候就触发toggleMenu逻辑,在该方法里面修改了数据模型的值-->
- <button ng-click='toggleMenu()'>Toggle Menu</button>
- <!--ng-show指令通过判断表达式的值进而决定是否应该显示内容-->
- <ul ng-show='menuState.show'>
- <li ng-click='stun()'>Stun</li>
- <li ng-click='disintegrate()'>Disintegrate</li>
- <li ng-click='erase()'>Erase from history</li>
- </ul>
- <div/>
- </body>
- <script src="js/angular-1.3.0.js"></script>
- <script src="NgShow.js"></script>
- </html>
上面演示了如何实现jQuery中的toggleClass效果
- var myCSSModule = angular.module('MyCSSModule',[]);
- //这里定义一个模块<MyCSSModule>,在模块上定义一个控制器DeathrayMenuController
- myCSSModule.controller('DeathrayMenuController',function($scope) {
- $scope.menuState={show:false};
- $scope.toggleMenu = function() {
- //这里的toggleMenu通过非符号'!'就能够动态改变了
- $scope.menuState.show = !$scope.menuState.show;
- };
- }
- ])