• angularJS学习笔记(二)


    前言

    首先,了解 一下ng的一些概念:

    • module 代码的组织单元,其它东西都是定义在具体的模块中的。
    • app 应用业务,需要多个模块的配合完成。
    • service 仅在数据层面实现特定业务功能的代码封装
    • controller 与DOM结构相关联的东西,即是一种业务封装概念,又体现了项目组织的层级结构
    • filter 改变数据的一种机制
    • directive 与DOM结构相关联,特定功能的封装形式

    上面的这些概念基本上就是ng的全部。每一部分都可以自由定义,使用时通过各种要素的相互配合来实现我们的业务需求。

    模块(module)

    每个ng应用都默认加载一个模块“ng”,该组件内部提供了一些常用的功能,我们可以直接使用使用他们,但这些功能可能没法完成我们的需求。因此ng另外还封装了一些其它模块,如ngAnimate、ngResource、ngRoute等,这些模块分别提供了一些各不相同的功能,注入进来我们就可以完全使用他们。我们也可以通过angular.module来创造、注册和加载模块。
    一个模块是 一组服务,指令,控制器,过滤函数和配置信息的集合。

    angular.module

    我们可以通过angular.module(name, [requires], [configFn])创造一个模块。模块名是绑定到模板中ngApp值,requires是需要依赖加载的模块,configFn是requires加载完成之后的初始化工作。返回一个带有其它方法和属性的模块。

    • provider() $provide.provider()的引用
    • factory() $provide.factory()的引用
    • service() $provide.service()的引用
    • value() $provide.value()的引用
    • constant() $provide.constant()的引用
    • decorator() $provide.decorator()的引用
    • animation() 自定义动画指令,$animateProvider.register()的引用
    • filter() 自定义过滤指令,$filterProvider.register()的引用
    • controller() 自定义控制器,$controllerProvider.register()的引用
    • directive() 自定义指令,$compileProvider.directive()的引用
    • config() 配置函数
    • run() 应用初始化
    • name 模块名
    • requires 依赖模块数组

    自定义服务$provide

    当你想在当前模块的控制器去引用另一模板的控制器功能时,可以自定义一个相关服务,然后在需要该服务的控制器中显示声明依赖该服务,这样就可在多个控制器中使用同一段逻辑代码。
    ng提供服务的过程涉及它的依赖注入机制。而provide使injector注册服务的方法。
    (1)provider方法:注册一个服务提供函数。
    该函数是一个构造函数,通过内部的$get属性来提供一个服务。

        var fn = function() {
            this.$get = function() {
                return "china";
            };
        }
    
        var myApp = angular.module('myApp', [], function($provide) {
            $provide.provider('test', fn);
        });
    
        myApp.controller('myCtrl', function($scope, test) {
            console.log(test);
        });

    上面是一种定义服务的方法,不常用,而且我也没搞懂,汗。。。
    (2)factory方法
    是provider方法的简写,相当于provider(name, {get:getFn}),直接把一个函数成是一个对象的get()provider(3)servicefactoryfactoryget方法即可,而service方法传入的是一个构造函数。即service返回的是一个对象,而factory方法 可以是一个数字或字符串。例如ng入门实例中的phonecat程序内部定义的ajax服务使用的就是factory方法,返回请求的json字符串。

    phonecatServices.factory('Phone', ['$resource',
      function($resource){
        return $resource('phones/:phoneId.json', {}, {
          query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
        });
      }]);

    (3)value方法
    相当于provider方法中的$get属性函数不需要参数且直接返回值的情况。provider方法中的test服务例子可直接简写:

    myApp.value('test',"China");

    传入值可以是字符串、数字、数组、对象和函数。
    (4)constant方法
    和value方法功能类似,即给一个服务名绑定一个常量,该常量可以是字符串、数字、数组、对象和函数。区别就是通过constant方法注册的服务能够被注入进module的配置中,而且不能被decorator方法修改。
    (5)decorator(name, decorator)方法
    中断一个服务的初始化,修改这个服务。参数name是已经定义但需要被修改的服务名。

    var myApp = angular.module('myApp', [])
                .config(['test', function(test) {
                            console.log(test.name);
                }])
                .constant('test',{name:"constant"})
                .value('valueTest',{name:'value'})
                .decorator('valueTest', function() {
                    return {
                        name: 'decoration'
                    };
                })
                .controller('myCtrl', ['valueTest', function(valueTest) {
                    console.log(valueTest.name);
                }]);

    自定义指令directive

    通过前面的学习,我们慢慢发现,ng中的功能都是通过在相应模板中绑定功能的指令来完成。如

    <div ng-controller="Controller">
      Hello <input ng-model='name'> <hr/>
      <span ng-bind="name"></span> <br/>
      <span ng:bind="name"></span> <br/>
      <span ng_bind="name"></span> <br/>
      <span data-ng-bind="name"></span> <br/>
      <span x-ng-bind="name"></span> <br/>
    </div>

    而ng的指令绑定方式有element names,attributes,comment,class names

    <my-dir></my-dir>
    <span my-dir="exp"></span>
    <!-- directive: my-dir exp -->
    <span class="my-dir: exp;"></span>

    ng不仅提供了一些简单的指令供我们使用,同时也允许我们自定义指令。通过模块中的directiveAPI可以定义指令,而最简单的定义指令方式是直接返回一个函数:

    angular.module('myApp', [])
    .directive('myLink', function($interval, dateFilter) {
                        return function link(scope, element, attrs) {
                            var format,
                                    timeoutId;
    
                            function updateTime() {
                                element.text(dateFilter(new Date(), format));
                            }
    
                            scope.$watch(attrs.myLink, function(value) {
                                format = value;
                                updateTime();
                            });
    
                            // 注册$destoty事件,防止内存泄露问题
                            // 当编译的DOM被销毁时触发
                            element.on('$destroy', function() {
                                $interval.cancel(timeoutId);
                            });
    
                            // start the UI update process; save the timeoutId for canceling
                            timeoutId = $interval(function() {
                                updateTime(); // update DOM
                            }, 1000);
                        }
                    });

    指令名必须是驼峰格式的命名,而直接直接返回函数的形式等同于复杂指令定义方式中的返回link函数

    angular.module('myApp', [])
                    .directive('myCurrentTime', function($interval, dateFilter) {
    
                        function link(scope, element, attrs) {
                            var format,
                                    timeoutId;
    
                            function updateTime() {
                                element.text(dateFilter(new Date(), format));
                            }
    
                            scope.$watch(attrs.myCurrentTime, function(value) {
                                format = value;
                                updateTime();
                            });
    
                            // 注册$destoty事件,防止内存泄露问题
                            // 当编译的DOM被销毁时触发
                            element.on('$destroy', function() {
                                $interval.cancel(timeoutId);
                            });
    
                            // start the UI update process; save the timeoutId for canceling
                            timeoutId = $interval(function() {
                                updateTime(); // update DOM
                            }, 1000);
                        }
    
                        return {
                            link: link
                        };
                    });

    即定义指令的复杂形式是返回一个对象,对象含有以下几种可能用到的属性:

    • multiElement
    • priority
    • terminal
    • scope
    • controller
    • require
    • restrict
    • templateNamespace
    • template
    • templateUrl
    • replace(ng2.0中会被移除)
    • transclude
    • compile
    • link

    在定义复杂的指令形式之前,我们必须了解一下ng对指令的解析和执行过程:

    • 浏览器将得到的HTML字符串内容解析成DOM结构
    • ng引入,将DOM结构扔给$compile函数处理:
      • $compile遍历DOM匹配指令,将指令添加进匹配DOM元素的指令列表中。一个元素可以匹配多个指令。
      • 关联DOM的多个指令按权重排列
      • 指令指令中的compile函数(可修改DOM结构),返回link函数
      • 得带的所有link函数组成一个列表作为$compile函数的返回
    • 指令link函数(连接模板的scope)

    下面是一个复杂指令的定义方式:

    myApp.directive('directiveName', function factory(injectables) {
      var directiveDefinitionObject = {
        priority: 0,
        template: '<div></div>', // or // function(tElement, tAttrs) { ... },
        // or
        // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
        transclude: false,
        restrict: 'A',
        templateNamespace: 'html',
        scope: false,
        controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
        controllerAs: 'stringIdentifier',
        bindToController: false,
        require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
        compile: function compile(tElement, tAttrs, transclude) {
          return {
            pre: function preLink(scope, iElement, iAttrs, controller) { ... },
            post: function postLink(scope, iElement, iAttrs, controller) { ... }
          }
          // or
          // return function postLink( ... ) { ... }
        },
        // or
        // link: {
        //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
        //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
        // }
        // or
        // link: function postLink( ... ) { ... }
      };
      return directiveDefinitionObject;
    });
    • multiElement
      当该属性设为true时,HTML编译器会搜集在directive-name-enddirective-name-end之间DOM节点,当作一个集合 作为directive elements使用
    • priority
      设置指令的权重,默认为0.当一个DOM元素匹配多个指令时,根据权重的大小来执行相应的指令。
    • terminal
      设为true时,当前指令是指令集中的最后 一个会被执行的指令。任何权重值小于当前指令权重的指令都不会被指令。
    • scope
      true创建一个新的作用域。{ }创建一个 隔离的scope,可引用相关节点属性:”@attr”引用节点属性,”=attr”把节点属性值引用成scope属性值,“&attr”把节点属性值包装成函数
    • controller
      为指令定义一个controller构造函数,允许指令之间彼此通信。function($scope,$element,$attrs,$transclude){}
    • require
      引用其它指令的控制器作为link函数的第四个参数。跟一个字符串或者字符串数组。
      • (no prefix) 在当前元素内查找控制器
      • ?努力查找或者null
      • ^ 在当前元素和父元素内查找
      • ^^ 在元素的父元素内查找
    • restrict
      决定指令的应用方式,默认EA
      • E 节点名“`
      • A 属性名
      • C 类值
      • M 注释
    • templateNamespace
      模板中的标记。html、svg、math
    • template
      模板内容
    • templateUrl
      模板地址取代模板内容
    • replace
      决定模板内容取代的位置,默认false。true:模板取代指令元素.false:模板取代指令元素的内容。
    • transclude
      true或者element
    • compile
      function compile(tElement,tAttrs, transclude) 装换模板内容。
    • link
      仅当compile属性没有定义时,才会使用。funciton link(scope,iElement,iAttrs,controller,transcludeFn)
      ps:暂时也就只能理解这么多。。。
      可以看官方的一个例子:
    <!doctype html>
    <html lang="en" ng-app="myApp">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="../js/angular.min.js"></script>
    </head>
    <body>
        <my-tabs>
            <my-pane title="Hello">
                <h4>Hello1</h4>
                <p>Lorem ipsum dolor sit amet</p>
            </my-pane>
            <my-pane title="World">
                <h4>World1</h4>
                <em>Mauris elementum elementum enim at suscipit.</em>
                <p><a href ng-click="i = i + 1">counter: {{i || 0}}</a></p>
            </my-pane>
        </my-tabs>
    
        <script>
            angular.module('myApp', [])
                    .directive('myTabs', function() {
                        return {
                            restrict: 'E',
                            transclude: true,
                            scope: {},
                            controller: function($scope) {
                                var panes = $scope.panes = [];
    
                                $scope.select = function(pane) {
                                    angular.forEach(panes, function(pane) {
                                        pane.selected = false;
                                    });
                                    pane.selected = true;
                                };
    
                                this.addPane = function(pane) {
                                    if (panes.length === 0) {
                                        $scope.select(pane);
                                    }
                                    panes.push(pane);
                                };
                            },
                            templateUrl: 'my-tabs.html'
                        };
                    })
                    .directive('myPane', function() {
                        return {
                            require: '^myTabs',
                            restrict: 'E',
                            transclude: true,
                            scope: {
                                title: '@'
                            },
                            link: function(scope, element, attrs, tabsCtrl) {
                                tabsCtrl.addPane(scope);
                            },
                            templateUrl: 'my-pane.html'
                        };
                    });
        </script>
    </body>
    </html>

    my-tabs.html

    <div class="tabbable">
        <ul class="nav nav-tabs">
            <li ng-repeat="pane in panes" ng-class="{active:pane.selected}">
                <a href="" ng-click="select(pane)">{{pane.title}}</a>
            </li>
        </ul>
        <div ng-transclude></div>
    </div>

    my-pane.html

    <div class="tabbable">
        <ul class="nav nav-tabs">
            <li ng-repeat="pane in panes" ng-class="{active:pane.selected}">
                <a href="" ng-click="select(pane)">{{pane.title}}</a>
            </li>
        </ul>
        <div ng-transclude></div>
    </div>

    路由ngRoute

    ngRoute模块提供了关于路由方面的一些服务和指令。根据URL中的hash部分发生变化时触发在路由服务中预定义的业务逻辑,例如phonecat应用程序中使用到的路由服务:

    phonecatApp.config(['$routeProvider',
      function($routeProvider) {
        $routeProvider.
          when('/phones', {
            templateUrl: 'partials/phone-list.html',
            controller: 'PhoneListCtrl'
          }).
          when('/phones/:phoneId', {
            templateUrl: 'partials/phone-detail.html',
            controller: 'PhoneDetailCtrl'
          }).
          otherwise({
            redirectTo: '/phones'
          });
      }]);

    运行时会发现这些url匹配的都是url的hash部分,eg: http://localhost:8000/app/#/phones

    加载路由

    由于ng将路由部分单独作为一个模块服务定义,因此在使用相关路由服务之前,需加载引用:

    <script src="../js/angular.min.js"></script>
    <script src="../js/angular-route.min.js"></script>
    
    angular.module('myapp',['ngRoute']);

    使用

    要使用路由功能,需要在相应的模块初始化阶段通过引用routeProvider1routeProvider.when(path, route)
    path参数是将要匹配的路径,可以在路径中定义需要获得的参数,例如“/phones/:phoneId”可以匹配”phones/111”,其中phoneId就是变量,即对应变量前使用”:”匹配。
    route是对应路由匹配成功后进行的业务处理对象。包含属性:

    • controller 控制器
    • template 模板内容
    • templateUrl 模板路由
    • resolve 可选需要注入进controller中的依赖,是一个对象,对象的key是依赖注入的名,value是string或function
    • redirectTo 重定义到新路由

    (2)$routeProvider.otherwise(params)
    当以上定义的路由都没有匹配时使用。
    (3)ngView
    HTML模板指令,当相关路由匹配成功时对应的模板内容加载区域。<div ng-view></div>
    (4)routeParamsrouteParams对象才更新。但我们可使用route.current.params访(5)route 控制路由匹配的controllers和views,监控$location.url的变化然后匹配。

    • reload() 重新加载
    • updateParams(newParams) 使用新的路由参数更新当前路由
    • $routeChangesStart 路由改变前的事件
    • $routeChangeSuccess 路由成功改变事件
    • $routeChangeError 路由改变错误事件
    • current 应用当前路由的定义
    • routes 当前路由的默认对象
    <div ng-controller="MainController">
      Choose:
      <a href="Book/Moby">Moby</a> |
      <a href="Book/Moby/ch/1">Moby: Ch1</a> |
      <a href="Book/Gatsby">Gatsby</a> |
      <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
      <a href="Book/Scarlet">Scarlet Letter</a><br/>
    
      <div ng-view></div>
    
      <hr />
    
      <pre>$location.path() = {{$location.path()}}</pre>
      <pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
      <pre>$route.current.params = {{$route.current.params}}</pre>
      <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
      <pre>$routeParams = {{$routeParams}}</pre>
    </div>

    另外,$location是ng中默认提供的一个服务:
    - absUrl() 当前绝对路径
    - url([url]) 更改或获取路径
    - protocol() 当前路径协议
    - host()
    - port()
    - path([path])
    - search(search,[paramValue])
    - hash([hash])

    ngResource

    ngResource与ngRoute一样,单独的模板,需要提前加载。
    ngResource是AJAX服务的一种更高级,抽象的服务,底层仍然调用AJAX服务,该模块是通过$resource提供了和服务端RESTful接口交互支持的服务。

    $resource(url, [paramDefaults], [actions], options)

    一个创建可以和RESTful服务端交互的resource对象的工厂函数。

    • url 可以含有参数
    • paramDefaults 默认的url参数值,可以在actions里面被重写
    • actions 自定义的方法列表,扩展默认的方法
    • options 用户自定义设置
      • stripTrailingSlashes 默认为true,省略任何计算的URL后面的斜杠。
    phonecatServices.factory('Phone', ['$resource',
      function($resource){
        return $resource('phones/:phoneId.json', {}, {
          query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
        });
      }]);

    ng还提供了一些其它的模块和服务,总之ng在真的很强大,它打破了我们以往按照jQuery+CSS+HTML开发动态网站的思维,将我们带入了另一个全新的世界。


    参考

    http://www.zouyesheng.com/angular.html

    http://www.cnblogs.com/lcllao/archive/2012/10/18/2728787.html

  • 相关阅读:
    多态的作用-游戏编程展示------新标准c++程序设计
    类与类之间的两种关系------新标准c++程序设计
    复制构造函数被调用的三种情况------新标准c++程序设计
    Dynamics CRM2011 隐藏sub-grid 新建项和添加现有项按钮
    Dynamics CRM Odata QueryUrl中的SetName问题
    Dynamics CRM 修改自定义实体名字及属性前缀(架构名称)
    Dynamics CRM 请求服务时报access is denied错误
    Dynamics CRM2011中通过JS脚本方式显示和隐藏ribbon中的自定义按钮
    (转载)表服务器无法打开与报表服务器数据库的连接。所有请求和处理都要求与数据库建立连接。
    如何将sqlserver的windows验证模式改为SQL Server 和 Windows 混合身份验证模式
  • 原文地址:https://www.cnblogs.com/qingguo/p/5686289.html
Copyright © 2020-2023  润新知