AngularJS 学习笔记
本文发布于 6 年前,部分内容可能已经失去参考价值。
1.1 四大特性
MVC
<!doctype html>
<html ng-app>
<body>
<div ng-controller="HelloAngular">
<p>{{greeting.text}}, Angular</p>
</div>
<script src="js/angular-1.3.0.js"></script>
<script>
function HelloAngular($scope) {
$scope.greeting = {
text: 'Hello'
};
}
</script>
</body>
</html>
模块化与依赖注入
<!doctype html>
<html ng-app="app">
<body>
<div ng-controller="HelloAngular">
<p>{{greeting.text}}, Angular</p>
</div>
<script src="js/angular-1.3.0.js"></script>
<script>
var myModule = angular.module("app", []);
myModule.controller("HelloAngular", ['$scope',
function($scope) {
$scope.greeting = {
text: 'Hello'
};
}
]);
</script>
</body>
</html>
双向数据绑定
<!doctype html>
<html ng-app>
<body>
<input ng-model="greeting.text" />
<p>{{greeting.text}},AngularJS</p>
<script src="js/angular-1.3.0.js"></script>
</body>
</html>
指令
<!doctype html>
<html ng-app="app">
<body>
<hello></hello>
<script src="js/angular-1.3.0.js"></script>
<script>
var myModule = angular.module("app", []);
myModule.directive("hello", function () {
return {
restrict: 'E',
template: '<div>Hi everyone!</div>',
replace: true
}
});
</script>
</body>
</html>
1.2 开发环境
node.js | JS 运行环境 |
Bower | 插件管理(相当于 NuGet) |
Grunt | 代码混淆、合并工具 |
Sublime | 代码编辑器(小巧),Zen Coding 快速编写 HTML/CSS 代码 |
WebStorm | 代码编辑器(强大) |
git 小乌龟 | 版本管理 |
2.1 MVC
Controller 使用要点:
不要复用 Controller
不要操作 DOM
不要做数据格式化,ng 有表单控件
不要做数据过滤,ng 有 $filter
$scope 作用域
<!doctype html>
<html ng-app>
<head>
<style>
.show-scope-demo .ng-scope, .show-scope-demo .ng-scope { border: 1px solid red; margin: 3px; }
</style>
</head>
<body>
<div class="show-scope-demo">
<div ng-controller="GreetCtrl">
Hello {{name}}!
</div>
<div ng-controller="ListCtrl">
<ol>
<li ng-repeat="name in names">
{{name}} from {{department}}
</li>
</ol>
</div>
</div>
<script src="js/angular-1.3.0.js"></script>
<script>
function GreetCtrl($scope, $rootScope) {
$scope.name = 'World';
// 在根作用域定义了 department,在 ListCtrl 控制器中也能用
$rootScope.department = 'Angular';
}
function ListCtrl($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}
</script>
</body>
</html>
<!doctype html>
<html ng-app>
<head>
<style>
.show-scope-demo .ng-scope, .show-scope-demo .ng-scope { border: 1px solid red; margin: 3px; }
</style>
</head>
<body>
<div ng-controller="EventController">
Root scope
<tt>MyEvent</tt> count: {{count}}
<ul>
<li ng-repeat="i in [1]" ng-controller="EventController">
<button ng-click="$emit('MyEvent')">
$emit('MyEvent')
</button>
<button ng-click="$broadcast('MyEvent')">
$broadcast('MyEvent')
</button>
<br>
Middle scope
<tt>MyEvent</tt> count: {{count}}
<ul>
<li ng-repeat="item in [1, 2]" ng-controller="EventController">
Leaf scope
<tt>MyEvent</tt> count: {{count}}
</li>
</ul>
</li>
</ul>
</div>
<script src="js/angular-1.3.0.js"></script>
<script>
function EventController($scope) {
$scope.count = 0;
$scope.$on('MyEvent', function () {
$scope.count++;
});
}
</script>
</body>
</html>
$emit:向上传播
$broadcast:向下传播
ng-repeat="i in [1, 2]":循环固定项
$scope 是一个树形结构,与 DOM 平行
子 $scope 对象会继承父 $scope 上的属性和方法
每个 Angular 应用只有一个根 $scope,一般位于 ng-app 上
$scope 可以传播事件,类似 DOM 事件,可向上可向下
2.2 路由、模块、依赖注入
var bookStoreApp = angular.module('bookStoreApp', [
'ngRoute', 'ngAnimate', 'bookStoreCtrls', 'bookStoreFilters',
'bookStoreServices', 'bookStoreDirectives'
]);
bookStoreApp.config(function($routeProvider) {
$routeProvider.when('/hello', {
templateUrl: 'tpls/hello.html',
controller: 'HelloCtrl'
}).when('/list',{
templateUrl:'tpls/bookList.html',
controller:'BookListCtrl'
}).otherwise({
redirectTo: '/hello'
})
});
2.3 双向数据绑定
绑定方式1:<p>{{greeting.text}}, Angular</p>
绑定方式2:<p><span ng-bind="greeting.text"></span>, Angular</p>
方式1 在加载 angular.js 之前会将 {{***}} 显示于界面,因此在 index.html 页面建议用方式2,通过模板加载的页面上的绑定可以使用方式1。
<!doctype html>
<html ng-app="UserInfoModule">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="css/bootstrap-3.0.0/css/bootstrap.css">
</head>
<body>
<div class="panel panel-primary">
<div class="panel-heading">
<div class="panel-title">双向数据绑定</div>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-12">
<form class="form-horizontal" role="form" ng-controller="UserInfoCtrl">
<div class="form-group">
<label class="col-md-2 control-label">
邮箱:
</label>
<div class="col-md-10">
<input type="email" class="form-control" placeholder="推荐使用126邮箱" ng-model="userInfo.email">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">
密码:
</label>
<div class="col-md-10">
<input type="password" class="form-control" placeholder="只能是数字、字母、下划线" ng-model="userInfo.password">
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="userInfo.autoLogin">自动登录
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button class="btn btn-default" ng-click="getFormData()">获取Form表单的值</button>
<button class="btn btn-default" ng-click="setFormData()">设置Form表单的值</button>
<button class="btn btn-default" ng-click="resetForm()">重置表单</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<script src="js/angular-1.3.0.js"></script>
<script>
var userInfoModule = angular.module('UserInfoModule', []);
userInfoModule.controller('UserInfoCtrl', ['$scope',
function ($scope) {
$scope.userInfo = {
email: "253445528@qq.com",
password: "253445528",
autoLogin: true
};
$scope.getFormData = function () {
console.log($scope.userInfo);
};
$scope.setFormData = function () {
$scope.userInfo = {
email: 'damoqiongqiu@126.com',
password: 'damoqiongqiu',
autoLogin: false
}
};
$scope.resetForm = function () {
$scope.userInfo = {
email: "253445528@qq.com",
password: "253445528",
autoLogin: true
};
}
}
]);
</script>
</body>
</html>
注意 ng-click 的用法。
ng-class 用法:
ng-class='{bg-danger: isError, bg-success: isSuccess}'
表示当 isError 为 true 时应用 bg-danger 样式,当 isSuccess 为 true 时应用 bg-success 样式。
ng-show / ng-hide 用法:
ng-show='isShow'
表示当 isShow 为 true 时显示,否则隐藏。
2.4 指令(Directive)重要!
路由
Angular 自带的 angular.route.js 不能实现嵌套路由,推荐使用 UI-Router,方便将页面分割成多个 ui-view 实现局部更新。
angular.module("app", []).directive("directiveName", function () {
return {
//通过设置项来定义
};
});
设置项:
restrict: 'AEMC', // A 属性(默认),E 元素,M 注释,C 样式
template: '<div>xxx</div>', // 替代的 HTML
replace: true, // 替代
transclude: true, // 嵌套,需要 template 配合,例如:
templace: '<div>xxx <div ng-transclude></div></div>', // 原来指令标签中的内容会被放置于 ng-transclude 所在 div 中。
templaceUrl: 'xxx.html', // 使用独立 html 的模板内容
compile: function() { }, // 对模板自身进行转换
link: function() {}, // 操作 DOM、绑定事件监听器
可以在页面中使用 ui-sref 或控制器中 $state.go 来实现跳转(页面更新)
如何传递参数:
一个简单的示例:在一个文章列表页面和一个文章详情页面中实现跳转,需要传递参数文章 id
在路由配置 state 中加入:params: { "id": null }
在列表行中绑定 id,格式如:<a ui-sref="app.blog.item({id:row.id})"><span>Edit</span></a>
在详情页控制器中接收参数:$stateParams,即可用 $stateParams.id 来获取文章 id 值
如果需要同时更改地址栏 url,并且能够使用该 url 直接打开该文章,那么修改 state 中的 url 为 /item?id,体现为 #/app/blog/item?id=9,也可以用冒号 /item:id,体现为 #/app/blog/item9
scope 的绑定策略:
@:把当前属性作为字符串传递。你还可以绑定来自外层 scope 的值,在属性值中插入 {{ }} 即可
=:与父 scope 中的属性进行双向绑定
&:传递一个来自父 scope 的函数,稍后调用
ERP 类型的系统必备 UI 组件:MiniUI、Ext JS
互联网/电商型系统必备 UI 组件:KISSY
其它常用组件:AngularUI
2.5 Service 与 Provider
使用 $http.get 获取 JSON 数据
<!doctype html>
<html ng-app="app">
<head>
<meta charset="UTF-8">
<script src="framework/1.3.0.14/angular.js"></script>
</head>
<body>
<div ng-controller="LoadDataCtrl">
<ul>
<li ng-repeat="user in users">
{{user.name}}
</li>
</ul>
</div>
<script>
var app = angular.module("app", []);
app.controller('LoadDataCtrl', ['$scope', '$http', function ($scope, $http) {
$http({
method: 'GET',
url: 'data.json'
}).success(function (data, status, headers, config) {
console.log("success...");
console.log(data);
$scope.users = data;
}).error(function (data, status, headers, config) {
console.log("error...");
})
}]);
</script>
</body>
</html>
data.json:
[
{ "name": "a" },
{ "name": "b" },
{ "name": "c" }
]
自定义 Service
<!doctype html>
<html ng-app="app">
<head>
<meta charset="UTF-8">
<script src="framework/1.3.0.14/angular.js"></script>
</head>
<body>
<div ng-controller="ServiceController">
<label>用户名:</label>
<input type="text" ng-model="username" placeholder="请输入用户名" />
<ul ng-show="username">
<li ng-repeat="user in users">
{{user.name}}
</li>
</ul>
</div>
<script>
var app = angular.module("app", []);
app.factory('userListService', ['$http', function ($http) {
var doRequest = function (username, path) {
return $http({ method: 'GET', url: 'data.json' });
};
return {
userList: function (username) {
return doRequest(username, 'userList');
}
}
}]);
app.controller('ServiceController', ['$scope', '$timeout', 'userListService', function ($scope, $timeout, userListService) {
var timeout;
$scope.$watch('username', function (newUserName) {
if (newUserName) {
if (timeout) {
$timeout.cancel(timeout);
}
timeout = $timeout(function () {
userListService.userList(newUserName)
.success(function (data, status) {
$scope.users = data;
});
}, 350);
}
});
}]);
</script>
</body>
</html>
知识点:
$timeout 延时,防抖动
userListService 服务调用 $http 服务获取数据,返回一个对象
自定义 Service 命名不要以“$”开头,可以像内置 Service 一样注入的,注入时必须放在内置 Service 之后
Service 是单例的
Service 只要声明,不需要实例化
Service 在整个应用的生命周期中存在,可以用来共享数据
$filter
currency / date / filter / json / limitTo / lowercase / number / orderBy / uppercase
data 例:
{{ 1304375948024 | data }}
{{ 1304375948024 | data:"MM/dd/yyyy @ h:mma" }}
{{ 1304375948024 | data:"yyyy-MM-dd hh:mm:ss" }}
效果:
May 3, 2011
05/03/2011 @ 6:39AM
2011-05-03 06:39:08
自定义 filter:
<!doctype html>
<html ng-app="app">
<head>
<meta charset="UTF-8">
<script src="framework/1.3.0.14/angular.js"></script>
</head>
<body>
{{'xoyozo'|filter1}}
<script>
var app = angular.module("app", []);
app.filter('filter1', function () {
return function (item) {
return item + 'o(u_u)o';
}
});
</script>
</body>
</html>
其它常用 Service:内置共 24 个
$compile 编译服务
$filter 数据格式化工具,内置了 8 个
$interval
$timeout
$locale
$location
$log
$parse
$http 封装了 ajax
2.6 综合实例 BookStore