软件工程
软件设计原则
-
避免重复原则(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来担当
- Model
AngularJS概述
Angular概述
- 概述
- AngularJS是一个纯JS框架,基于jQuery对DOM操作做了进一步的封装
- 使用MVC操作代替所有的DOM操作
- 用于以数据操作为主的SPA(单页应用)应用
Angular四大特性
- AngularJS的四大特性:
- 采用MVC模式,页面中再也无需出现DOM操作
- Model: 模型,即业务数据,ng中由保存在特定范围内的变量来担当
- View: 视图,负责数据的呈现,ng中由HTML(增强型)来担当
- Controller: 控制器,负责操作(CDUD)数据,ng中由模块中的function来担当
- 采用MVC模式,页面中再也无需出现DOM操作
双向数据绑定
-
方向一:把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 = {width: '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="width: 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组件:
- AngularJS官方提供的模块
-
Angular模块中的常用组件之filter
- filter:过滤器,用于Model数据在View中呈现时进行某种格式的筛选/过滤/格式化
- 在View中使用过滤器时,需要借助于管道 |
- ng模块中提供的过滤器
- lowercase 把数据格式化为小写
- 语法:{{表达式 | lowercase}}
- uppercase 把数据格式化为大写
- 语法:{{表达式 | uppercase}}
- number 把数字型数据格式化为三位一个逗号的字符串,同时指定小数点位数
- 语法:{{表达式 | number:小数位数}}
- currency 把数字型数据格式化为货币格式的字符串,同时指定货币符号
- 语法:{{表达式 | currency:'货币符号'}}
- date 把数据/Date型数据格式化为特定日期时间格式的字符串
- 真实项目中,往往不使用Date类型表示日期时间
- 而使用长整型的数字来代替
- 所有的编程语言/数据库系统都支持长整型数字,都可以把数字和日期时间随意的转换
- 语法: {{表达式 | date:'日期时间格式'}}
- lowercase 把数据格式化为小写
<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>
Angular国际化项目
- 国际化项目
- internationalization
- 简写 i18n
- 一个项目可以根据客户端的不同,呈现出不同的语言
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:不可以
- 数组直接量:
Angular模块指令
- 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>
- 语法:
- ngAPP: 自动载入/启动一个Angular应用
<!-- 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>
-
Angular中ngAnimate模块提供的指令
-
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>
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变量的值
- 声明一个自定义的模块(module)
- 使用ngInit指令声明
- 有两种方式可以声明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的父作用域对象
-
作用域对象的关系
- 嵌套关系的作用域
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>
如何压缩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);
Web项目中“单页应用”和“多页应用”的比较
-
多页应用
- 一个项目中有多个完整的.html页面
- 多个页面间的跳转可以使用超链接、表单提交、JS(location.href="xx.html")
- 页面切换是同步请求:客户端先删除第一个页面的DOM结构,发起HTTP请求,等待服务器给第二个页面的响应数据...一片惨白
- 每个页面都是一个完整的DOM树
- 页面切换时控制权在浏览器手中,不可能添加任何的过场动画效果
-
单页应用(SPA)
- 只有一个.html是完整的(缺少body主体),其他.html都是不完整的(可能只是一个div而已)
- 多个“伪页面”间的跳转可以使用超链接、JS(...)
- 伪页面切换是异步请求:客户端首先请求一个完整的页面,然后再发起异步AJAX请求,获取不同的模板页面,插入在当前的DOM树
- 整个项目只有一个完整的DOM树
- 伪页面切换的本质是一棵DOM树上的两个DIV在切换,可以很容易的添加各种过场动画
-
总结
- 单页应用完全可以实现传统的多页面的效果
- 同时还可以降低服务器和客户端数据传输量、加快页面显示速度、添加丰富的过场动画效果!
如何仿照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树上