基础 - AngularJS
AngularJS 基于JS的一前端框架,产生于2009年 官方网址 https://www.angularjs.org/ 客户端模板 把数据和模板先发送到客户端再装配 MVC设计模式 Model 承载数据,对象的属性 View 展示数据,即DOM Controller 应用逻辑,即JS 数据绑定 又称MVVM 自动同步model与view之间的数据 这样,只要改动了一方,另一方就会同步 依赖注入 B的实现需要A,叫做B依赖A,A注入B 通常,将A做为参数传递,使A成为全局变量 依赖注入,不需要创建依赖而获取需要的东西
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--angularjs--> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script> </body> </html>
ng-app指令 说明Angular可以管理的范围
<body> <!--angularjs--> <script type="text/javascript" src="//cdn.bootcss.com/angular.js/1.2.10/angular.min.js"></script> <!--自定义--> <script type="text/javascript" src="js/xiezi.js"></script> </body>
表达式 {{ }} angular表达式通过$parse服务解析执行 angular表达式的属性求值是对于scope的,JS表达式的属性求值是对于window的 angular表达式的表达式求值对于undefined和null是宽容的, JS表达式的表达式求值对于undefined和null产生NullPointerExceptions错误异常 angular表达式没有流程控制语句,JS表达式含有流程控制语句 angular表达式可以将表达式结果传入过滤器链
<!-- 数据绑定模型name view与model是双向绑定的 view改变值,model对应的改变 model改变,view值对应的改变 --> <input type="text" ng-model="name" /> <input type="text" ng-model="name" /> <!--输出模型name--> {{name}}
<body> <div ng-app="" > <div ng-controller="firstController" > <input type="text" ng-model="name"> </div> </div> <!--angularjs--> <script type="text/javascript" src="//cdn.bootcss.com/angular.js/1.2.10/angular.min.js"></script> <!--自定义--> <script type="text/javascript" src="js/xiezi.js"></script> </body>
/** * * @param $scope 依赖注入,参数名不可改变,作用域 */ function firstController ($scope) { $scope.name = "菲尔"; }
ng-bind 等待angularjs加载完再显示model数据 <input type="text" ng-model="name"> <p ng-bind="name"></p>
多个作用域 加载时,外部作用域下的模型数据可以传递给内部的作用域,优先选择内部自己的作用域模型数据 加载完,外部作用域下的模型数据不可以传递给内部的作用域 加载完,内部作用域下的模型数据不可以传递给外部的作用域
<div ng-app="" > <div ng-controller="firstController" > <input type="text" ng-model="name"> <div ng-controller="secondController" > <input type="text" ng-model="name"> </div> </div> </div>
/** * * @param $scope 依赖注入,参数名不可改变,作用域 */ function firstController ($scope) { $scope.name = "菲尔"; } function secondController ($scope) { console.log($scope); }
Angular的脏检查 复制一份参照,检查时如果数据有差别,即时同步数据 绑定HTML的对象,被列为检查对象 检查对象的属性,被列为检查属性 初始化时,为每个检查属性添加一个监听watcher
$apply()底层的实现流程 $scope.$apply()进入上下文, $eval()解析表达式, $rootScope.$digest()执行脏检查 注意,$scope.$apply()不传参的话,检查所有监听元素
/** * * @param $scope 依赖注入,参数名不可改变,作用域 */ function firstController ($scope) { setInterval(function () { $scope.$apply(function () { $scope.name = new Date(); }); },1000); }
模型改变即时刷新view
function secondController ($scope) { $scope.$watch("name", function (newValue,oldValue) { console.log(newValue,oldValue); },true); }
/** * 购物车 */
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!--BootstrapCSS--> <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css" > </head> <body ng-app> <div class="container" ng-controller="funCarController"> <p ng-hide="car.length">您的购物车清空了</p> <table class="table" ng-show="car.length"> <thead> <tr> <th>序号</th> <th>名字</th> <th>数量</th> <th>单价</th> <th>总价</th> <th>操作</th> </tr> </thead> <tbody> <tr ng-repeat="item in car"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td> <button type="button" class="btn btn-primary" ng-click="funReduce(item.id)">-</button> <input type="text" value="{{item.quantity}}" ng-model="item.quantity" /> <button type="button" class="btn btn-primary" ng-click="funAdd(item.id)">+</button> </td> <td>{{item.price}}</td> <td>{{item.price*item.quantity}}</td> <td><button type="button" class="btn btn-danger" ng-click="funRemove(item.id)">移除</button></td> </tr> <tr> <td colspan="2"></td> <td>{{funAllQuantity()}}</td> <td></td> <td>{{funAllPrice()}}</td> <td><button type="button" class="btn btn-danger" ng-click="car={}">清空</button></td> </tr> </tbody> </table> </div> <!--jquery核心代码--> <script src="//cdn.bootcss.com/jquery/3.1.0/jquery.js"></script> <!--bootstrap核心JS--> <script src="//cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.js"></script> <!--angularjs--> <script type="text/javascript" src="//cdn.bootcss.com/angular.js/1.2.10/angular.min.js"></script> <!--自定义--> <script type="text/javascript" src="js/xiezi.js"></script> </body> </html>
function funCarController($scope) { $scope.car = [ { id : 001, name : "WeWeZhang", quantity : 5 , price : 111 }, { id : 002, name : "WeWeZhang", quantity : 3 , price : 222 }, { id : 003, name : "WeWeZhang", quantity : 2 , price : 333 } ]; $scope.funAllPrice = function() { var x = 0; angular.forEach($scope.car,function(item) { x += item.quantity*item.price; }); return x; } $scope.funAllQuantity = function() { var x = 0; angular.forEach($scope.car,function(item) { x += parseInt(item.quantity); }); return x; } function funFindIndex(id) { var index = -1; angular.forEach($scope.car, function(item,key) { if (item.id === id) { index = key; return; } }); return index; } $scope.funRemove = function(id) { var index = funFindIndex(id); if (index == -1) return; $scope.car.splice(index,1); } $scope.funReduce = function(id) { var index = funFindIndex(id); if (index == -1) return; if ($scope.car[index].quantity<=1) { if(confirm("删掉此行数据")){ $scope.funRemove(id); } }else { $scope.car[index].quantity--; } } $scope.funAdd = function(id) { var index = funFindIndex(id); if (index == -1) return; $scope.car[index].quantity++; } $scope.$watch("car", function(newValue,oldValue) { angular.forEach(newValue, function (item,key) { if (item.quantity<1) { if(confirm("数据不合法,是否置1")){ item.quantity=1; }else{ item.quantity=oldValue[key].quantity; } } }) },true); }
/** * 模块 */ 声明依赖关系和组装方式和启动方式 优点 声明式的启动 可以只加载需要的模块,方便单元测试 可以将第三方代码打包成代码 可以串行执行也可以并行执行,模块的执行是延迟的 可自定义模块 机制 模块提供多种机制,服务、指令、过滤器以及其它配置信息 服务机制 服务需要显式地声明依赖,使模块准确的注入服务 ng模块,angular默认的模块,内部封装了$http和$scope等服务 可以在现有的模块上自定义服务 可以自定义新的模块,再自定义服务
<!--we模块--> <div ng-app="we"> <div class="container" ng-controller="funCarController"> <p ng-hide="car.length">您的购物车清空了</p> <table class="table" ng-show="car.length"> <thead> <tr> <th>序号</th> <th>名字</th> <th>数量</th> <th>单价</th> <th>总价</th> <th>操作</th> </tr> </thead> <tbody> <tr ng-repeat="item in car"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td> <button type="button" class="btn btn-primary" ng-click="funReduce(item.id)">-</button> <input type="text" value="{{item.quantity}}" ng-model="item.quantity" /> <button type="button" class="btn btn-primary" ng-click="funAdd(item.id)">+</button> </td> <td>{{item.price}}</td> <td>{{item.price*item.quantity}}</td> <td><button type="button" class="btn btn-danger" ng-click="funRemove(item.id)">移除</button></td> </tr> <tr> <td colspan="2"></td> <td>{{funAllQuantity()}}</td> <td></td> <td>{{funAllPrice()}}</td> <td><button type="button" class="btn btn-danger" ng-click="car={}">清空</button></td> </tr> </tbody> </table> </div> </div>
/** * 创建模块 */ var oWeModule = angular.module("we",[]); oWeModule.controller("funCarController", function ($scope) { $scope.car = [ { id : 001, name : "WeWeZhang", quantity : 5 , price : 111 }, { id : 002, name : "WeWeZhang", quantity : 3 , price : 222 }, { id : 003, name : "WeWeZhang", quantity : 2 , price : 333 } ]; $scope.funAllPrice = function() { var x = 0; angular.forEach($scope.car,function(item) { x += item.quantity*item.price; }); return x; } $scope.funAllQuantity = function() { var x = 0; angular.forEach($scope.car,function(item) { x += parseInt(item.quantity); }); return x; } function funFindIndex(id) { var index = -1; angular.forEach($scope.car, function(item,key) { if (item.id === id) { index = key; return; } }); return index; } $scope.funRemove = function(id) { var index = funFindIndex(id); if (index == -1) return; $scope.car.splice(index,1); } $scope.funReduce = function(id) { var index = funFindIndex(id); if (index == -1) return; if ($scope.car[index].quantity<=1) { if(confirm("删掉此行数据")){ $scope.funRemove(id); } }else { $scope.car[index].quantity--; } } $scope.funAdd = function(id) { var index = funFindIndex(id); if (index == -1) return; $scope.car[index].quantity++; } $scope.$watch("car", function(newValue,oldValue) { angular.forEach(newValue, function (item,key) { if (item.quantity<1) { if(confirm("数据不合法,是否置1")){ item.quantity=1; }else{ item.quantity=oldValue[key].quantity; } } }) },true); });
/** * 自定义模块,自定义服务 */ var oWeModule = angular.module("we",[], function ($provide) { $provide.provider("$newService", function () { this.$get = function () { return { message:"没理由的呢" } } }); }); oWeModule.controller("funCarController", function ($scope,$newService) { console.log($newService); },true);
/** * 简便写法,factory可返回任意形式的数据,service只能返回对象类型 */ var oWeModule = angular.module("we",[], function ($provide) { $provide.factory("$newFactory", function () { return "没理由的呢"; }); $provide.service("$newService", function () { return {name:"wewezhang",age:25}; }); });
/** * 然而实际开发中,这样使用factory和service */ angular.module("we",[]) .factory("$newFactory", function () { return "没理由的呢"; }) .service("$newService", function () { return {name:"wewezhang",age:25}; }) .controller("funCarController", function ($scope,$newService,$newFactory) { console.log($newService,$newFactory); },true);
/** * 多控制器之间的数据交互 */
<!--we模块--> <div ng-app="we"> <div ng-controller="funFirstController"> <input type="text" ng-model="data.message" /> </div> <div ng-controller="funSecondController"> <input type="text" ng-model="data.message" /> </div> </div>
angular.module("we",[]) .factory("$pubicData", function () { return { message : "WeWeZhang" }; }) .controller("funFirstController", function ($scope,$pubicData) { $scope.data = $pubicData; },true) .controller("funSecondController", function ($scope,$pubicData) { $scope.data = $pubicData; },true);
/** * 过滤器 */ 对数据进行格式化 筛选数据 可以直接使用在模板中 {{表达式 | 过滤器}} {{表达式 | 过滤器 | 过滤器}} {{表达式 | 过滤器 : 参数,参数}} 常见的过滤器 number 格式化数字,例如 {{123234456 | number}} 就是 123,234,456 currency 格式化货币,例如 {{1234| currency:"¥"}} 就是 $1234.00 date 格式化日期,例如 {{data.time | date:"yyyy年MM月dd日 HH点mm分ss秒 hh点mm分ss秒"} yyyy年MM月dd日 HH点mm分ss秒 hh点mm分ss秒 2016年10月23日 15点05分51秒 03点05分51秒 medium Oct 23, 2016 11:25:12 AM short 10/23/16 11:44 AM fullDate Sunday, October 23, 2016 longDate October 23, 2016 mediumDate Oct 23, 2016 shortDate 10/23/16 mediumTime 11:46:51 AM shortTime 11:48 AM limitTo 格式化截取{{[2,3,4,5,6] | limitTo:3}} {{[2,3,4,5,6] | limitTo:-3}} lowercase 格式化小写{{"WeWeZhang" | lowercase}} uppercase 格式化大写{{"WeWeZhang" | uppercase}} filter 格式化对象 {{[{name:"Zhang"},{name:"WeZhao"},{name:"WeQian"}] | filter:"We"}} {{[{name:"Zhang"},{name:"We"},{name:"We"}] | filter:{name:"We"} }} orderby 格式化排序 升序asc和降序desc {{ [{"id": 2,"name": "index02"}, {"id": 1,"name": "index01"}, {"id": 3,"name": "index03"}] | orderBy:'id' }} {{ [{"id": 2,"name": "index02"}, {"id": 1,"name": "index01"}, {"id": 3,"name": "index03"}] | orderBy:'id':true }} json 格式化Josn 控制器中使用过滤器 .controller("funFirstController", function ($scope,$pubicData,$filter) { $pubicData.time = $filter("date")($pubicData.time,"yyyy年MM月dd日 HH点mm分ss秒 hh点mm分ss秒"); $scope.data = $pubicData; console.log($filter('json')($scope.data)); },true) 自定义不带参数filter .filter('funOrdinal', function () { return function (number) { if (isNaN(number) || number < 1) { return number; } else { var lastDigit = number % 10; if (lastDigit === 1) { return number + 'st' } else if (lastDigit === 2) { return number + 'nd' } else if (lastDigit === 3) { return number + 'rd' } else if (lastDigit > 3) { return number + 'th' } } } }) {{777 | funOrdinal}} 自定义带参数filter .filter('funCapitalize', function () { return function (input, char) { if (isNaN(input)) { var char = char - 1 || 0; var letter = input.charAt(char).toUpperCase(); var out = []; for (var i = 0; i < input.length; i++) { if (i == char) { out.push(letter); } else { out.push(input[i]); } } return out.join(''); } else { return input; } } }) {{'seven' | funCapitalize:3}}
/** * 过滤器实例 */
<!--模块--> <div ng-app="we" class="container"> <div ng-controller="funSampleController"> <nav class="navbar navbar-default" role="navigation"> <div class="container-fluid"> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <form class="navbar-form navbar-left" role="search"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search" ng-model="search.id"> </div> </form> </div> </div> </nav> <table class="table"> <thead> <tr> <th ng-click="funChangeOrder('id')" ng-class="{dropup:!order.length}">编号<span class="caret"></span> </th> <th ng-click="funChangeOrder('name')" ng-class="{dropup:!order.length}">名称<span class="caret" ></th> <th ng-click="funChangeOrder('price')" ng-class="{dropup:!order.length}">价钱<span class="caret" ></th> </tr> </thead> <tbody> <tr ng-repeat="item in data | filter:search | orderBy:order+orderType "> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.price | currency:"¥"}}</td> </tr> </tbody> </table> </div> </div>
angular.module("we",[]) .factory("$publicData", function () { return [ { id:002, name:"iPhone4S", price:2000 }, { id:001, name:"iPhone5S", price:3500 }, { id:003, name:"iPhone6P", price:6000 } ]; }) .controller("funSampleController", function ($scope,$publicData,$filter) { $scope.data = $publicData; console.log($filter('json')($scope.data)); $scope.orderType = "id"; $scope.order = ""; $scope.funChangeOrder = function (string) { $scope.orderType = string; $scope.order = $scope.order.length?"":"-"; } },true);
/** Controller的正确使用方法 抽离不必要的业务到.service或.factory中,然后Controller通过依赖注入的方式使用它们 常见的不必要的业务 任何DOM操作,任何的表现逻辑都是不必要的,通常抽离到directive中 任何输入格式化,通常使用formcontrols代替 任何输出格式化过滤,通常使用filter代替 任何无状态或有状态的controllers共享的代码,通常使用service或factory代替 任何实例化或管理其他组件的生命周期 */
/** * 显式的依赖注入 */ .controller("funSampleController",["$scope","$filter","$publicData", function ($scope,$filter,$publicData) { $scope.data = $publicData; console.log($filter('json')($scope.data)); }],true)
function funNormal($sample) { } funNormal.$inject = ["$scope"];
/** * 指令 * 扩展HTML标签,声明式语法使用特殊的标签替换普通的标签 * 指令的校验格式 * 普通校验格式 ng-name * XML校验格式 ng:name * XHTML校验格式 x-ng-name * HTML5校验格式 data-ng-name * angular内置的指令 * angular内置了多种多样的指令,例如ng-app ng-controller等 * angular内置的指令大体可分为:渲染指令、、 * 渲染指令 * ng-init 初始化指令 <div ng-init="array=['we']"></div> * ng-bind 等待渲染指令 <div ng-bind>{{1+1}}</div> * ng-repeat 遍历指令 * 其中,$index当前元素的索引 $first当前元素是否头元素 $middle当前元素是否既不是头也不是尾 $last当前元素是否尾元素 * ng-include <div ng-include="'sample.html'"></div> * 事件指令 * 执行完事件以后,自动执行脏检查 * $scope.funChangeOrder = function (event) { * angular.element(event.target).val($scope.bState); * } * <div ng-click="funChangeOrder($event)"></div> * 节点指令 * ng-style <div ng-style="{'color':'#cccccc','margin-top':'50px'}">Sam</div> * ng-class <div ng-class="{clsssname:isTrue}"></div> * ng-class-odd奇数 ng-class-even偶数 * ng-show显示或ng-hide隐藏 <div ng-show="state"></div> * ng-switch on="state" ng-switch-when="true" 或 "false" * ng-src ng-href 采用延迟加载机制,类似ng-bind * ng-if 条件判断 * 自定义指令 */ angular.module("we",[],["$compileProvider",function($compileProvider){ $compileProvider.directive("zwCustomTag", function () { return{ /** * A属性 * C类 * E元素 <zw-custom-tag></zw-custom-tag> * M注释 **/ restrict:"ACEM", template:"<div>Sample</div>", replace:true } }); }]) .directive("zwCustomTag", function () { return { /** * A属性 * C类 * E元素 <zw-custom-tag></zw-custom-tag> * M注释 **/ restrict: "ACEM", template: "<div>Sample</div>", replace: true } });