• AngularJS 1.0 学习笔记


    软件工程

    软件设计原则

    • 避免重复原则(DRY-不要重复代码)

      • 编程的最基本原则是避免重复。
      • 在程序代码中总会有很多结构体,如循环、函数、类等等。
      • 一旦你重复某个语句或概念,就会很容易形成一个抽象体
      • 造价公式:单位工资 X 3倍 X 开发人数 X 天数
    • 抽象原则

      • 程序代码中每一个重要的功能,只能出现在源代码的一个位置
    • 简单原则(KISS-代码越简单越好)

      • 简单的代码占用时间少,漏洞少,并且易于修改
    • 避免创建不要的代码(YAGNI-不要写不需要的代码)

      • 除非你需要它,否则别创建新功能
    • 尽可能做可运行的最简单的事

      • 在编程中,一定要保持简单原则
      • 作为一名程序员不断的反思“如何在工作中做到简化呢?”
      • 这将有助于在设计中保持简单的路径。
    • 开闭原则(OCP-对拓展持“开放”态度,对修改持“封闭”态度)

      • 你所编写的软件实体(类、模块、函数等)最好是开放的,这样别人可以拓展开发
      • 对于你的代码,得限定别人不得修改
      • 别人可以基于你的代码进行拓展编写,但却不能修改你的代码
    • 最小惊讶原则

      • 最小惊讶原则通常是在用户界面方面引用,但同样适用于编写的代码
      • 代码应该尽可能减少让读者惊喜
      • 你编写的代码只需按照项目的要求来编写。
      • 其他华丽的功能就不必了,以免弄巧成拙
    • 单一责任原则(SRP)

      • 某个代码的功能,应该保证只有单一的明确的执行任务
    • 高内聚低耦合原则(HCLC)

      • 代码的任何一个部分应该减少对其他区域代码的依赖关系
      • 尽量不要使用共享参数
      • 相似的功能代码应尽量放在一个部分
      • 低耦合往往是完美结构系统和优秀设计的标志
    • 最少知识法则/迪米特法则

      • 让一个对象知道的越少越好
      • 该代码只和与其有直接关系的部分连接

    软件设计模式

    • 概念

      • 是前人的优秀的项目经验的总结,在某种特定的场景下的特定的代码设计方法
      • C/C++/Java/PHP/JS的设计模式是通用的
      • 总共有23+种设计模式
    • MVC模式

      • Model
        • Model 模型 Modal 模态框 Module 模块
        • 模型,指业务数据,Web项目中由JS中由变量(数字、字符串、对象、数组等)来担当
      • View
        • 视图,指业务数据在用户面前的呈现,Web项目中由HTML(增强型)来担当
      • Controller
        • 控制器,负责获取、删除、更新模型数据,Web项目中由JS中的function来担当

    AngularJS概述

    Angular概述

    • 概述
      • AngularJS是一个纯JS框架,基于jQuery对DOM操作做了进一步的封装
      • 使用MVC操作代替所有的DOM操作
      • 用于以数据操作为主的SPA(单页应用)应用

    Angular四大特性

    • AngularJS的四大特性:
      • 采用MVC模式,页面中再也无需出现DOM操作
        • Model: 模型,即业务数据,ng中由保存在特定范围内的变量来担当
        • View: 视图,负责数据的呈现,ng中由HTML(增强型)来担当
        • Controller: 控制器,负责操作(CDUD)数据,ng中由模块中的function来担当

    双向数据绑定

    • 方向一:把Model数据绑定到View上,此后不论何时只要Model发生了改变,则View中的呈现会立即随之改变!

      • 实现方法:都实现了方向一的绑定
        • {{}}
        • ngBind
        • ngRepeat
        • ngIf
        • ngSrc
    • 方向二:把View(表单控件)中修改绑定到Model上,此后不论任何时候,只要View中的数据一修改,Model中的数据会自动随之修改

      • 实现方法:只有ngModel指令
      • 可以使用$scope.$watch('模型变量名', fn)监视一个模型变量值的改变
      • 单行文本输入域、多行文本输入域、下拉框、单选按钮控件默认会把自己的value属性值绑定到一个Model变量
      • 复选框会把一个true/false值绑定到一个Model变量
      • input
      • textarea
      • select 与value相关
      • input[radio] 与value相关
      • input[checkbox]
    // 方向一
    angular.module('myModule11', ['ng']).
      controller('c11', function($scope, $interval){
        $scope.age = 10;
        $interval(function(){
          $scope.age++;
        }, 1000);
        $scope.sum = 0;
        $scope.sumer = function(){
          $scope.sum++;
        }
      })
    
    // 轮播
    angular.module('M12', ['ng']).
      controller('C12', function($scope, $interval){
        $scope.num = 1;
        $scope.pro = function(){
          $interval.cancel(t);
          $scope.num > 1 ? $scope.num-- : $scope.num = 5;                
        }
        $scope.next = function(){
          $interval.cancel(t);
          $scope.num < 5 ? $scope.num++ : $scope.num = 1;
        }
        let t = $interval(function(){
          $scope.num < 5 ? $scope.num++ : $scope.num = 1;
        }, 1000)
      })
    
    // 进度条
    angular.module('M13', ['ng']).
      controller('C13', function($scope, $interval){
        let percentage = 0;
        $scope.myStyle = { '0%'};
        let t = $interval(function(){
          percentage += 10;
          $scope.myStyle.width = percentage + "%"
          percentage < 100 ? percentage : $interval.cancel(t);
          // if(percentage>=100){
          //     $interval.cancel(t);
          //     console.log('已完成');
          // }
        }, 50)
      })
    
    <!-- 方向二 -->
    <!DOCTYPE html>
    <html ng-app="M14">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
    <section class="container" ng-controller="C14">
        <input ng-model="userName">
        <p ng-bind="userName"></p>
    </section>
    <script src="js/angular.js"></script>
    <script>
    angular.module('M14', ['ng']).
        controller('C14', function($scope, $interval){
            // 监视一个Model数据的改变
            $scope.$watch('userName', function(){
                console.log($scope.userName);
            })
        })
    </script>
    </body>
    </html>
    
    <!-- 简易版购物车计算器 -->
    <!DOCTYPE html>
    <html lang="en" ng-app="M15">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
    <section class="container" ng-controller="C15">
        <p>简易版购物车计算器</p>
        <p>单价:<input type='text' ng-model="price"> 数量:<input type='number' ng-model="count"> 小计:<span ng-bind='total'>0</span></p>
    </section>
    <script src="js/angular.js"></script>
    <script>
    angular.module('M15', ['ng']).
        controller('C15', function($scope, $interval){
            $scope.$watch('price', function(){
                $scope.total = parseInt($scope.price) * parseInt($scope.count);
            })
            $scope.$watch('count', function(){
                $scope.total = parseInt($scope.price) * parseInt($scope.count);
            })
        })
    </script>
    </body>
    </html>
    
    <!--同意条款 ngIf方式 操作DOM-->
    <section class="container" ng-controller="C16">
       <input type="checkbox" ng-model='agree'><span>我同意本站的使用条款</span><br>
       <input class='btn btn-success' type="button" value="提交注册信息" ng-if="agree">
    </section>
    <script>
    angular.module('M16', ['ng']).
        controller('C16', function($scope){
            $scope.agree = true;
        })
    </script>
    
    <!--同意条款 ngShow方式 操作display-->
    <section class="container" ng-controller="C16">
       <input type="checkbox" ng-model='agree'><span>我同意本站的使用条款</span><br>
       <input class='btn btn-success' type="button" value="提交注册信息" ng-show="agree">
    </section>
    <script>
    angular.module('M16', ['ng']).
        controller('C16', function($scope){
            $scope.agree = true;
        })
    </script>
    
    <!--同意条款 disabled方式 -->
    <section class="container" ng-controller="C16">
       <input type="checkbox" ng-model='agree'><span>我同意本站的使用条款</span><br>
       <input class='btn btn-success' type="button" value="提交注册信息" ng-disabled="!agree">
    </section>
    <script>
    angular.module('M16', ['ng']).
        controller('C16', function($scope){
            $scope.agree = true;
        })
    </script>
    
    <!-- 头像选择 -->
    <section class="container" ng-controller="C17">
      <select ng-model="portrait">
        <option value="1.jpg">小萝莉</option>
        <option value="2.jpg">小鲜肉</option>
        <option value="3.jpg">萌大叔</option>
        <option value="4.jpg">胖大婶</option>
      </select>
      <img ng-src="img/{{portrait}}" style=" 120px;">
      <p ng-bind="portrait"></p>
    </section>
    <script>
    angular.module('M17', ['ng']).
      controller('C17', function($scope, $interval){
        $scope.portrait = '1.jpg';
      })
    </script>
    
    <!--全选/取消全选-->
    <section class="container" ng-controller="C18">
      <table class='table table-bordered'>
        <thead>
          <tr>
            <th>选择</th>
            <th>姓名</th>
            <th>工资</th>
            <th>操作</th>
          </tr>
        </thead>
          <tbody>
            <tr ng-repeat="item in employee">
              <td><input type='checkbox' ng-checked="selectAll"></td>
              <td ng-bind="item.name">Sunny</td>
              <td ng-bind="item.salary">8500</td>
              <td><button class='btn btn-danger'>删除</button></td>
            </tr>
          </tbody>
      </table>
      <input type="checkbox" ng-model="selectAll">
      <span ng-hide='selectAll'>全选</span>
      <span ng-show='selectAll'>取消全选</span>
    </section>
    <script src="js/jquery-1.11.3.js"></script>
    <script src="js/angular.js"></script>
    <script>
    angular.module('M18', ['ng']).
      controller('C18', function($scope){
        $scope.employee = [{
          name: 'Sunny',
          salary: 7200
        },{
          name: 'Tom',
          salary: 6400
        },{
          name: 'Jerry',
          salary: 7800
        }]
        $scope.selectAll = false;
      })
    </script>
    

    依赖注入

    • 依赖注入概念
      • 依赖(Dependency):Driver对象的创建和运行必须一个car对象,称为Drive对象,“依赖于”Car对象
    function(car){
      car.start();
      car.run();
      car.stop();
    }
    
    • 依赖对象的解决方法:
      • 主动创建
      • 被动注入(inject)
        • 一般由特定框架来创建Driver对象,发现其依赖于一个Car对象,框架自动创建被依赖的Car对象 —— 称为“依赖注入”
    // 主动创建
    var c1 = new Car();  // 创建被依赖的对象
    var d1 = new Driver(c1); // 使用被依赖的对象
    
    // 依赖注入
    module.controller('控制器名', function(){$scope, $http})
    
    • 控制器的创建

      • 控制器对象不能受手动创建
      • 必须由框架来创建
        • <div ng-controller="C30"></div>
      • 注意:
        • 控制器对象的构造函数是由AngularJS来调用的,不能手动调用
        • Angular会根据控制器对象的构造函数的形参名来创建依赖的参数对象(形参名不能随意指定!)
        • 若控制器对象未声明形参,则Angular不会传递任何实参进来
        • 控制器对象的形参名必须是Angular可识别的,但是数量和顺序没有限制
        • AngularJS会根据每一个形参的名称来查找创建被依赖的对象,并自动注入进来
    • JS压缩功能的解决方案

      • 若使用了JS的压缩功能,会自动将依赖对象的形参进行精简混淆,则Angular就无法再根据形参名实现依赖注入了
      • 在数组内,形参的数量与顺序一一对应
    angular.module('M30', ['ng']).
        controller('C30', ['$scope', '$http', '$animate' ,function(a, b, c){
            console.log('c3控制器对象的实例开始创建...');
            console.log(arguments);
            console.log('c3控制器对象的实例创建完成!');
        }])
    

    模块化(Module)设计

    • 设计原则

      • 模块化设计体现着“高内聚低耦合”设计原则
      • 项目中,可以根据功能的不同,将不同的组件放置在不同的模块中
        • 用户管理相关内容全部放在userModule
        • 商品相关的内容全部放在productModule
    • AngularJS中有两种模块

      • AngularJS官方提供的模块
        • ng ngRoute ngAnimate ngTouch ...
      • 用户自定义的模块
        • userModule productModule orderModule ...
      • 一个AngularJS的模块中可以包含哪些组件?
        • controller组件:用于维护Model模型数据(自定义模块)
        • directive组件:用于View中输出/绑定Model数据
        • service组件:用于在不同的控制器中提供某种函数服务
        • filter组件:用于对View中输出的数据进行格式化
        • provider组件:
        • function组件:
        • object组件:
        • type组件:
    • Angular模块中的常用组件之filter

      • filter:过滤器,用于Model数据在View中呈现时进行某种格式的筛选/过滤/格式化
      • 在View中使用过滤器时,需要借助于管道 |
      • ng模块中提供的过滤器
        • lowercase 把数据格式化为小写
          • 语法:{{表达式 | lowercase}}
        • uppercase 把数据格式化为大写
          • 语法:{{表达式 | uppercase}}
        • number 把数字型数据格式化为三位一个逗号的字符串,同时指定小数点位数
          • 语法:{{表达式 | number:小数位数}}
        • currency 把数字型数据格式化为货币格式的字符串,同时指定货币符号
          • 语法:{{表达式 | currency:'货币符号'}}
        • date 把数据/Date型数据格式化为特定日期时间格式的字符串
          • 真实项目中,往往不使用Date类型表示日期时间
          • 而使用长整型的数字来代替
          • 所有的编程语言/数据库系统都支持长整型数字,都可以把数字和日期时间随意的转换
          • 语法: {{表达式 | date:'日期时间格式'}}
    <section class="container" ng-controller="C31">
        <p ng-bind="ename"></p>
        <p ng-bind="ename.toUpperCase()"></p>
        <!--过滤器在使用时要借助管道-->
        <p ng-bind="ename | uppercase"></p>
        <p ng-bind="ename | lowercase | uppercase"></p>
    </section>
    <script>
    angular.module('M31', ['ng']).
        controller('C31', function($scope){
            $scope.ename = 'Tom';
        })
    </script>
    
    <!--服务器中运行-->
    <!DOCTYPE html>
    <html lang="en" ng-app="M32">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <link rel="stylesheet" href="css/bootstrap.css">
    </head>
    <body>
    <!--
        点击一个按钮“加载员工数据”,
        向服务器发起异步的AJAX请求,
        获取服务器的一段JSON数据;
        加载完数据后,按钮即禁用/消失
    -->
    <section class="container" ng-controller="C32">
      <button class='btn btn-success' ng-click='loadData()' ng-disabled='agree'>加载员工数据...</button>
      <hr>
      <table class="table">
        <thead>
          <tr>
            <th>序号</th>
            <th>姓名</th>
            <th>工资</th>
            <th>入职日期</th>
          </tr>
        </thead>
        <tbody>
          <tr ng-repeat='(key, item) in employee'>
            <td ng-bind='key'></td>
            <td ng-bind='item.ename | uppercase'></td>
            <td ng-bind='item.salary | currency:"¥ "'></td>
            <td ng-bind='item.hiredate | date:"yyyy年mm月dd日"'></td>
          </tr>
        </tbody>
      </table>  
    </section>
    <script src="js/jquery-1.11.3.js"></script>
    <script src="js/angular.js"></script>
    <script>
    angular.module('M32', ['ng']).
      controller('C32', function($scope, $http){
        $scope.loadData = function(){
          $scope.agree = true;
          $http.get('data/5.json').success(function(data){
            $scope.employee = data;
          })
        }
      })
    </script>
    </body>
    </html>
    
    // 5.json
    [{
        "ename": "Tom",
        "salary": 12000,
        "hiredate": 1601968856625
    },{
        "ename": "Jerry",
        "salary": 15000,
        "hiredate": 1604588394625
    },{
        "ename": "John",
        "salary": 9000,
        "hiredate": 1601969624625
    },{
        "ename": "Sunny",
        "salary": 13000,
        "hiredate": 1601884394625
    },{
        "ename": "Mary",
        "salary": 11000,
        "hiredate": 1601968394815
    }
    

    AngularJS数据绑定的原理&最大的缺陷

    • 绑定原理

      • 每一次方向1的绑定都会在$digest队列中生成一个执行DOM操作的函数
      • 若一个ngApp中有N次数据绑定就会生成N个这样的函数
      • 只要某一个Model数据发生了值的改变,立即会自动执行$digest队列的每一个函数,进行View的更新
      • 队列的数据轮询
    • setInterval()和$interval()的不同

      • window.setInterval()只会执行指定的任务,即使修改了Model数据也不会自动轮询$digest队列
      • $interval()的执行体中会在最后自动执行:$scope.$digest()/$scope.$apply()
        • 轮询$digest队列,执行其中的每一个DOM操作函数
        • 简言之,$interval = setInterval()+$scope().$digest()
    <!DOCTYPE html>
    <html lang="en" ng-app="M20">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <link rel="stylesheet" href="css/bootstrap.css">
    </head>
    <body>
    <section class="container" ng-controller="C20">
        <p>完整版购物车计算器</p>
        <button class='btn btn-success' ng-click='addProduct()'>添加商品</button>
        <hr/>
        <div>
            <p ng-repeat="(index, item) in cart" class='alert alert-success'>
                单价:<span ng-bind='item.price'></span>
                数量:<input type='number' ng-model="item.count">
                小计:<span ng-bind='item.price*item.count'>0</span>
            </p>
        </div>
        <div>总计:<span ng-bind='getTotal()'></span></div>
    </section>
    <script src="js/jquery-1.11.3.js"></script>
    <script src="js/angular.js"></script>
    <script>
        angular.module('M20', ['ng']).
            controller('C20', function($scope, $interval){   
                $scope.cart = []
                $scope.cart.push({price: 10.5, count: 2});
                $scope.cart.push({price: 5.5, count: 5});
                $scope.addProduct = function(){
                    let p = {price: Math.round(Math.random()*500)/10, count: Math.ceil(Math.random()*10)}
                    $scope.cart.push(p);
                    console.log($scope.cart.count);
                }
                $scope.getTotal = function(){
                    let total = 0;
                    angular.forEach($scope.cart, function(v, k){
                        total += v.count * v.price; 
                        console.log(v);
                    })
                    return total
                }
            })
        </script>
    </body>
    </html>
    

    Web项目中“单页应用”和“多页应用”的比较

    • 多页应用

      • 一个项目中有多个完整的.html页面
      • 多个页面间的跳转可以使用超链接、表单提交、JS(location.href="xx.html")
      • 页面切换是同步请求:客户端先删除第一个页面的DOM结构,发起HTTP请求,等待服务器给第二个页面的响应数据...一片惨白
      • 每个页面都是一个完整的DOM树
      • 页面切换时控制权在浏览器手中,不可能添加任何的过场动画效果
    • 单页应用(SPA)

      • 只有一个.html是完整的(缺少body主体),其他.html都是不完整的(可能只是一个div而已)
      • 多个“伪页面”间的跳转可以使用超链接、JS(...)
      • 伪页面切换是异步请求:客户端首先请求一个完整的页面,然后再发起异步AJAX请求,获取不同的模板页面,插入在当前的DOM树
      • 整个项目只有一个完整的DOM树
      • 伪页面切换的本质是一棵DOM树上的两个DIV在切换,可以很容易的添加各种过场动画
    • 总结

      • 单页应用完全可以实现传统的多页面的效果
      • 同时还可以降低服务器和客户端数据传输量、加快页面显示速度、添加丰富的过场动画效果!

    Angular国际化项目

    • 国际化项目
      • internationalization
      • 简写 i18n
      • 一个项目可以根据客户端的不同,呈现出不同的语言

    Angular模块指令

    Angular表达式

    • Angular表达式
      • 语法:{{表达式}}
      • 作用:在当前位置“输出”该表达式的值
      • 表达式运算
        • 算术运算 自加自减不可以
        • 比较运算 都可以
        • 逻辑运算 都可以
        • 三目运算 都可以
        • 赋值运算 += -= *= 等运算赋值不可以
        • 特殊运算符 不可以使用typeof()
        • 调用string的方法和属性
          • {{"apple".split('')}} 字符串变数组
          • {{"apple".slice(1, 4)}} 提取字符串
          • {{"apple".substr(0, 4)}} 从字符串某处提取N个字符
          • length属性 <span ng-init="ename='Tom'"></span> <p>{{ ename.length }}</p>
          • toUpperCase()方法 <span ng-init="ename='Tom'"></span> <p>{{ ename.toUpperCase() }}</p>
        • 创建新对象
          • 直接量语法: <p>{{ {ename:'Tom',age:30}.age }}</p>
          • new 构造方法:不可以
        • 创建数组
          • 数组直接量:<p>{{ [1,2,3] }}</p>
          • 数组直接量:<p>{{ [1,2,3][1] }}</p>
          • new Array:不可以

    ng模块提供的指令(Directive)

    • Angular中ng模块提供的指令(Directive)
      • ngAPP: 自动载入/启动一个Angular应用
        • 语法:
          • ng-app
          • <ANY ng-app="xxx"></ANY>
          • <ANY ng-app></ANY>
          • <ANY data-ng-app="xxx"></ANY>
        • 注意:一个HTML页面中只允许使用一次ngApp指令!用于确定AngularJS应用的范围
      • ngInit: 用于声明Model变量
        • ng-init
        • 语法:<ANY ng-init="变量名=值;变量名=值;..."></ANY>
        • 注意:Model变量声明时不能使用Var
      • ngController: 创建一个控制器对象的实例(即调用Controller函数)
        • ng-controller
        • 语法:<ANY ng-controller="控制器名"></ANY>
      • ngBind: 在当前元素的innerHTML上输出指定的表达式的值
        • ng-bind
        • 语法:<ANY ng-bind="表达式"></ANY>
        • 说明:此指令的作用与{{}}一样,只是可以防止闪动问题
      • ngRepeat: 为HTML增加循环功能,循环输出当前元素
        • 语法:<ANY ng-repeat="变量名 in Model数组/对象"></ANY>
        • 语法:<ANY ng-repeat="(下标, 值) in Model数组/对象"></ANY>
      • ngIf: 为HTML增加选择功能,
        • 只有在表达式值为true时,当前元素才添加到DOM树
        • 否则就从DOM树上删除
        • 语法:<ANY ng-if="表达式"></ANY>
      • ngSrc: 解决img等标签的src属性中包含{{}}产生的404问题
        • 语法:<img ng-src="路径/{{表达式}}">
      • ngClick: 为元素绑定监听函数(不是全局函数,而是Model函数)
        • 语法:<ANY ng-click="模型函数()"></ANY>
        • 注意:使用$scope.模型函数名 = function(){}格式来声明模型函数
      • ngStyle: 允许你在HTML元素上条件化设置CSS样式
        • 语法:<ANY ng-style="属性对象"></ANY>
        • 赋值为一个Model对象,用于为当前元素指定样式
      • ngModel: 使用NgModelController绑定一个 input,select, textarea (或自定义表单控件) 到域上的一个属性
        • 语法:
      • ngShow: 根据ngShow属性上表达式来显示或隐藏给定的HTML元素,通过display:none/block来控制当前元素是否显示
        • 语法:<ANY ng-show="表达式"></ANY>
      • ngHide: 根据ngHide属性上表达式来显示或隐藏给定的HTML元素,通过display:none/block来控制当前元素是否显示
        • 语法:<ANY ng-hide="表达式"></ANY>
      • ngDisabled: 赋值为true/false,可以控制当前元素是否禁用
        • 语法:<ANY ng-disabled="表达式"></ANY>
      • ngChecked: 赋值为true/false,可以控制当前元素是否选中
        • 语法:<ANY ng-checked="表达式"></ANY>
    <!-- ngInit指令 -->
    <div class="container" >
        <h2>Angular中创建Model变量的两种方法</h2>
        <h3>使用ngInit指令</h3>
        <!-- ngInit指令作为HTML元素属性来使用 -->
        <span ng-init="price=10.5"></span>
        <p>{{ price }}</p>
        <!-- ngInit指令作为HTML元素样式来使用 -->
        <span class="ng-init: price=22.5"></span>
        <p>{{ price }}</p>
    </div>
    

    ngAnimate模块

    • Angular中的ngAnimate模块

      • ngAnimate可以支持JS、Transition、Keyframes动画
      • 但它本身未提供任何的动画效果
      • 而是为上面三种技术提供了相应的“动画钩子(Hooks)”
    • ng模块中提供的指令:ngRepeat, ngInclude, ngIf, ngSwitch, ngShow, ngHide, ngView and ngClass 默认都提供了动画钩子

    • 使用ngAnimate模块调用其CSS Transition动画钩子的步骤:

      • 在index.html引入angular.js和angular-animate.js
      • 自定义模块中声明依赖于ngAnimate模块
        • 特定的指令就会产生动画钩子
        • angular.module('app', ['ng', 'ngRoute', 'ngAnimate'])
      • 为ngView声明class,样式中指定transition动画,现在就可以查看到动画钩子
        • <div class="page" ng-view></div>
      • 可以看到ngAnimate为即将要离开的ngView添加了ng-leave和ng-leave-active两个class,为即将要进入的ngView添加了ng-enter和ng-enter-active两个class
        • 为这四个class编写特定的class样式即可
    <!-- index.html -->
    <!DOCTYPE html>
    <html lang="en" ng-app="app">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <link rel="stylesheet" href="css/bootstrap.css">
        <link rel="stylesheet" href="css/app.css">
    </head>
    <body>
    <div class="page" ng-view></div>
    <script src="js/jquery-1.11.3.js"></script>
    <script src="js/angular.js"></script>
    <script src='js/angular-route.js'></script>
    <script src='js/angular-animate.js'></script>
    <script src='js/app.js'></script>
    </body>
    </html>
    
    // app.js
    angular.module('app', ['ng', 'ngRoute', 'ngAnimate']).
        controller('startCtrl', function($scope, $location){
          $scope.message = 'Hello start!';
          $scope.jump = function(routeUrl){
              $location.path(routeUrl); //修改路由地址
          }
        }).
        controller('mainCtrl', function($scope){
          $scope.message = 'Hello main!'
        }).
        controller('detailCtrl', function($scope){
          $scope.message = 'Hello detail!'
        }).
        config(function($routeProvider){
            $routeProvider.
                when('/start', {
                    templateUrl: 'tpl/start.html',
                    controller: 'startCtrl',
                }).
                when('/main', {
                    templateUrl: 'tpl/main.html',
                    controller: 'mainCtrl'
                }).
                when('/detail', {
                    templateUrl: 'tpl/detail.html',
                    controller: 'detailCtrl'
                }).
                otherwise({
                    redirectTo: '/start'
                })
        })
    
    /* app.css */
    body {
        position: relative;
        overflow: hidden;
    }
    .page {
        transition: all .15s linear;
        position: absolute;
         100%;
    }
    /* 即将要离开的ngView动画开始时的样式 */
    .page.ng-leave {
        /* left: 0; */
        opacity: 1;
    }
    /* 要离开的ngView动画结束时的样式 */
    .page.ng-leave.ng-leave-active {
        /* left: -100%; */
        opacity: 0;
    }
    /* 即将要进入的ngView动画开始时的样式 */
    .page.ng-enter {
        /* left: 100%; */
        opacity: 0;
    }
    /* 要进入的ngView动画结束时的样式 */
    .page.ng-enter.ng-enter-active {
        /* left: 0; */
        opacity: 1;
    }
    

    ngRoute模块

    • Angular中ngRoute模块
      • 概念:
        • ngRoute模块可以让用户自定义“路由字典”
        • 自动解析请求URL中的理由地址,查找路由字典
        • 自动发起异步AJAX请求,把获取的结果放在当前页面中
      • 使用ngRoute模块的步骤:
        • 创建唯一完整的页面:index.html,引入angular.js和angular-route.js
        • 在index.html的body中使用ngView指令声明一个容器元素用于盛放模板页面
        • 创建自定义模块,声明依赖于ng和ngRoute两个模块
        • 在当前模块中使用ngRoute提供的对象配置路由字典
          • 调用config(function(){})
          • 注入方法 $routeProvider
        • 再创建几个模板页面,只需要有div元素即可
        • 测试路由字典的配置是否正确
    <!--index.html-->
    <!DOCTYPE html>
    <html ng-app="M33">
    <head lang="en">
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <link rel="stylesheet" href="css/bootstrap.css">
    </head>
    <body>   
    <div ng-view></div>
    <script src="js/jquery-1.11.3.js"></script>
    <script src="js/angular.js"></script>
    <script src="js/angular-route.js"></script>
    <script>
    angular.module('M33', ['ng', 'ngRoute']).
      config(function($routeProvider){
        $routeProvider.
          when('/start', {
            templateUrl: 'tpl/start.html'
          }).
          when('/main', {
            templateUrl: 'tpl/main.html'
          }).
          when('/detail', {
            templateUrl: 'tpl/detail.html'
          }).
          otherwise({
            // 若URL中未提供路由地址或提供了不存在的路由地址
            // 重定向
            redirectTo: '/start'
          })
      })
    </script>
    </body>
    </html>
    
    <!--start.html-->
    <div class="panel panel-danger">
        <div class="panel-heading">
            <h3 class="panel-title">
                Start
            </h3>
        </div>
        <div class="panel-body">
            起始页
            <p><a href="#/detail" class='btn btn-success'>跳转到详情页</a></p>
            <p><a href="#/main" class='btn btn-success'>跳转到菜单页</a></p>
        </div>
    </div>
    
    <!--detail.html-->
    <div class="panel panel-success">
        <div class="panel-heading">
            <h3 class="panel-title">
                Start
            </h3>
        </div>
        <div class="panel-body">
            详情页
            <p><a href="#/start" class='btn btn-success'>跳转到起始页</a></p>
            <p><a href="#/main" class='btn btn-success'>跳转到菜单页</a></p>
        </div>
    </div>
    
    <!--main.html-->
    <div class="panel panel-info">
        <div class="panel-heading">
            <h3 class="panel-title">
                Start
            </h3>
        </div>
        <div class="panel-body">
            菜单页
            <p><a href="#/detail" class='btn btn-success'>跳转到详情页</a></p>
            <p><a href="#/start" class='btn btn-success'>跳转到起始页</a></p>
        </div>
    </div>
    
    • 使用ngRoute模块需要注意的问题:
      • 由于模板页面被客户端请求后挂载在index.htmlDOM树上
        • 所以其中所有的图片等外部资源文件的路径必须相对于index.html
        • 而不是模板页面
      • 使用ngRoute模块时,无需为模板页面中的某个元素单独设置ngController
        • 只需要再声明路由字典时设置整个模板页面所需的控制器即可
      • 在不同的模板页面间跳转可以采用两种方式:
        • 超链接方式
          • <a href="#/路由地址"></a>
        • JS编程方式
          • <button ng-click='jump()'></button>
          • $scope.jump = function(){$location.path('/路由地址');}
    // app.js
    angular.module('app', ['ng', 'ngRoute']).
      controller('startCtrl', function($scope, $location){
        $scope.message = 'Hello start!';
        $scope.jump = function(routeUrl){
          $location.path(routeUrl); //修改路由地址
        }
      }).
      controller('mainCtrl', function($scope){
        $scope.message = 'Hello main!'
      }).
      controller('detailCtrl', function($scope){
        $scope.message = 'Hello detail!'
      }).
      config(function($routeProvider){
        $routeProvider.
          when('/start', {
            templateUrl: 'tpl/start.html',
            controller: 'startCtrl',
          }).
          when('/main', {
            templateUrl: 'tpl/main.html',
            controller: 'mainCtrl'
          }).
          when('/detail', {
            templateUrl: 'tpl/detail.html',
            controller: 'detailCtrl'
          }).
          otherwise({
            redirectTo: '/start'
          })
      })
    
    <!--start.html-->
    <div class="panel panel-danger">
        <div class="panel-heading">
            <h3 class="panel-title">
                Start _ 起始页
            </h3>
        </div>
        <div class="panel-body">
            <p><a href="#/detail" class='btn btn-success'>跳转到详情页</a></p>
            <p><a class='btn btn-success' ng-click="jump('/main')">跳转到菜单页</a></p>
            <hr>
            <hr>
            <p class='text-justify text-danger'>jQuery全屏滚动插件fullPage.js</p>
            <p ng-bind='message'></p>
            <img class='img-responsive' src="img/10.jpg" alt="">
        </div>
    </div>
    

    ng模块中提供的服务(server)

    • $rootScope

      • 用于在不同的控制器间共享数据
    • $interval

      • 提供周期性定时器服务
    angular.module('myModule11', ['ng']).
      controller('c11', function($scope, $interval){
        $scope.age = 10;
        let t = $interval(function(){
          $scope.age > 100 ? $interval.cancel(t) : $scope.age++;
        }, 1000)
      })
    
    • $timeout

      • 提供一次性定时器服务
    • $http

      • 发起异步的AJAX请求服务
    <?php
    // 向客户端输出员工的信息,以JSON格式
    header('Content-Type: application/json');
    $empList = [];
    $empList[] = [
        'eno' => 101,
        'ename' => 'Tom',
        'salary' => rand(1000, 10000)
    ];
    $empList[] = [
        'eno' => 102,
        'ename' => 'Jerry',
        'salary' => rand(4500, 10000)
    ];
    $empList[] = [
        'eno' => 103,
        'ename' => 'Sunny',
        'salary' => rand(1000, 10000)
    ];
    $str = json_encode($empList);
    echo $str;
    ?>
    
    <!DOCTYPE html>
    <html lang="en" ng-app="M19">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <link rel="stylesheet" href="css/bootstrap.css">
    </head>
    <body>
    <section class="container" ng-controller="C19">
      <button class='btn btn-success' ng-click='loadEmpInfo()'>加载员工数据...</button>
      <table class='table table-bordered'>
        <thead>
          <tr>
            <th>选择</th>
            <th>姓名</th>
            <th>工资</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr ng-repeat="item in employee">
            <td><input type='checkbox' ng-checked="selectAll"></td>
            <td ng-bind="item.eno">Sunny</td>
            <td ng-bind="item.ename">Sunny</td>
            <td ng-bind="item.salary">8500</td>
            <td><button class='btn btn-danger'>删除</button></td>
          </tr>
        </tbody>
      </table>
      <input type="checkbox" ng-model="selectAll">
      <span ng-hide='selectAll'>全选</span>
      <span ng-show='selectAll'>取消全选</span>
    </section>
    <script src="js/jquery-1.11.3.js"></script>
    <script src="js/angular.js"></script>
    <script>
    angular.module('M19', ['ng']).
      controller('C19', function($scope, $http){
        $scope.employee = [];
        $scope.selectAll = false;
        $scope.loadEmpInfo = function(){
          // 点击按钮,则向服务器发起AJAX请求
          $http.get('data/19.php').
            success(function(data){
                for(let i=0; i<data.length;i++){
                  $scope.employee.push(data[i]);
                }
            })
        }
      })
    </script>
    </body>
    </html>
    

    Angular中声明变量与作用域

    Angular业务数据

    • Angular中声明变量——Model数据
      • 有两种方式可以声明Model变量
        • 使用ngInit指令声明
          • ngInit指令可以声明为HTML元素的属性或样式
          • ngInit指令声明的Model变量可以先使用再声明
          • ngInit指令可以一次声明多个Model变量,用分号隔开即可
          • ngInit指令可以声明哪些类型的Model变量
            • number 可以
            • string 可以
            • boolean 可以
            • 对象 直接量可以
            • 数组 直接量可以
            • 对象的数组 直接量可以
            • 注意:使用ng-init定义Model变量时,不能使用new关键字
            • 此方法把View和Model混杂在一起,不推荐使用
        • 使用Controller创建Model变量 推荐使用
          • 创建模块 <= 创建Controller <= 创建Model变量
          • 注意:新版本的Angular要求控制器必须声明在一个模块中!
          • 具体步骤
            • 声明一个自定义的模块(module)
              • angular.module('模块名',[])
            • 在当前AngularJS应用中注册自定义模块
              • ng-app="模块名"
            • 在自定义模块中创建Controll函数,其中创建Model数据
              • $scope是AngularJS中的域模型,也称为作用域实例,其实就是个可劲儿造的空对象
              • $scope.模型变量名 = 值;
            • 在View中创建Controller对象的实例,指定其作用范围
              • <ANY ng-controller="控制器名">...控制器的有效范围...</ANY>
            • 在控制器的作用范围内输出控制器中声明的Model变量
              • 可以使用{{}}输出Model变量的值
    <!-- MVC基础操作 -->
    <!DOCTYPE html>
    <!-- 2.在Angular应用中注册自定义模块 -->
    <html ng-app="myModule1">
    <head lang="en">
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <link rel="stylesheet" href="css/bootstrap.css">
    </head>
    <body>
      <div class="container">
        <div ng-controller="myController1">
          <!-- 5.在控制器的作用范围内输出控制器中声明的Model变量 -->
          <p>ename:{{ename}}</p>
          <p>age:{{age}}</p>
          <p>birthday:{{birthday.getFullYear()+'-'+(birthday.getMonth()+1)}}</p>
        </div>
        <div ng-controller="myController2">
          <p>ename:{{ename}}</p>
          <p>age:{{age}}</p>
          <p>birthday:{{birthday.getFullYear()+'-'+(birthday.getMonth()+1)}}</p>
        </div>
      </div>
    <script src="js/angular.js"></script>   
    <script>
      // 1.声明自定义模块
      angular.module('myModule1', ['ng']).
        controller('myController1', function($scope){
          // 3.创建一个Controller函数
          console.log('1对象的实例开始创建...');
          // 4.使用Controller函数创建/修改/删除Model数据
          $scope.ename = 'Tom';
          $scope.age = 18;
          $scope.birthday = new Date();
          console.log('1对象的实例创建完成!');
        }).
        controller('myController2', function($scope){
          // 3.创建一个Controller函数
          console.log('2对象的实例开始创建...');
          // 4.使用Controller函数创建/修改/删除Model数据
          $scope.ename = 'Jerry';
          $scope.age = 19;
          $scope.birthday = new Date();
          console.log('2对象的实例创建完成!');
        })
    </script>
    </body>
    </html>
    
    <!-- 对象操作 -->
    <!DOCTYPE html>
    <html ng-app="myMd5">
    <head lang="en">
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <link rel="stylesheet" href="css/bootstrap.css">
    </head>
    <body>
    <div class="container">
      <div ng-controller="myCtrl5">
        <p>name:{{stu.sname}}</p>
        <p>age:{{stu.age}}</p>
        <p ng-bind="'生日:'+stu.birthday.getFullYear()"></p>
        <p ng-bind="'性别:'+stu.sex"></p>
        <p>成绩:{{stu['score']}}</p>
      </div>
    </div>
    <script src="js/angular.js"></script>   
    <script>
      angular.module('myMd5', ["ng"]).
        controller("myCtrl5", function($scope){
          $scope.stu = new Object;
          $scope.stu.sname = 'Sunny';
          $scope.stu.age = 23;
          $scope.stu.sex = "女";
          $scope.stu.score = 99;
          $scope.stu.birthday = new Date();
        })
    </script>
    </body>
    </html>
    
    <!-- for循环 -->
    <!DOCTYPE html>
    <html ng-app="myMd6">
    <head lang="en">
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <link rel="stylesheet" href="css/bootstrap.css">
    </head>
    <body>
    <div class="container">
      <div ng-controller="myCtrl6">
        <p>{{scoreList}}</p> 
        <ul>
          <li ng-repeat="item in scoreList">
            {{item}}
          </li>
          <li ng-repeat="(index, num) in scoreList">
            {{index}} - {{num}}
          </li>
        </ul>
      </div>
    </div>
    <script src="js/angular.js"></script> 
    <script>
      angular.module("myMd6", ["ng"]).
        controller("myCtrl6", function($scope){
          $scope.scoreList = [95, 93, 89];
          $scope.scoreList.push(99);
          $scope.scoreList[$scope.scoreList.length] = 94;
        })
    </script>
    </body>
    </html>
    

    Angular域模型 (实例作用域)

    • $scope $rootScope

      • 每个控制器的实例都对应一个作用范围对象,即$scope
      • 在控制器中声明的Model数据,必须保存在控制的作用范围内
      • 一个HTML中可以声明多个控制器实例,每个控制器都有自己的作用范围,这些范围内的数据彼此隔离,不会相互影响,可以由不同的开发人员来编写
      • 为了在多个控制器间共享数据,可以将Model数据保存在一个"全局作用范围内"
      • $rootScope 真个AngularAPP中有且只有一个$rootScope对象
      • 且此对象是所有$scope的父作用域对象
    • 作用域对象的关系

      • 嵌套关系的作用域

    如何压缩css/js文件,得到xx.min.js/css

    • YUI框架:Yahoo User Interface,是由雅虎的前端工程师将自己的工作经验整理出来的工具集合,其中一个小工具:

      • yui-compressor,可用于压缩CSS和JS文件
      • yuicompressor-2.4.2.jar 置放于C盘根目录下
      • 使用步骤:
        • 下载并安装Java语言的运行环境——JDK
        • 在Java命令下运行yui-compressor工具
          • java.exe -jar c:/yui-comressor-2.4.2.jar e:/my.js >e:/my.min.js
          • 也可以把此工具配置为WebStorm中的FileWatcher(files/setting/tools),只要用户编辑一个.js/.css文件,即自动调用此工具得到压缩后的文件
      • 压缩效果:
        • 删除所有的注释
        • 删除没有语义的空白字符
        • 尽可能简化局部的变量名,函数名,形参名 —— 称为混淆
        • 注意:所有的数据值(如数字、字符串等)、关键字不会做任何改变
        • ctrl+alt+L 压缩恢复
    • JS框架

    // 自调函数的写法
    /*
    *这是我的一个JS框架
    * author: 文华
    * email:  liwenhua@tedu.cn
    * */
    +function(win, doc){
      var age = 20;
      var ename = 'Tom Cruise';
    
      //下面有一个执行相加操作的函数
      function add(num1, num2){
        var sum  = 0;
        sum = num1 + num2;
        return sum;
      }
    
      add(age, ename);   //调用add函数
    
    }(window, document);
    

    如何仿照AngularJS实现SPA的页面切换效果

    • 页面URL形如:
      • http://127.0.0.1/index.html#/路由地址
      • 浏览器首先请求基础页面(index.html),再解析URL中的路由地址
      • 查找路由字典,形如
        • /start -> tpl/start.html

        • /main -> tpl/main.html

        • ...
        • 获取当前URL中路由地址所对应的真实模板页面的地址
        • location.protocol
        • location.hostname
        • location.port
        • location.path
        • location.hash
      • 客户端发起异步AJAX请求,获取目标模板页面,将服务器返回的HTML片段(只含有几个DIV),插入到当前的DOM树上

    页面包含

    • 一个项目中的多个页面中可能包含完全相同的内容

      • 如京东商城中的很多页面都有完全相同的header和footer部分
      • 若每个HTML都拷贝一遍相同的内容
      • 就违反了DRY设计原则("不要重复你自己的代码"),造成代码的维护困难
    • 解决方法有如下几种:[最好]

      • 使用Web服务器的SSI(ServerSideInclude)
        • 修改Web服务器的配置文件
      • 使用服务器端动态编程语言进行页面的包含,如:PHP:
        • include('header.php');
        • ...
        • include('footer.php');
        • 三个PHP页面会组成一个大的响应消息,一次性返回给客户端
    • 纯前端解决方案:

      • 使用frameset或者iframe[尽量少使用]
    • 纯前端解决方案:使用AJAX异步请求:

      • 产品详情页.html
      • 注意:ngInclude指令必须赋值为一个字符串
        • <div ng-include=" 'tpl/header.html' "></div>
        • <div ng-include=" 'tpl/footer.html' "></div>
      • perspective: 1024px; 3D视图属性可影响 ng-include
    <div id='header'></div>
    <div>主体内容</div>
    <div id='footer'></div>
    
    $(document).read(function(){
      $('#header').load('header.html');   // XHR
      $('#footer').load('footer.html');   // XHR
    })
    
    • AngularJS中提供了一个类似于方案4的AJAX解决方案:ngInclude指令
    <div ng-include=" 'tpl/header.html' "></div>
    <div ng-include=" 'tpl/footer.html' "></div>
    

    多人协作开发模式

    • 配置目录

      • view1 开发者1使用的目录
        • 开发者1使用的母版
        • 开发者1使用的母版脚本
      • view2 开发者2使用的目录
        • 开发者2使用的母版
        • 开发者2使用的母版脚本
      • js 公共版本js库
        • angular.js
        • angular-animate.js
        • angular-route.js
        • app.js 项目母版脚本
      • index.html 项目母版
    • index.html 项目母版

    <!DOCTYPE html>
     <html lang="en" ng-app="myApp">
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <title>My AngularJS App</title>
      <meta name="description" content="">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="stylesheet" href="app.css">
    </head>
    <body>
      <div ng-view></div>
      <script src="js/angular.js"></script>
      <script src="js/angular-route.js"></script>
      <script src="js/app.js"></script>
      <script src="view1/view1.js"></script>
      <script src="view2/view2.js"></script>
    </body>
    </html>
    
    • app.js 项目母版脚本
    'use strict';
    angular.module('myApp', [
      'ngRoute',
      'myApp.view1',
      'myApp.view2'
    ]).
    config(['$routeProvider', function($routeProvider) {
      $routeProvider.otherwise({redirectTo: '/view1'});
    }]);
    
    • 开发者2使用的母版
    <p>This is the partial for view 2.</p>
    
    • 开发者2使用的母版脚本
    'use strict';
    angular.module('myApp.view2', ['ngRoute']).
      config(['$routeProvider', function($routeProvider) {
        $routeProvider.when('/view2', {
          templateUrl: 'view2/view2.html',
          controller: 'View2Ctrl'
        });
      }]).
      controller('View2Ctrl', [function() {
    
      }]);
    
  • 相关阅读:
    学习进度博客六
    Ultimate四则运算
    水骑士团队介绍
    返回一个二维整数数组中最大联通子数组的和
    学习进度博客五
    构建之法阅读笔记02
    四则运算4
    敏捷开发方法综述
    第一冲刺阶段站立会议02
    学习进度表_七周
  • 原文地址:https://www.cnblogs.com/SharkJiao/p/13780314.html
Copyright © 2020-2023  润新知