angular(常识)

我觉得angularjs是前端框架,而jquery只是前端工具,这两个还是没有可比性的。

看知乎上关于jquery和angular的对比http://www.zhihu.com/question/27471743

优点:1. 模板功能强大丰富,并且是声明式的,自带了丰富的Angular指令;2. 是一个比较完善的前端MV*框架,包含模板,数据双向绑定,路由,模块化,服务,过滤器,依赖注入等所有功能;3. 自定义Directive,比jQuery插件还灵活,但是需要深入了解Directive的一些特性,简单的封装容易,复杂一点官方没有提供详细的介绍文档,我们可以通过阅读源代码来找到某些我们需要的东西,如:在directive使用 $parse;4. ng模块化比较大胆的引入了Java的一些东西(依赖注入),能够很容易的写出可复用的代码,对于敏捷开发的团队来说非常有帮助,我们的项目从上线到目前,UI变化很大,在摸索中迭代产品,但是js的代码基本上很少改动。5. 补充:Angular支持单元测试和e2e-testing。缺点:1. 验证功能错误信息显示比较薄弱,需要写很多模板标签,没有jQuery Validate方便,所以我们自己封装了验证的错误信息提示,详细参考 why520crazy/w5c-validator-angular · GitHub ;2. ngView只能有一个,不能嵌套多个视图,虽然有 angular-ui/ui-router · GitHub 解决,但是貌似ui-router 对于URL的控制不是很灵活,必须是嵌套式的(也许我没有深入了解或者新版本有改进);3. 对于特别复杂的应用场景,貌似性能有点问题,特别是在Windows下使用chrome浏览器,不知道是内存泄漏了还是什么其他问题,没有找到好的解决方案,奇怪的是在IE10下反而很快,对此还在观察中;4. 这次从1.0.X升级到1.2.X,貌似有比较大的调整,没有完美兼容低版本,升级之后可能会导致一个兼容性的BUG,具体详细信息参考官方文档 AngularJS ,对应的中文版本:Angular 1.0到1.2 迁移指南5. ng提倡在控制器里面不要有操作DOM的代码,对于一些jQuery 插件的使用,如果想不破坏代码的整洁性,需要写一些directive去封装插件,但是现在有很多插件的版本已经支持Angular了,如:jQuery File Upload Demo6. Angular 太笨重了,没有让用户选择一个轻量级的版本,当然1.2.X后,Angular也在做一些更改,比如把route,animate等模块独立出去,让用户自己去选择。当然使用的人多才会暴露更多的问题,一起为这些问题寻找解决方案是一个社区的良性趋势,选择Angular,的确使我们的开发效率大大提高。

2009年google feedback project 1500行
为了解决ajax开发的痛苦

1. 几个常用的概念
a.客户端模板:模板和数据都会发送到浏览器中
b.mvc:
c.数据绑定:自动将Model和view间的数据同步。
angular 实现数据绑定的方式,可以让我们把model当做程序中唯一可信的数据来源。view始终是model的投影。。当model发生变化时,会自动反映到view上。
大多数的数据绑定都是单向的,当我们的model和view修改后要去提醒另外一个的话,就必须使用ajax之类的,比如jquery还要手动的同步,这样子的话,增加了不必要的麻烦。
d.依赖注入:

2.依赖注入 的详解

回顾下spring中的ioc 控制反转:

控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。依赖注入应用比较广泛。

个人理解:就是本来需要你在程序设计时,创建的某些对象,交给spring来管理,当你需要某个时候需要某个对象的时候spring在给你,这样子对象的生命周期之类的就由spring来维护了。

js的依赖注入:(我们这里所说的依赖注入和上面的ioc或者di还是有点不同的,我们这里更局限在依赖这个词)
方法1:

var A = function () {
   this.getName = function () {
   return '张三';
 }
}

var B = function (obj) {
// B 依赖于 a
document.write(obj.getName());
}

// a 注入 ba

var a = new A;
var b = new B(a);

========================

方法2:

var A = function () {
   this.getName = function () {
   return '张三';
 }
}

var a = new A;

var B = function () {
// B 依赖于 a
document.write(a.getName());
}

// a 注入 ba


var b = new B(a);

===========================

3. 在 ng-app下

<input type="text" ng-model="name" value=""/>

<!--angular的表达式-->
{{ name }}

<input type="text" ng-model="name" value=""/>

这三个name的数据是绑定。

4. 控制器

<div ng-controller="firstController">
    <input type="text" value="" ng-model="name"/>
    <input type="text" value="" ng-model="age"/>
    {{name}}
    {{age}}
</div>

var firstController = function($scope){

      // $scope 我们叫做作用域
      // 申明一个Model
      $scope.name = '张三';

     $scope.age = 20;

}

5. 多个控制器

<div ng-controller="firstController">
   <input type="text" value="" ng-model="name"/>

   <div ng-controller="secondController">
   <input type="text" value="" ng-model="name"/>
    </div>
</div>

var firstController = function($scope){

$scope.name = '张三';
console.log($scope);

}

var secondController = function($scope){

console.log($scope);
}

6. $apply方法

var firstController = function($scope){

    $scope.date = new Date();

    // setInterval(function(){
    // // 这里虽然变 但是并没有触发 脏检查
    // $scope.date = new Date();
   //
   // },1000)

   setInterval(function(){
          $scope.$apply(function(){
              $scope.date = new Date();
              //....会去触发脏检查
         })
  },1000)


   // 触发一次脏检查
}

7. watch

var firstController = function($scope){

    $scope.name = '张三';
    $scope.data = {
        name :'李四',
        count:20
    }
   $scope.count = 0;

   // 监听一个model 当一个model每次改变时 都会触发第2个函数
   $scope.$watch('name',function(newValue,oldValue){

      ++$scope.count;

      if($scope.count > 30){
         $scope.name = '已经大于30次了';
     }
  });


    $scope.$watch('data',function(){

    },true)

  // 上面的true表示只要有一个true发生改变,那么这个watch就触发。
}

8. 一个简单的互动的demo代码

 1  <div ng-controller="cartController" class="container">
 2         <table class="table" ng-show="cart.length">
 3             <thead>
 4                 <tr>
 5                     <th>产品编号</th>
 6                     <th>产品名字</th>
 7                     <th>购买数量</th>
 8                     <th>产品单价</th>
 9                     <th>产品总价</th>
10                     <th>操作</th>
11                 </tr>
12             </thead>
13             <tbody>
14                 <tr ng-repeat="item in cart">
15                     <td>{{item.id}}</td>
16                     <td>{{item.name}}</td>
17                     <td>
18                         <button type="button" ng-click="reduce(item.id)" class="btn tn-primary">-</button>
19                         <input type="text" value="{{item.quantity}}" ng-model="item.quantity" >
20                         <button type="button" ng-click="add(item.id)" class="btn tn-primary">+</button>
21                     </td>
22                     <td>{{item.price}}</td>
23                     <td>{{item.price * item.quantity}}</td>
24                     <td>
25                         <button type="button" ng-click="remove(item.id)" class="btn btn-danger">移除</button>
26                     </td>
27                 </tr>
28                 <tr>
29                     <td>
30                         总购买价
31                     </td>
32                     <td>
33                         {{totalPrice()}}
34                     </td>
35                     <td>
36                         总购买数量
37                     </td>
38                     <td>
39                         {{totalQuantity()}}
40                     </td>
41                     <td colspan="2">
42                         <button type="button" ng-click="cart = {}" class="btn btn-danger">清空购物车</button>
43                     </td>
44                 </tr>
45             </tbody>
46         </table>
47 
48         <p ng-show="!cart.length">您的购物车为空</p>
49     </div>
  1 var cartController = function ($scope) {
  2 
  3     $scope.cart = [
  4         {
  5             id: 1000,
  6             name: 'iphone5s',
  7             quantity: 3,
  8             price: 4300
  9         },
 10         {
 11             id: 3300,
 12             name: 'iphone5',
 13             quantity: 30,
 14             price: 3300
 15         },
 16         {
 17             id: 232,
 18             name: 'imac',
 19             quantity: 4,
 20             price: 23000
 21         },
 22         {
 23             id: 1400,
 24             name: 'ipad',
 25             quantity: 5,
 26             price: 6900
 27         }
 28     ];
 29 
 30 
 31     /**
 32      * 计算购物总价
 33      */
 34     $scope.totalPrice = function () {
 35         var total = 0;
 36         angular.forEach($scope.cart, function (item) {
 37             total += item.quantity * item.price;
 38         })
 39         return total;
 40     }
 41 
 42     /**
 43      * 计算总购买数
 44      */
 45     $scope.totalQuantity = function () {
 46         var total = 0;
 47         angular.forEach($scope.cart, function (item) {
 48             total += parseInt(item.quantity);
 49         })
 50         return total;
 51     }
 52 
 53 
 54     /**
 55      * 找一个元素的索引
 56      */
 57     var findIndex = function (id) {
 58         var index = -1;
 59 
 60         angular.forEach($scope.cart, function (item, key) {
 61             if (item.id === id) {
 62                 index = key;
 63                 return;
 64             }
 65         });
 66 
 67         return index;
 68     }
 69 
 70 
 71     /**
 72      * 为某个产品添加一个数量
 73      */
 74     $scope.add = function (id) {
 75         var index = findIndex(id);
 76 
 77         if (index !== -1) {
 78             ++$scope.cart[index].quantity;
 79         }
 80     }
 81 
 82 
 83     /**
 84      * 为某个产品减少一个数量
 85      */
 86     $scope.reduce = function (id) {
 87         var index = findIndex(id);
 88 
 89         if (index !== -1) {
 90             var item = $scope.cart[index];
 91             if(item.quantity > 1){
 92                 --item.quantity;
 93             }else{
 94                 var returnKey = confirm('是否从购物车内删除该产品!');
 95                 if(returnKey){
 96                     $scope.remove(id);
 97                 }
 98             }
 99 
100         }
101     }
102 
103     /**
104      * 移除一项
105      */
106     $scope.remove = function (id) {
107 
108 
109         var index = findIndex(id);
110         // 如果找到了那个item
111         if (index !== -1) {
112             $scope.cart.splice(index, 1);
113         }
114 
115         // 自动做脏检查
116     }
117 
118     // 监听数量 如果小于 1 则让用户判断是否要删除产品
119     $scope.$watch('cart',function(newValue,oldValue){
120 
121         angular.forEach(newValue,function(item,key){
122             if(item.quantity < 1){
123                 var returnKey = confirm('是否从购物车内删除该产品!');
124                 if(returnKey){
125                     $scope.remove(item.id);
126                 }else{
127                     item.quantity = oldValue[key].quantity;
128                 }
129             }
130         })
131     },true);
    //如果这个方式和上边的reduce同时执行的话,特别是reduce为0的时候, 先执行reduce方法,remove之后,执行这个函数的时候,就已经找不到那个cart中对应的值了,所以confirm不会重复弹出。
132 133 134 135 }

9. 控制器属于模块    。

模块是组织业务的一个框架,在一个模块当中定义多个服务。当引入了一个模块的时候,就可以使用这个模块提供的一种或多种服务了。
angularjs本身的一个默认模块叫做ng,它提供了$http,$scope等等服务。
服务只是模块提供的多种机制中的一种,其他的而还有指令(directive),
过滤器(filter),及其他配置信心。
也可以在已有的模块中新定义一个服务,也可以先定义一个模块,然后在新模块中定义新服务,。
服务是需要显示的声明依赖引入关系的,让ng自动地做注入。

<div ng-app="myApp">

        <div ng-controller="firstController">
            {{name}}
        </div>

    </div>
var myApp = angular.module('myApp',[]);


myApp.controller('firstController',function($scope){
    $scope.name = '张三';
});

10.  

$provide.service() 必须返回对象(数组也是对象),不能返回字符串之类的。
$provide.factory 这个可以返回任何类型。

var myApp = angular.module('myApp',[],function($provide){

    // 自定义服务
    $provide.provider('CustomService',function(){

        this.$get = function(){
            return {
                message : 'CustomService Message'
            }
        }
    });

    // 自定义工厂
    $provide.factory('CustomFactory',function(){
        return [1,2,3,4,5,6,7];
    });

    // 自定义服务
    $provide.service('CustomService2',function(){
        return 'aaa';
    })

});

myApp.controller('firstController',function($scope,CustomFactory,CustomService2){
    $scope.name = '张三';

    console.log(CustomFactory);

    console.log(CustomService2);

});

//myApp.service();
//myApp.factory();

11. 

服务本身是一个任意的对象。
ng提供服务的过程涉及它的依赖注入机制。
angular 是用$provider对象来实现自动依赖注入机制,注入机制通过调用一个provider的$get方法,
把得到对象作为参数进行相关调用。
$provider.provider是一种定义服务的方法,$provider还提供了很多很多简便的方法,这些方法还被module所引用。
也许这里有人问:control层和service层的区别:
1.事务的回滚在service层,比如重定向之类的在control层。
view层:    结合control层,显示前台页面。

control层:业务模块流程控制,调用service层接口。

service层:业务操作实现类,调用dao层接口。

dao层:     数据业务处理,持久化操作

model层: pojo,OR maping,持久层
 
 
var myApp = angular.module('myApp',[],function($provide){


    // 自定义服务
  //自定义服务本身就是一个服务,这个服务的数据可以设置也可以返回,而service和factoyr只能返回数据。
$provide.provider('CustomService',function(){ this.$get = function(){ return { message : 'CustomService Message' } } }); $provide.provider('CustomService2',function(){ this.$get = function(){ return { message : 'CustomService2 Message' } } }); }); myApp.controller('firstController',function(CustomService,$scope,CustomService2){ $scope.name = '张三'; console.log(CustomService2); });

12. 多个控制器数据的共享两种方法:

$scope.data = $scope.$$prevSibling.data; 这样子必须是一个对象的值,在html页面的显示,必须是一个data.name这种形式,如果是data的话那么就不行。
<div ng-app="myApp">


        <div ng-controller="firstController">
            first.data <input type="text" ng-model="data.name" />
            first.Data <input type="text" ng-model="Data.message" />
            <p>
                first-name:{{data.name}}
            </p>
            <p>
                first-message:{{Data.message}}
            </p>
        </div>

        <div ng-controller="secondController">
            <p>
                second-name:{{data.name}}
            </p>
            <p>
                second-message:{{Data.message}}
            </p>
        </div>
    </div>
angular.module('myApp',[])

.factory('Data',function(){
    // this.$get = function(){}
    return {
        message : '共享的数据'
    };
})

.controller('firstController',function($scope,Data){
   $scope.data  = {
       name : '张三'
   };

   $scope.Data = Data;
})

.controller('secondController',function($scope,Data){
   $scope.data = $scope.$$prevSibling.data;

   $scope.Data = Data;
});

13. 过滤器:

angular.module('myApp',[])

.factory('Data',function(){

    return {
        message : '共享的数据'
    };
})

.controller('firstController',function($scope,Data,$filter){
   $scope.data = Data;

   $scope.today = new Date;

})
<div ng-controller="firstController">

        <!--123,456,789-->
        <p>{{123456789 | number}}</p>
        <!--12,345.679-->
        <p>{{12345.6789 | number:3}}</p>

        <!--$999,999.00-->
        <p>{{999999 | currency}}</p>
        <!--rmb999,999.00-->
        <p>{{999999 | currency:'rmb'}}</p>

        <p>
            default:{{ today }}
        </p>

        <p>
            medium: {{ today | date:'medium'}}
        </p>

        <p>
            short:{{ today | date:'short'}}
        </p>

        <p>
            fullDate:{{ today | date:'fullDate'}}
        </p>

        <p>
            longDate:{{ today | date:'longDate'}}
        </p>

        <p>
            mediumDate:{{ today | date:'mediumDate'}}
        </p>

        <p>

            shortDate:{{ today | date:'shortDate'}}
        </p>

        <p>
            mediumTime:{{ today | date:'mediumTime'}}
        </p>

        <p>
            shortTime:{{ today | date:'shortTime'}}
        </p>

        <p>
            year:
            {{today | date : 'y'}}
            {{today | date : 'yy'}}
            {{today | date : 'yyyy'}}
        </p>
        <p>
            month:
            {{today | date : 'M'}}
            {{today | date : 'MM'}}
            {{today | date : 'MMM'}}
            {{today | date : 'MMMM'}}
        </p>
        <p>
            day:
            {{today | date : 'd'}}
            Day in month {{today | date : 'dd'}}
            Day in week {{today | date : 'EEEE'}}
            {{today | date : 'EEE'}}
        </p>

        <p>
            hour:
            {{today | date : 'HH'}}
            {{today | date : 'H'}}
            {{today | date : 'hh'}}
            {{today | date : 'h'}}
        </p>

        <p>
            minute:
            {{today | date : 'mm'}}
            {{today | date : 'm'}}
        </p>

        <p>
            second:
            {{today | date : 'ss'}}
            {{today | date : 's'}}
            {{today | date : '.sss'}}
        </p>

        <p>
            {{today | date : 'y-MM-d H:m:s'}}
        </p>


</div>

14. 更多的选择器:

原始数据类型:

 <div ng-controller="firstController">

        <!--[1,2,3,4,5]-->
        <p>{{[1,2,3,4,5,6,7] | limitTo:5}}</p>

        <!--[3,4,5,6,7]-->
        <p>{{[1,2,3,4,5,6,7] | limitTo:-5}}</p>

        <!-- hello world -->
        <p>{{data.message | lowercase}}</p>
        <!-- HELLO WORLD -->
        <p>{{data.message | uppercase}}</p>

        <p>
            <!-- [{"name":"上海11212","py":"shanghai"}]-->
            {{ data.city | filter : '上海'}}
        </p>
        <p>
            <!-- []-->
            {{ data.city | filter : 'name'}}
        </p>

        <p>
            <!-- name":"上海11212","py":"shanghai"},{"name":"北京","py":"beijing"}-->
            {{ data.city | filter : {py:'g'} }}
        </p>

        <p>
            <!-- name":"上海11212","py":"shanghai"},{"name":"北京","py":"beijing"}-->
            {{ data.city | filter : checkName }}
        </p>

        <p>
            <!-- [{"name":"北京","py":"beijing"},{"name":"上海11212","py":"shanghai"},{"name":"四川","py":"sichuan"}] -->
            <!-- 默认顺序是 正序 asc a~z -->
            {{ data.city | orderBy : 'py'}}

            <!-- 默认顺序是 反序 desc z~a  -->
            <!-- [{"name":"四川","py":"sichuan"},{"name":"上海11212","py":"shanghai"},{"name":"北京","py":"beijing"}] -->
            {{ data.city | orderBy : '-py'}}
        </p>
angular.module('myApp',[])

.factory('Data',function(){

    return {
        message : 'Hello World',
        city : [
            {
                name:'上海11212',
                py : 'shanghai'
            },
            {
                name:'北京',
                py : 'beijing'
            },
            {
                name:'四川',
                py : 'sichuan'
            }
        ]
    };
})

.controller('firstController',function($scope,Data,$filter){
   $scope.data = Data;

   $scope.today = new Date;


   // 过滤器
   var number = $filter('number')(3000);

   var jsonString = $filter('json')($scope.data);

        console.log(jsonString);
        console.log($scope.data);

   $scope.checkName = function(obj){
        if(obj.py.indexOf('h') === -1)
            return false;
        return true;
   }

})

15. 自定义的过滤器

<div ng-controller="firstController">
        <ul>
            <li ng-repeat="user in data | filterAge">
                {{user.name}}
                {{user.age}}
                {{user.city}}
            </li>
        </ul>
    </div>
var myApp = angular.module('myApp', [], function ($filterProvider, $provide, $controllerProvider) {

    $provide.service('Data', function () {
        return [
            {
                name: '张三',
                age: '20',
                city: '上海'
            },
            {
                name: '李四',
                age: '30',
                city: '北京'
            }
        ];

    });

    $filterProvider.register('filterAge', function () {
        return function (obj) {
            var newObj = [];

            angular.forEach(obj, function (o) {
                if (o.age > 20) {
                    newObj.push(o);
                }
            });

            return newObj;

        }
    });


    $controllerProvider.register('firstController', function ($scope, Data) {
        $scope.data = Data;
    })



})

// module.filter
.filter('filterCity',function(){
    return function(obj){
        var newObj = [];

        angular.forEach(obj, function (o) {
            if (o.city === '上海') {
                newObj.push(o);
            }
        });

        return newObj;
    }
})

16.正确的使用controller

正确的使用controller
controller不应该尝试做太多的事情。它应该仅仅包含单个视图所需要的业务逻辑,保持controller的简单性,常见办法是抽出不属于controller的工作到service中,在controller通过依赖注入来使用service。
不要在controller中做以下的事情:
1.任何类型的DOM操作-controller应该仅仅包含业务逻辑,任何表现逻辑放到controller中,大大地影响了应用逻辑的可测试性。angular为了自动操作(更新)DOWM,提供的数据绑定。如果希望执行我们自定义的DOM操作,可以把表现逻辑抽取到directive中。
2.input formatting(输入格式化) 使用angular form controls代替。
3.output filtering(输出格式化过滤) 使用angular filters.
4.执行无状态或有状态的,controller共享的代码--使用angular services代替。
5. 实例化或者管理其他组件的生命周期。(例如创建一个服务实例)

17.代码的显示注入和隐式注入

var myApp = angular.module('myApp', [], ['$filterProvider', '$provide', '$controllerProvider', function (a, b, c) {
    console.log(a, b, c);
}])

.
factory('CustomService', ['$window', function (a) {
    console.log(a);
}])

// 隐示的依赖注入
    .controller('firstController', function ($scope, CustomService) {
        console.log(CustomService);
    })

// 显示的依赖注入
    .controller('secondController', ['$scope', '$filter', function (a, b) {
        console.log(b('json')([1, 2, 3, 4, 5]));
    }]);

function otherController(a) {
    console.log(a);
}

otherController.$inject = ['$scope'];

 18. 内置指令:

渲染指令:
ng-init
ng-bind
ng-repeat
$index 当前索引
$first 是否为头元素
$middle 是否为非头非尾元素
$lasth是否为尾元素

ng-include
ng-bing-template.

ng-bind
ng:bind
data-ng-bind
x-ng-bind
事件指令:
ng-change
ng-click
ng-dblclick
ng-mousedown
ng-mouseenter
ng-mouseleave
ng-mousemove
ng-mouseover
ng-mouseup
ng-submit
节点指令
ng-style
ng-class
ng-class-even
ng-class-odd

这里的red表示style中的类,而-even表示在偶数列会添加这个class.

ng-show
ng-hide
ng-switch
ng-src
ng-href
ng-if

==

.red{color:red;}
ng-class='{red:status}'

什么是指令:
可以利用指令来扩展HTML标签,增加声明式语法来实现想做的任何事,可以对应用有特殊意义的元素和属性来替换一般的HTML标签。
angular 也内置了非常堵偶的指令,ng-app ,ng-controller.

ngsrc 延迟加载。等angular加载完然后加载。这个属性。

<div ng-app="myApp">

    <div ng-controller="firstController">
        <p>{{1+1}}</p>
        <p ng-bind="1+1">2</p>
        <p ng-bind-template="{{1+1}}"></p>

        <!-- $scope.cityArr = ['上海','北京','杭州'] -->
        <ul ng-class="{red:status}" ng-init="cityArr = ['上海','北京','杭州']">
            <li ng-class-even="'偶数'" ng-class-odd="'奇数'" ng-repeat="city in cityArr" >
            <span>
                index:{{$index}}
            </span>
            <span>
                first:{{$first}}
            </span>
            <span>
                middle:{{$middle}}
            </span>
            <span>
                last :{{$last}}
            </span>
            <span>
                {{city}}
            </span>
            </li>
        </ul>



        <div ng-include="'other.html'">

        </div>

        <div ng-include src="'other.html'">

        </div>


















    </div>
</div>

var myApp = angular.module('myApp', [])

    .controller('firstController', function ($scope) {
        $scope.status = false;

        $scope.changeStatus = function (event) {
            // 通过element转换成 jquery对象
            angular.element(event.target).html('切换状态为:' + $scope.status);

            $scope.status = !$scope.status;

        }

        $scope.defaultStyle = {
            color: 'red',
            'margin-top': '50px'
        };

        $scope.src = 'http://www.angularjs.org/img/AngularJS-large.png';
    })

 $scope.changeStatus 这个会自动触发脏检查。

ng-style="{color:'red','margin-top':'50px'}" 后边这个注意加单引号。

 19. 自定义的指令:

自定义过滤器,factory,service.

templateUrl:加载模板所要使用的URl
可加载当前模板对应的text/ng-template script id

在使用chrome浏览器时,‘同源策略’会阻止chrome从file://中加载模板,并显示一个"Acces-Control-Allow-Origin"不允许源为null,可以把项目放在服务器上加载,命令为:chrome -allow-file-access-from-files

<div ng-app="myApp">

    <custom-tags>1212</custom-tags>

    <div class="custom-tags">

    </div>

    <div custom-tags>

    </div>

    <!-- directive:custom-tags -->
</div>
var myApp = angular.module('myApp', [], ['$compileProvider',function ($compileProvider) {

    $compileProvider.directive('customTags',function(){
        return {
            restrict:'ECAM',
            template:'<div>custom-tags-html</div>',
            replace:true  //这个属性对于E这种指令适用,可以提现出来
        }
    });

}])

//.directive('')  这是一种简单的写法

20.transclude:true保留原始数据

21.优先级(不是很重要) 


priority && terminal

priority 设置指令在模板中的执行顺序,顺序是相对于元素上其他执行而言,默认为0,从大到小的顺序依次执行。

设置优先级的情况比较少,象ng-repest,在遍历元素的过程中,需要angular先拷贝生成的模板元素,在应用其他指令,所以ng-repeat默认的priority是1000

terminal是否当前指令的权重为结束界限,如果这值设置为true,则节点中权重小于当前指令的其他指令不会被执行。相同权重的会执行。

22.

angularjs指令编译三阶段
1.标准浏览器API转化。
将html转化成dom,所以自定义的html标签必须符合html的格式。
2.angular compile
搜索匹配directive,按照priority排序,并执行directive上的compile方法。
3.angular link
执行directive上的link方法,进行scope绑定及事件绑定。

directive可以配置的指令:
priority
template
terminal
templateUrl
scope
replace: 是否替换当前html标签
controller
transclude
controllerAs
compile
require
link
restrict

23.

compile

compile:function(tElement,eAttrs,transclude)
compile函数用来对模板自身进行转换,仅仅在编译阶段运行一次,
compile中直接返回的函数是postLink,表示参数需要执行的函数,也可以返回一个对象里边包含preLink和postLink,
当定义compile参数时,将无视link参数,因为compile里返回的就是该指令需要执行的link函数。

24.

一个标签有两个指令的话,最好有一个template(多的情况不常用)
compile返回的就是link函数,所以说定义了compile就不用定义link.
compile的三个参数,(tElement,eAttrs,transclude)
eElement是angular内置的jquery的一个对象所以可以调用eElement.append的方法。
compile 和link的使用时机
compile想再dom渲染前对它进行变形,并且不需要scope参数想在所有相同directive里共享某些方法,这时应该定义compile里,性能会比较好,返回值就是link的function,这时就是共同使用的时候。
link 对特定的元素注册事件。
需要用到scope参数来实现dom元素的一些行为。
如果在你的directive的返回不是一个对象,而是返回的是一个匿名方法的话,这个方法就是postLink方法。或者说就是Link,link就是postLink。

link(scope,iElement,iAttrs, controller)
link参数代表的是compile返回的postLink
preLink表示在编译阶段之后,指令练级到子元素之前运行。
postLink 表示会在所有子元素指令都连接之后才运行
link函数负责在模型和视图之间进行动态关联,对于每个指令的每个实例,link函数都会执行一次。

25.

<div ng-app="myApp">

    <div ng-controller="firstController">
        <!--
            1. div 转换为dom结构
            2. 默认的优先级为0,哪个先定义哪个先使用

        -->
        <div ng-repeat="user in users" custom-tags="" custom-tags2>

        </div>

    </div>



</div>
var i = 0;

var myApp = angular.module('myApp', [])

    .directive('customTags',function(){
        return {
            restrict : 'ECAM',
            template : '<div>{{user.name}}</div>',
            replace : true,
            compile:function(tElement,tAttrs,transclude){

                tElement.append(angular.element('<div>{{user.name}}{{user.count}}</div>'));

                // 编译阶段...
                console.log('customTags compile 编译阶段...');

                return {
                    // 表示在编译阶段之后,指令连接到子元素之前运行
                    pre:function preLink(scope,iElement,iAttrs,controller){
                        console.log('customTags preLink..')
                    },
                    // 表示在所有子元素指令都连接之后才运行
                    post:function postLink(scope,iElement,iAttrs,controller){

                        iElement.on('click',function(){
                            scope.$apply(function(){
                                scope.user.name = 'click after';
                                scope.user.count = ++i;
                                // 进行一次 脏检查
                            });
                        })

                        console.log('customTags all child directive link..')
                    }
                }
                // 可以直接返回 postLink
                // return postLink function(){
                    // console.log('compile return fun');
                //}
            },
            // 此link表示的就是 postLink
            link:function(){
//                iElement.on('click',function(){
//                    scope.$apply(function(){
//                        scope.user.name = 'click after';
//                        scope.user.count = ++i;
//                        // 进行一次 脏检查
//                    });
//                })
            }
        }
    })

    .directive('customTags2',function(){
        return {
            restrict : 'ECAM',
            replace : true,
            compile:function(){
                // 编译阶段...
                console.log('customTags2 compile 编译阶段...');

                return {
                    // 表示在编译阶段之后,指令连接到子元素之前运行
                    pre:function preLink(){
                        console.log('customTags2 preLink..')
                    },
                    // 表示在所有子元素指令都连接之后才运行
                    post:function postLink(){
                        console.log('customTags2 all child directive link..')
                    }
                }

            }
        }
    })


    .directive('customTags3',function(){

       // return postLink;
       return function(){

       }
    })

    .controller('firstController', ['$scope', function ($scope) {
        $scope.users = [
            {
                id:10,
                name:'张三'
            },
            {
                id:20,
                name:'李四'
            }
        ];
    }]);

 26.

controller && controllerAds && require
controller他会暴露一个API,利用这个API可以在多个指令之间通过依赖注入进行通信
controller($scope,$element,$transclude)
controllerAs是给controller起个别名,方便使用
require可以将其他指令传递给自己
directiveName: 通过驼峰法的命名指定了控制器应该带有哪一条指令,默认会从同一个元素上的指令
^directiveName: 在父级朝找指令
?directiveName:表示指令是可选的,如果找不到,不需要抛出移除。

27.自定义指令:controllerAs 和link,可以使用上面的controller中的属性方法


angular.module('myApp', [])

    .directive('bookList', function () {
        return {
            restrict: 'ECAM',
            controller: function ($scope) {
                $scope.books = [
                    {
                        name: 'php'
                    },
                    {
                        name: 'javascript'
                    },
                    {
                        name: 'java'
                    }
                ];
                $scope.addBook = function(){

                }
                this.addBook = function(){
                    // ...
                }
            },
            controllerAs:'bookListController',//上边 controller的别名,下边的link或者compile可以使用
            template: '<ul><li ng-repeat="book in books">{{book.name}}</li></ul>',
            replace:true,
            link:function(scope,iEelement,iAttrs,bookListController){
          //上边的iEelement表示的是template中的内容和jquery中的一样,bookListController表示的上边的controllerAs,
          // 如果调用this.addBook,你直接用
bookListController.addBook,如果调$scope.addBook

          iEelement.on('click',bookListController.addBook) } } })
.controller('firstController', ['$scope', function ($scope) { // console.log($scope);
    //这里写的controller代码和上边的controller写是一样的效果
}]);

 28. require的用法

记住1.require后边的需要有一个引号。2.后面也需要一个引号。3.addBook方法是写在this上而不是写在scope上额。

angular.module('myApp', [])

    .directive('bookList', function () {
        return {
            restrict: 'ECAM',
            controller: function ($scope) {
                $scope.books = [
                    {
                        name: 'php'
                    },
                    {
                        name: 'javascript'
                    },
                    {
                        name: 'java'
                    }
                ];

                this.addBook = function(){

                    $scope.$apply(function(){
                        $scope.books.push({
                            name:'Angularjs'
                        })
                    });
                }
            },
            controllerAs:'bookListController',
            template: '<div><ul><li ng-repeat="book in books">{{book.name}}</li></ul><book-add></book-add></div>',
            replace:true

        }

    })

    .directive('bookAdd',function(){
        return {
            restrict:'ECAM',
            require:'^bookList',
            template:'<button type="button">添加</button>',
            replace:true,
            link:function(scope,iElement,iAttrs,bookListController){
                iElement.on('click',bookListController.addBook);
            }
        }
    })

    .controller('firstController', ['$scope', function ($scope) {
        // console.log($scope);


    }]);

这里我们可以看到require可以继承父类的controller方法,和属性。注意^bookList继承父类的。

http://raowensheng.com/2014/05/09/angularjs%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4%E7%9A%84require%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E/

require的作用是为了让父子指令或者兄弟指令的controller之间搭建一个桥梁
也就是说父指令里的controller里面的数据能分享给子指令的controller
其中子指令的link第四个参数的值是父指令的controller对象的作用域上下文
require有两个修饰符号:”?”、”^”
? : 如果require没有找到相应的指令避免报错,还能确保程序的正常执行
^ : 表示往父级查找

?^可以一起使用

29.scope  中@只能是值的绑定(简单数据类型的绑定)而&却可以是对象的绑定。注意对象html页面中的内容。如果是一个对象的话,我们需要先把父类的controller中的东西放到一个属性中,然后我们的子controller然后从html标签中的属性中取值,然后付给自己的属性。

scope(是针对子controller与父controller,但是我们需要注意的时候与reqiuire的区别是,require为了link中的第四个参数提供服务,而我们的scope则需要把属性绑定到html的属性上边)

这里我们可以看出来,如果books是object类型,而title是简单数据类型。

scope:为当前指令创建一个新的作用域,而不是使之继承父作用域 默认值记不清了 false继承父元素的作用域,和父共享一个作用域 true创建一个新的作用域,但是还是会继承父作用域的属性, object也是创建一个独立的scope但是也可以通过一些方式继承父类
object:参数 & 作用域把父作用域的属性包装成一个函数,从而以函数的方法会读写父作用域的属性。 注意这里的单项绑定是方法,下边的双向绑定确实一个属性。 =:作用域的属性与父作用域的属性进行双向绑定,任何一方的修改均影响到对方。 @: 只能读取父作用域里的值单向绑定。



<div ng-app="myApp">

    <div ng-controller="firstController">
        {{
            books
        }}
        <div book-list books="books" parent-books="books" parent-title="{{title}}"> <!--注意这里的title有{{}},简单数据类型绑定属性的时候有,而负责的数据类型则没有-->

        </div>

    </div>



</div>
angular.module('myApp', [])

    .directive('bookList', function () {
        return {
            restrict: 'ECAM',
            controller: function ($scope) {

                // &books
                // $scope.books = $scope.a();

                // =books;
                // $scope.books = $scope.b;
                // $scope.b.push({name:'nodejs'});

                console.log($scope.c);

            },
            // 创建一个有继承链的独立作用域
            // scope:true,

            // 当为对象的时候也会创建一个独立的作用域
            scope:{
                // 将父元素books封装成一个a函数
                // a:'&books'
                // 双向绑定 b = parentBooks属性对应的父作用域的表达式
                // b:'=parentBooks'

                // 使用简单数据类型的方法
                c:'@parentTitle'
            },
            controllerAs:'bookListController',
            template: '<div><ul><li ng-repeat="book in books">{{book.name}}</li></ul></div>',
            replace:true

        }

    })


    .controller('firstController', ['$scope', function ($scope) {
        console.log($scope);

        $scope.books = [
            {
                name: 'php'
            },
            {
                name: 'javascript'
            },
            {
                name: 'java'
            }
        ];

        $scope.title = '张三';

    }]);

 30.自定义   

嵌套的directive

  heading:@heading 可以简写成heading:@

<div ng-app="myApp">

    <div class="container">
        <div ng-controller="firstController">

            <kittencup-group>

                <kittencup-collapse ng-repeat="collapse in data" heading="{{collapse.title}}">
                    {{collapse.content}}
                </kittencup-collapse>

            </kittencup-group>

        </div>
    </div>



</div>
angular.module('myApp', [])
    // 数据
    .factory('Data', function () {
        return [
            {
                title: 'no1',
                content: 'no1-content'
            },
            {
                title: 'no2',
                content: 'no2-content'
            },
            {
                title: 'no3',
                content: 'no3-content'
            }
        ];
    })
    // 控制器
    .controller('firstController', ['$scope','Data',function ($scope,Data) {
        $scope.data = Data;
    }])

    .directive('kittencupGroup',function(){
        return {
            restrict:'E',
            replace:true,
            template:'<div class="panel-group" ng-transclude></div>',
            transclude:true,
            controllerAs:'kittencupGroupContrller',
            controller:function(){
                this.groups = [];

                this.closeOtherCollapse = function(nowScope){
                    angular.forEach(this.groups,function(scope){
                        if(scope !== nowScope){
                            scope.isOpen = false;
                        }
                    })
                }
            }
        }
    })

    .directive('kittencupCollapse',function(){
        return {
            restrict:'E',
            replace:true,
            require:'^kittencupGroup',
            templateUrl:'app/tmp/kittencupCollapse.html',
            scope:{
                heading:'@'
            },
            link:function(scope,element,attrs,kittencupGroupContrller){
                scope.isOpen = false;

                scope.changeOpen = function(){
                    scope.isOpen = !scope.isOpen;

                    kittencupGroupContrller.closeOtherCollapse(scope);
                }


                kittencupGroupContrller.groups.push(scope);
            },
            transclude:true
        }
    })

 一段angular指令自己平时练习的代码:

var ng = angular.module('box',[]);
ng.directive('aa',function(){
    return {
        restrictive:"ECAM",
        template:"<div><h2>this is our world {{data}}</h2><span  ng-transclude></span><bb data='data' title='{{title}}'></bb></div>",
        replace: true,
        transclude:true,
        controller:function($scope){
            $scope.data = {'key':"beautiful"}
            this.al = function(){
                alert(1234);
            }
            $scope.title = "title";
        },
        controllerAs:"aacontroller"
    }
})
ng.controller('first',function($scope){

});
ng.directive('bb',function(){
    return{
        restrictive:"ECAM",
        require:'^?aa',
        template:"<div>this is son directive {{data}}<input ng-model='data'/></div>",
        replace: true,
        controller:function($scope){
            $scope.data = $scope.a;
        },
        scope:{
            a:'@title'
        },
        link:function(scope,el,attr,aacontroller){
            //el.on('click',aacontroller.al);
        }
    }
});

 32.优先级,小于0的不执行

    <div ng-controller="firstController">
        <custom-tags>原始数据</custom-tags>

        <div custom-tags2 custom-tags3>

        </div>
    </div>
var myApp = angular.module('myApp', [])

    .directive('customTags', function () {
        return {
            restrict: 'ECAM',
            template:'<div>新数据 <span ng-transclude></span></div>',
            replace: true,
            transclude:true
        }
    })

    .directive('customTags2', function () {
        return {
            restrict: 'ECAM',
            template:'<div>2</div>',
            replace: true,
            priority:-1
        }
    })

    .directive('customTags3', function () {
        return {
            restrict: 'ECAM',
            template:'<div>3</div>',
            replace: true,
            priority: 0,
            // 小于0的directive 都不会执行
            terminal:true
        }
    })

    .controller('firstController', ['$scope', function ($scope) {
        $scope.name = '张三';
    }]);

 33. $scope相当于js对象继承的作用域链

34.

$provide方法都有快捷方法。
constant(name,object)
此方法首先运行,可以用它来声明整个应用范围内的常量,并且让它们在所有配置(config方法里)和实例(controller,service等)方法中都可用。
run(initializationFn)
想要在注入启动之后执行某些操作,而这些操作需要在页面对用户可用之前执行,可以使用此方法。
比如 加载远程的模板,需要在使用前放入缓存,或者在使用操作前判断用户是否登录,未登录可以先去登录页面。

angular.module('myApp',[],['$provide',function($provide){
        console.log('config');
    // $provide.factory
    // $provide.service

    // $provide.constant
    // $provide.value;

}])

.config(function(APIKEY){
    console.log(APIKEY);
        console.log('config');
})

    // 在config之后controller等其他服务之前。。
.run(function(){
    console.log('run');
})
    // 它只是可以注入任何方法
.constant('APIKEY','xxxx')

    // 只能注入controller...service factory
.value('vension','1.0.0')

.controller('firstController',['APIKEY','vension',function(APIKEY,vension){
    console.log(APIKEY);
        console.log(vension);
        console.log('controller');


}]);

 35. ng-show ng-hide ng-if  可以看:http://m.blog.csdn.net/article/details?id=44701769

angularJS中的ng-show、ng-hide、ng-if指令都可以用来控制dom元素的显示或隐藏。ng-show和ng-hide根据所给表达式的值来显示或隐藏HTML元素。当赋值给ng-show指令的值为false时元素会被隐藏,值为true时元素会显示。ng-hide功能类似,使用方式相反。元素的显示或隐藏是通过改变CSS的display属性值来实现的。

ng-if指令可以根据表达式的值在DOM中生成或移除一个元素。如果赋值给ng-if的表达式的值是false,那对应的元素将会从DOM中移除,否则生成一个新的元素插入DOM中。ng-if同no-show和ng-hide指令最本质的区别是,它不是通过CSS显示或隐藏DOM节点,而是删除或者新增结点。

36.服务返回一种方法的时候 http://www.runoob.com/try/try.php?filename=try_ng_services_filter2

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>

<div ng-app="myApp" ng-controller="myCtrl">
<p>在获取数组 [255, 251, 200] 值时使用过滤器:</p>

<ul>
  <li ng-repeat="x in counts">{{x | myFormat}}</li>
</ul>

<p>过滤器使用服务将10进制转换为16进制。</p>
</div>

<script>
var app = angular.module('myApp', []);
app.service('hexafy', function() {
    this.myFunc = function (x) {
        return x.toString(16);
    }
});
app.filter('myFormat',['hexafy', function(hexafy) {
    return function(x) {
        return hexafy.myFunc(x);
    };
}]);
app.controller('myCtrl', function($scope) {
    $scope.counts = [255, 251, 200];
});
</script>

</body>
</html>

 一下就是自己angular开发中,常遇到的一些问题

37.如果ul li中的li点击事件,本来想在Link中直接写一个类型ul.find('li').on的发现不行的,只能在页面的li中写一个方法,并且传入$event.利用

// 通过element转换成 jquery对象
angular.element(event.target).html('切换状态为:' + $scope.status);

38.$scope与this的区别。

(1)$scope会继承,但是this不会。

(2)在两个directive中,如果一个directive通过require引用另外一个directive中的东西,那么方法必须写在this中,如果写在$scope中则不行。

39.const run value这个方法的区别和联系。

config先执行,而run在config之后在controller等其他服务之前。。

const value

但是const只能注入方法中,

value// 只能注入controller...service factory

40.transclude:true实现的在于必须外边的controller是有定义的,如果外边的controller没有定义没效果.

41.AngularJS的学习 $on、$emit和$broadcast的使用

不过用的是$scope 发射和接受。

emit(name,data)向父control发射的。

而broadcast(name,data)是向子control发射的。 

原文地址:https://www.cnblogs.com/coding4/p/5549812.html