AngularJS API
AngularJS API 学习笔记(详细版)
一、API 概述
AngularJS API 是一组由 AngularJS 框架提供的全局 JavaScript 函数和对象方法,用于操作模块、元素、数据、表单等。它们主要通过 angular 全局对象和注入的服务来访问。
1.1 API 分类总览
AngularJS API
├── angular 全局函数
│ ├── angular.module()
│ ├── angular.element()
│ ├── angular.bootstrap()
│ ├── angular.copy()
│ ├── angular.extend()
│ ├── angular.merge()
│ ├── angular.equals()
│ ├── angular.forEach()
│ ├── angular.isArray()
│ ├── angular.isDate()
│ ├── angular.isDefined()
│ ├── angular.isElement()
│ ├── angular.isFunction()
│ ├── angular.isNumber()
│ ├── angular.isObject()
│ ├── angular.isString()
│ ├── angular.isUndefined()
│ ├── angular.lowercase()
│ ├── angular.uppercase()
│ ├── angular.noop()
│ ├── angular.identity()
│ ├── angular.toJson()
│ └── angular.fromJson()
├── jqLite(angular.element)
├── $scope API
├── 表单 / 控件 API
├── $http API
├── $location API
├── $timeout / $interval API
├── $filter API
├── $q(Promise)API
├── $rootScope 事件 API
└── $injector API
二、angular 全局函数
2.1 angular.module()
创建、获取或注册 AngularJS 模块。
// 创建模块(第二个参数为依赖数组)
var myApp = angular.module('myApp', ['ngRoute']);
// 获取已有模块(省略第二个参数)
var existingApp = angular.module('myApp');
// 链式调用注册组件
angular.module('myApp', [])
.controller('MyCtrl', function() {})
.service('MySvc', function() {})
.directive('myDir', function() {});
| 用法 | 语法 | 说明 |
|---|---|---|
| 创建 | angular.module(name, [requires], [configFn]) |
返回模块实例 |
| 获取 | angular.module(name) |
返回已有模块实例 |
2.2 angular.element()
将 DOM 元素或 HTML 字符串包装为 jqLite 对象(jQuery 子集)。
// 包装 DOM 元素
var elem = angular.element(document.getElementById('myDiv'));
// 包装 HTML 字符串
var elem = angular.element('<div class="new">Hello</div>');
// 在指令 link 函数中,element 参数已经是 jqLite 对象
app.directive('myDir', function() {
return {
link: function(scope, element, attrs) {
// element 就是 jqLite 对象
element.addClass('active');
}
};
});
如果页面引入了 jQuery,
angular.element即为 jQuery 的$。
2.3 angular.bootstrap()
手动引导 AngularJS 应用,替代 ng-app 自动引导。
angular.element(document).ready(function() {
angular.bootstrap(document, ['myApp'], {
strictDi: true // 严格依赖注入模式(生产环境推荐)
});
});
| 参数 | 类型 | 说明 |
|---|---|---|
element |
DOMElement | 应用根元素 |
modules |
Array<string> | 模块名数组 |
config |
Object | 配置项(strictDi 等) |
使用场景:
- 动态加载脚本后初始化
- 同一页面多个 AngularJS 应用
- 需要在引导前执行初始化逻辑
2.4 angular.copy()
深拷贝对象或数组,可指定目标对象。
var source = { name: 'Tom', address: { city: 'BJ' } };
// 深拷贝到新对象
var clone = angular.copy(source);
clone.address.city = 'SH';
console.log(source.address.city); // 'BJ' —— 原对象不受影响
// 拷贝到目标对象
var target = { age: 20 };
angular.copy(source, target);
// target = { name: 'Tom', address: { city: 'BJ' } }
// 注意:target 原有属性会被清除!
| 参数 | 说明 |
|---|---|
source |
源对象 |
destination(可选) |
目标对象,会被清空后填充 |
注意:
- 会断开所有引用关系(真正的深拷贝)
- 目标对象的原有属性会被全部删除
- 循环引用会抛出异常
2.5 angular.extend()
浅拷贝合并对象,将源对象的属性复制到目标对象。
var defaults = { theme: 'light', lang: 'zh', pageSize: 10 };
var options = { theme: 'dark', showNav: true };
var result = angular.extend({}, defaults, options);
// result = { theme: 'dark', lang: 'zh', pageSize: 10, showNav: true }
// 直接修改目标对象
angular.extend(defaults, options);
// defaults 被修改:{ theme: 'dark', lang: 'zh', pageSize: 10, showNav: true }
特点:
- 浅拷贝:嵌套对象仍然是引用
- 后面的源对象属性覆盖前面的
- 返回目标对象
// ⚠️ 浅拷贝陷阱
var src = { info: { city: 'BJ' } };
var dst = {};
angular.extend(dst, src);
dst.info.city = 'SH';
console.log(src.info.city); // 'SH' —— 嵌套对象是引用!
2.6 angular.merge()
深拷贝合并对象(AngularJS 1.4+)。
var defaults = {
theme: 'light',
pagination: { pageSize: 10, current: 1 }
};
var options = {
theme: 'dark',
pagination: { current: 3 }
};
// angular.extend(浅拷贝)
var result1 = angular.extend({}, defaults, options);
// result1.pagination = { current: 3 } —— pageSize 丢失!
// angular.merge(深拷贝)
var result2 = angular.merge({}, defaults, options);
// result2.pagination = { pageSize: 10, current: 3 } —— 正确合并
extend vs merge 对比:
| 特性 | angular.extend | angular.merge |
|---|---|---|
| 拷贝深度 | 浅拷贝 | 深拷贝 |
| 嵌套对象 | 整体替换 | 递归合并 |
| 可用版本 | 全部 | 1.4+ |
| 性能 | 更快 | 较慢 |
2.7 angular.equals()
深度比较两个值是否相等。
angular.equals('hello', 'hello'); // true
angular.equals(1, 1); // true
angular.equals([1, 2], [1, 2]); // true —— 数组内容相同
angular.equals({a: 1}, {a: 1}); // true —— 对象内容相同
angular.equals(NaN, NaN); // true —— 特殊处理
angular.equals(/abc/g, /abc/g); // true —— 正则相同
angular.equals(new Date(2024, 0, 1), new Date(2024, 0, 1)); // true
angular.equals({a: 1}, {a: 2}); // false
与 === 的区别:
| 比较 | === |
angular.equals |
|---|---|---|
NaN === NaN |
false |
true |
[1] === [1] |
false |
true |
{a:1} === {a:1} |
false |
true |
2.8 angular.forEach()
遍历对象或数组,不可 break。
// 遍历数组
var arr = ['a', 'b', 'c'];
angular.forEach(arr, function(value, key) {
console.log(key + ': ' + value);
// 0: a, 1: b, 2: c
});
// 遍历对象
var obj = { name: 'Tom', age: 25 };
angular.forEach(obj, function(value, key) {
console.log(key + ': ' + value);
// name: Tom, age: 25
});
// 使用 this 上下文
var result = [];
angular.forEach([1, 2, 3], function(val) {
this.push(val * 2);
}, result);
// result = [2, 4, 6]
与原生 forEach 的区别:
| 特性 | angular.forEach | Array.prototype.forEach |
|---|---|---|
| 遍历对象 | 支持 | 不支持 |
| 遍历数组 | 支持 | 支持 |
| this 绑定 | 第三个参数 | 第二个参数 |
| IE8 兼容 | 是 | 否 |
| 可 break | 否 | 否 |
2.9 类型检查函数
// angular.isArray
angular.isArray([1, 2, 3]); // true
angular.isArray('hello'); // false
angular.isArray(arguments); // false —— arguments 不是数组
// angular.isDate
angular.isDate(new Date()); // true
angular.isDate('2024-01-01'); // false
// angular.isDefined
var a = 1;
angular.isDefined(a); // true
angular.isDefined(undefined); // false
// angular.isUndefined
angular.isUndefined(undefined); // true
// angular.isElement
angular.isElement(document.body); // true
angular.isElement(angular.element('<div>')); // true
// angular.isFunction
angular.isFunction(function(){}); // true
angular.isFunction(() => {}); // true
// angular.isNumber
angular.isNumber(42); // true
angular.isNumber(NaN); // true —— NaN 是数字
angular.isNumber('42'); // false
// angular.isObject
angular.isObject({}); // true
angular.isObject([]); // true —— 数组也是对象
angular.isObject(null); // false —— null 不是对象
angular.isObject(function(){}); // true —— 函数也是对象
// angular.isString
angular.isString('hello'); // true
angular.isString(42); // false
类型检查速查表:
| 函数 | true 示例 | false 示例 |
|---|---|---|
isArray |
[1,2] |
'abc', arguments
|
isDate |
new Date() |
'2024-01-01' |
isDefined |
1, null, ''
|
undefined |
isUndefined |
undefined |
null, 0, ''
|
isElement |
document.body |
'<div>' |
isFunction |
function(){} |
{} |
isNumber |
42, NaN
|
'42' |
isObject |
{}, [], function(){}
|
null, 42, 'str'
|
isString |
'hello' |
42 |
2.10 angular.lowercase() / angular.uppercase()
angular.lowercase('Hello World'); // 'hello world'
angular.uppercase('Hello World'); // 'HELLO WORLD'
注意: AngularJS 1.5.8+ 中这两个函数已被标记为已弃用,建议使用原生
String.prototype.toLowerCase()/toUpperCase()。
2.11 angular.noop()
一个空函数,用于不需要执行任何操作时的占位。
function doSomething(callback) {
callback = callback || angular.noop;
// 如果没有传 callback,不会报错
callback();
}
// 常见场景:可选回调
function save(data, onSuccess, onError) {
onSuccess = onSuccess || angular.noop;
onError = onError || angular.noop;
$http.post('/api/save', data)
.then(onSuccess, onError);
}
2.12 angular.identity()
返回第一个参数的函数,用于函数式编程中的占位。
angular.identity(42); // 42
angular.identity('hello'); // 'hello'
angular.identity(null); // null
// 使用场景:过滤函数的默认值
function filterItems(items, predicate) {
predicate = predicate || angular.identity;
return items.filter(predicate);
}
filterItems([1, 2, 3]); // [1, 2, 3] —— 无过滤
filterItems([1, 2, 3], x => x > 1); // [2, 3]
2.13 angular.toJson() / angular.fromJson()
JSON 序列化与反序列化。
// angular.toJson —— 对象 → JSON 字符串
var obj = { name: 'Tom', age: 25 };
var json = angular.toJson(obj);
// '{"name":"Tom","age":25}'
// 格式化输出(缩进空格数)
var pretty = angular.toJson(obj, 2);
/*
{
"name": "Tom",
"age": 25
}
*/
// angular.fromJson —— JSON 字符串 → 对象
var parsed = angular.fromJson('{"name":"Tom","age":25}');
// { name: 'Tom', age: 25 }
与 JSON.stringify / JSON.parse 的区别:
| 特性 | angular.toJson | JSON.stringify |
|---|---|---|
| 窗口/元素等对象 | 自动跳过(返回 undefined) | 抛出异常 |
| $$ 前缀属性 | 自动忽略 | 正常序列化 |
| 返回值 | 字符串 | 字符串 |
// $$ 前缀属性会被忽略(AngularJS 内部属性)
var data = { name: 'Tom', $$hashKey: 'obj:001' };
angular.toJson(data); // '{"name":"Tom"}' —— $$hashKey 被忽略
三、jqLite API(angular.element)
jqLite 是 jQuery 的极小子集,内置于 AngularJS 中。当页面未引入 jQuery 时,angular.element 返回 jqLite 对象。
3.1 支持的方法
var el = angular.element('<div class="box"><span>Hello</span></div>');
// === 查找 ===
el.find('span'); // 查找子元素(仅支持标签名选择器)
el.children(); // 直接子元素
el.parent(); // 父元素
el.next(); // 下一个兄弟元素
el.eq(0); // 获取第 N 个元素
// === 类操作 ===
el.addClass('active'); // 添加类
el.removeClass('box'); // 移除类
el.toggleClass('open'); // 切换类
el.hasClass('active'); // 是否有该类
// === 属性操作 ===
el.attr('id', 'main'); // 设置属性
el.attr('id'); // 获取属性
el.removeAttr('id'); // 移除属性
el.prop('disabled', true);// 设置 DOM 属性
el.prop('disabled'); // 获取 DOM 属性
// === CSS 操作 ===
el.css('color', 'red'); // 设置样式
el.css('color'); // 获取样式
el.css({ color: 'red', fontSize: '14px' }); // 批量设置
// === 内容操作 ===
el.html('<b>Bold</b>'); // 设置 innerHTML
el.html(); // 获取 innerHTML
el.text('Hello'); // 设置 textContent
el.text(); // 获取 textContent
el.val('new value'); // 设置 value
el.val(); // 获取 value
// === DOM 操作 ===
el.append('<p>Appended</p>'); // 追加子元素
el.prepend('<p>Prepended</p>');// 前置子元素
el.after('<hr>'); // 后面插入
el.before('<hr>'); // 前面插入
el.replaceWith('<div>New</div>'); // 替换
el.remove(); // 移除元素
el.empty(); // 清空内容
el.clone(); // 克隆元素
// === 事件 ===
el.on('click', handler); // 绑定事件
el.off('click', handler); // 解绑事件
el.triggerHandler('click'); // 触发事件
// === 数据 ===
el.data('key', 'value'); // 存储数据
el.data('key'); // 获取数据
el.removeData('key'); // 移除数据
// === 尺寸与位置 ===
el.ready(callback); // DOM ready 回调
3.2 jqLite 不支持的功能
// ❌ 不支持复杂选择器
angular.element('.my-class'); // 不支持
angular.element('#myId'); // 不支持
angular.element('div > span'); // 不支持
// ✅ 只支持标签名选择器
angular.element('div'); // 支持
// ✅ 包装 DOM 元素
angular.element(document.getElementById('myId')); // 支持
// ❌ 不支持动画方法
el.fadeIn(); // 不支持
el.slideDown(); // 不支持
el.animate(); // 不支持
3.3 jqLite 注意事项
// 1. find() 只支持标签名
el.find('span'); // ✅
el.find('.class'); // ❌
el.find('#id'); // ❌
// 2. 事件对象是原生 DOM 事件
el.on('click', function(event) {
event.preventDefault();
event.stopPropagation();
});
// 3. triggerHandler 不会冒泡
el.triggerHandler('click'); // 只触发当前元素的处理函数
// 4. 在指令中使用时,element 已经是 jqLite 对象
app.directive('myDir', function() {
return {
link: function(scope, element, attrs) {
// 不要再包装
// ❌ angular.element(element)
// ✅ 直接使用
element.addClass('active');
}
};
});
四、$scope API
4.1 核心方法
// === 数据相关 ===
// $watch:监听表达式变化
var deregister = $scope.$watch('user.name', function(newVal, oldVal) {
console.log('name changed from', oldVal, 'to', newVal);
});
// 深度监听
$scope.$watch('user', function(newVal, oldVal) {
console.log('user changed');
}, true); // 第三个参数:深度监听
// 监听集合变化(1.3+,性能优于深度监听)
$scope.$watchCollection('items', function(newVal, oldVal) {
console.log('items changed');
});
// 取消监听
deregister();
// $apply:手动触发脏检查
$scope.$apply(function() {
$scope.message = 'Updated from outside AngularJS';
});
// $eval:在当前 scope 上执行表达式
var result = $scope.$eval('1 + 2'); // 3
var result2 = $scope.$eval(function(scope) { // 可传函数
return scope.user.name;
});
// $evalAsync:在当前脏检查周期或下一个周期执行
$scope.$evalAsync(function() {
$scope.data = 'will be applied soon';
});
// === 事件相关 ===
// $on:监听事件
var deregisterEvent = $scope.$on('customEvent', function(event, data) {
console.log('received:', data);
// event.stopPropagation(); // 停止冒泡
// event.preventDefault(); // 阻止默认行为
});
// 取消监听
deregisterEvent();
// $emit:向上冒泡(子 → 父 → ... → $rootScope)
$scope.$emit('userUpdated', { id: 1 });
// $broadcast:向下广播(父 → 子 → 孙)
$scope.$broadcast('dataLoaded', { items: [] });
// === 生命周期 ===
// $destroy:scope 被销毁时触发
$scope.$on('$destroy', function() {
// 清理资源:取消定时器、解绑事件等
$interval.cancel(promise);
});
// 手动销毁 scope
$scope.$destroy();
4.2 $watch 详解
// 形式一:监听表达式字符串
$scope.$watch('user.name', function(newVal, oldVal, scope) {
// newVal: 新值
// oldVal: 旧值
// scope: 当前 scope
});
// 形式二:监听函数返回值
$scope.$watch(
function() { return $scope.user.age * 2; },
function(newVal, oldVal) {
console.log('age*2 changed:', newVal);
}
);
// 深度监听 vs 集合监听
$scope.$watch('items', handler, true); // 深度监听:递归比较所有属性
$scope.$watchCollection('items', handler); // 集合监听:只比较数组/对象的第一层
// 性能对比
// $watch('expr') —— 最快,引用比较
// $watchCollection —— 中等,浅层比较
// $watch('expr', ..., true) —— 最慢,深度递归比较
4.3 $apply vs $digest
// $apply:从 $rootScope 开始整棵 scope 树脏检查
$scope.$apply(function() {
$scope.data = 'new value';
});
// 等价于:
// 执行函数 → $rootScope.$digest()
// $digest:只从当前 scope 及其子 scope 脏检查
$scope.$digest(); // 不推荐直接使用
// $apply 的完整流程
$scope.$apply = function(expr) {
try {
return $eval(expr);
} finally {
$rootScope.$digest(); // 最终调用 $digest
}
};
何时需要 $apply:
// 原生事件回调中
element.addEventListener('click', function() {
$scope.$apply(function() {
$scope.clicked = true;
});
});
// setTimeout 中
setTimeout(function() {
$scope.$apply(function() {
$scope.time = new Date();
});
}, 1000);
// 第三方库回调中
someLibrary.onComplete(function(data) {
$scope.$apply(function() {
$scope.result = data;
});
});
// ❌ 不需要 $apply 的场景
// ng-click、$http、$timeout、$interval 等 AngularJS 内部已自动调用
五、表单 / 控件 API
5.1 NgModelController
app.directive('myValidator', [function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
// === 值相关 ===
ctrl.$viewValue; // 视图值(字符串)
ctrl.$modelValue; // 模型值(可能已转换类型)
ctrl.$setViewValue('new value'); // 设置视图值
ctrl.$commitViewValue(); // 提交视图值到模型
// === 验证相关 ===
ctrl.$validators.myCheck = function(modelValue, viewValue) {
return true; // 同步验证
};
ctrl.$asyncValidators.myAsyncCheck = function(modelValue, viewValue) {
return $q.resolve(); // 异步验证
};
ctrl.$setValidity('errorKey', false); // 设置验证状态
ctrl.$validate(); // 手动触发验证
ctrl.$error; // 错误对象
ctrl.$pending; // 异步验证中的项
// === 状态相关 ===
ctrl.$setPristine(); // 设为原始状态
ctrl.$setDirty(); // 设为已修改状态
ctrl.$setUntouched(); // 设为未触碰
ctrl.$setTouched(); // 设为已触碰
ctrl.$isEmpty(value); // 判断是否为空
ctrl.$pristine; // 是否原始
ctrl.$dirty; // 是否已修改
ctrl.$valid; // 是否有效
ctrl.$invalid; // 是否无效
ctrl.$touched; // 是否已触碰
ctrl.$untouched; // 是否未触碰
// === 管道相关 ===
ctrl.$parsers; // viewValue → modelValue 转换管道
ctrl.$formatters; // modelValue → viewValue 转换管道
ctrl.$render; // 自定义渲染函数
}
};
}]);
5.2 FormController
// 在控制器中通过 $scope 访问
app.controller('MyCtrl', ['$scope', function($scope) {
var form = $scope.myForm;
// === 属性 ===
form.$pristine; // 是否原始
form.$dirty; // 是否已修改
form.$valid; // 是否有效
form.$invalid; // 是否无效
form.$submitted; // 是否已提交
form.$error; // 错误对象(按类型分组)
form.$pending; // 异步验证中的控件
// === 方法 ===
form.$setPristine(); // 重置为原始状态
form.$setDirty(); // 设为已修改
form.$setSubmitted(); // 设为已提交
form.$setUntouched(); // 所有控件设为未触碰
form.$commitViewValue(); // 提交所有控件的视图值
form.$addControl(ctrl); // 添加控件
form.$removeControl(ctrl); // 移除控件
form.$setValidity(key, isValid, ctrl); // 设置验证状态
// 访问子控件
form.username; // 名为 username 的控件
}]);
六、$http API
6.1 基本用法
// GET
$http.get('/api/users', {
params: { page: 1, size: 10 } // 查询参数
}).then(successFn, errorFn);
// POST
$http.post('/api/users', { name: 'Tom' }).then(successFn, errorFn);
// PUT
$http.put('/api/users/1', { name: 'Tom Updated' }).then(successFn, errorFn);
// PATCH
$http.patch('/api/users/1', { name: 'Tom Patched' }).then(successFn, errorFn);
// DELETE
$http.delete('/api/users/1').then(successFn, errorFn);
// HEAD
$http.head('/api/users').then(successFn, errorFn);
// JSONP
$http.jsonp('/api/users?callback=JSON_CALLBACK').then(successFn, errorFn);
// 通用方法
$http({
method: 'GET',
url: '/api/users',
params: { page: 1 },
headers: { 'X-Custom-Header': 'value' },
timeout: 5000,
responseType: 'json'
});
6.2 响应对象
$http.get('/api/users').then(function(response) {
response.data; // 响应体(已自动解析)
response.status; // HTTP 状态码(200)
response.headers; // 响应头获取函数
response.headers('Content-Type'); // 获取特定头
response.config; // 请求配置对象
response.statusText; // 状态文本('OK')
}, function(response) {
// 错误处理
response.data; // 错误响应体
response.status; // 错误状态码(404, 500 等)
});
6.3 请求配置
$http({
method: 'POST',
url: '/api/users',
data: { name: 'Tom' }, // 请求体
params: { format: 'json' }, // URL 查询参数
headers: { // 请求头
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
timeout: 5000, // 超时(毫秒)
withCredentials: true, // 跨域携带 Cookie
responseType: 'json', // 响应类型:json|blob|arraybuffer|text
cache: false, // 是否缓存 GET 请求
transformRequest: [function(data, headers) {
return JSON.stringify(data); // 请求转换
}],
transformResponse: [function(data, headers) {
return JSON.parse(data); // 响应转换
}],
interceptors: [] // 拦截器
});
6.4 拦截器
app.factory('authInterceptor', ['$q', '$injector', function($q, $injector) {
return {
// 请求发出前
request: function(config) {
var token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = 'Bearer ' + token;
}
return config;
},
// 请求发出失败
requestError: function(rejection) {
return $q.reject(rejection);
},
// 响应到达后
response: function(response) {
return response;
},
// 响应错误
responseError: function(rejection) {
if (rejection.status === 401) {
// 未授权,跳转登录
$injector.get('$state').go('login');
}
return $q.reject(rejection);
}
};
}]);
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
}]);
七、$location API
7.1 核心方法
// === URL 各部分获取/设置 ===
// 完整 URL
$location.absUrl(); // 'http://example.com/path?key=val#hash'
$location.url('/new?key=val#hash'); // 设置 path + search + hash
// 路径
$location.path(); // '/path'
$location.path('/new-path'); // 设置路径
// 查询参数
$location.search(); // { key: 'val' }
$location.search('key'); // 'val'(获取单个参数)
$location.search({ key: 'newVal', page: 2 }); // 设置参数对象
$location.search('key', 'newVal'); // 设置单个参数
$location.search('key', null); // 移除参数
// 哈希
$location.hash(); // 'hash'
$location.hash('newHash'); // 设置哈希
// 协议、主机、端口
$location.protocol(); // 'http'
$location.host(); // 'example.com'
$location.port(); // 80
// === 状态方法 ===
$location.replace(); // 替换历史记录(不产生新记录)
$location.state(); // 获取 HTML5 history state
$location.state({ key: 'val' }); // 设置 state
7.2 $location vs window.location
| 特性 | $location | window.location |
|---|---|---|
| 与 Angular 集成 | 是(触发脏检查) | 否 |
| 重定向 | 不刷新页面 | 刷新页面 |
| 路由集成 | 是 | 否 |
| 可测试性 | 高 | 低 |
八、$timeout / $interval API
8.1 $timeout
// 基本用法(自动触发脏检查)
var promise = $timeout(function() {
$scope.message = '3秒后显示';
}, 3000);
// 取消
$timeout.cancel(promise);
// 带返回值
var promise = $timeout(function() {
return 'result';
}, 1000);
promise.then(function(result) {
console.log(result); // 'result'
});
// 不触发脏检查(第三个参数)
$timeout(function() {
// 不触发 $apply
}, 0, false);
8.2 $interval
// 基本用法
var promise = $interval(function() {
$scope.now = new Date();
}, 1000);
// 取消
$interval.cancel(promise);
// 限制执行次数(第四个参数)
var promise = $interval(function() {
$scope.count++;
}, 1000, 5); // 执行5次后自动停止
// 在 $destroy 中清理
$scope.$on('$destroy', function() {
$interval.cancel(promise);
});
为什么用 timeout/timeout/timeout/interval 而非原生:
- 自动触发
$apply,视图自动更新 - 可通过
cancel清理,防止内存泄漏 - 在测试中可被 mock,控制时间
九、$filter API
9.1 在控制器/服务中使用
app.controller('MyCtrl', ['$scope', '$filter', function($scope, $filter) {
// 获取过滤器函数
var uppercaseFilter = $filter('uppercase');
$scope.name = uppercaseFilter('hello'); // 'HELLO'
var currencyFilter = $filter('currency');
$scope.price = currencyFilter(123.45); // '$123.45'
var dateFilter = $filter('date');
$scope.today = dateFilter(new Date(), 'yyyy-MM-dd'); // '2024-01-15'
var numberFilter = $filter('number');
$scope.pi = numberFilter(3.14159, 2); // '3.14'
var limitToFilter = $filter('limitTo');
$scope.shortList = limitToFilter([1,2,3,4,5], 3); // [1,2,3]
var orderByFilter = $filter('orderBy');
$scope.sorted = orderByFilter(items, 'name', false);
var filterFilter = $filter('filter');
$scope.filtered = filterFilter(items, { status: 'active' });
}]);
9.2 内置过滤器一览
| 过滤器 | 用法 | 说明 |
|---|---|---|
currency |
{{ price | currency }} |
货币格式化 |
date |
{{ now | date:'yyyy-MM-dd' }} |
日期格式化 |
filter |
{{ items | filter:{name:'Tom'} }} |
数组过滤 |
json |
{{ obj | json }} |
JSON 格式化 |
limitTo |
{{ items | limitTo:5 }} |
限制数量 |
lowercase |
{{ name | lowercase }} |
转小写 |
uppercase |
{{ name | uppercase }} |
转大写 |
number |
{{ pi | number:2 }} |
数字格式化 |
orderBy |
{{ items | orderBy:'name' }} |
排序 |
十、$q(Promise/Deferred)API
10.1 创建 Promise
app.service('DataService', ['$q', '$http', function($q, $http) {
// 方式一:deferred
this.getUser = function(id) {
var deferred = $q.defer();
$http.get('/api/users/' + id)
.then(function(response) {
deferred.resolve(response.data);
}, function(error) {
deferred.reject(error);
});
return deferred.promise;
};
// 方式二:$q 构造函数(推荐,1.4+)
this.getUser2 = function(id) {
return $q(function(resolve, reject) {
$http.get('/api/users/' + id)
.then(function(response) {
resolve(response.data);
}, function(error) {
reject(error);
});
});
};
}]);
10.2 Promise 链式调用
$q.when(someValue) // 将值包装为 resolved Promise
.then(function(val) {
return process(val); // 返回值自动包装为 Promise
})
.then(function(result) {
return nextStep(result);
})
.catch(function(error) {
// 捕获链中任何一步的错误
console.error(error);
})
.finally(function() {
// 无论成功失败都执行
$scope.loading = false;
});
10.3 批量 Promise
// $q.all —— 全部成功才成功
$q.all([
$http.get('/api/users'),
$http.get('/api/products'),
$http.get('/api/orders')
]).then(function(results) {
var users = results[0].data;
var products = results[1].data;
var orders = results[2].data;
// 全部完成
});
// 对象形式(1.5+)
$q.all({
users: $http.get('/api/users'),
products: $http.get('/api/products')
}).then(function(results) {
var users = results.users.data;
var products = results.products.data;
});
// $q.race —— 最先完成的结果
$q.race([
primaryRequest(),
fallbackRequest()
]).then(function(result) {
// 最先返回的结果
});
10.4 辅助方法
// $q.resolve —— 创建 resolved Promise
$q.resolve('success value');
// $q.reject —— 创建 rejected Promise
$q.reject('error reason');
// $q.when —— 将值/Promise 包装为 Promise
$q.when(maybePromise).then(handler);
十一、$rootScope 事件 API
11.1 事件流向
$emit(冒泡)
子 scope ──► 父 scope ──► ... ──► $rootScope
$broadcast(广播)
$rootScope ──► 子 scope ──► 孙 scope ──► ...
11.2 生命周期事件
// $scope 生命周期事件
$scope.$on('$destroy', function() {
// scope 被销毁
});
// 路由事件
$scope.$on('$routeChangeStart', function(event, next, current) {
// 路由即将变化
});
$scope.$on('$routeChangeSuccess', function(event, current, previous) {
// 路由变化成功
});
$scope.$on('$routeChangeError', function(event, current, previous, rejection) {
// 路由变化失败
});
// 状态事件(ui-router)
$scope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {});
$scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {});
十二、$injector API
// 获取注入器实例
var $injector = angular.injector(['ng']);
// invoke:调用函数并自动注入依赖
$injector.invoke(function($http, $q) {
// $http 和 $q 被自动注入
});
// get:获取服务实例
var $http = $injector.get('$http');
// has:检查服务是否存在
$injector.has('$http'); // true
// annotate:获取函数的依赖列表
var fn = function($scope, $http) {};
$injector.annotate(fn); // ['$scope', '$http']
十三、API 速查总表
13.1 angular 全局函数
| 函数 | 返回值 | 说明 |
|---|---|---|
angular.module(name, [reqs]) |
Module | 创建/获取模块 |
angular.element(el) |
jqLite | 包装 DOM 元素 |
angular.bootstrap(el, mods) |
injector | 手动引导应用 |
angular.copy(src, [dst]) |
Object | 深拷贝 |
angular.extend(dst, ...srcs) |
Object | 浅合并 |
angular.merge(dst, ...srcs) |
Object | 深合并(1.4+) |
angular.equals(o1, o2) |
Boolean | 深度比较 |
angular.forEach(obj, fn, [ctx]) |
Object | 遍历 |
angular.isArray(val) |
Boolean | 是否数组 |
angular.isDate(val) |
Boolean | 是否日期 |
angular.isDefined(val) |
Boolean | 是否已定义 |
angular.isUndefined(val) |
Boolean | 是否未定义 |
angular.isElement(val) |
Boolean | 是否 DOM 元素 |
angular.isFunction(val) |
Boolean | 是否函数 |
angular.isNumber(val) |
Boolean | 是否数字 |
angular.isObject(val) |
Boolean | 是否对象 |
angular.isString(val) |
Boolean | 是否字符串 |
angular.lowercase(str) |
String | 转小写(已弃用) |
angular.uppercase(str) |
String | 转大写(已弃用) |
angular.noop() |
undefined | 空函数 |
angular.identity(val) |
val | 返回自身 |
angular.toJson(obj, [pretty]) |
String | 序列化 JSON |
angular.fromJson(str) |
Object | 反序列化 JSON |
13.2 $scope 方法
| 方法 | 说明 |
|---|---|
$watch(expr, fn, [deep]) |
监听变化 |
$watchCollection(expr, fn) |
监听集合变化 |
$apply([expr]) |
手动触发脏检查 |
$eval(expr, [locals]) |
在 scope 上执行表达式 |
$evalAsync(fn) |
异步执行(当前或下一周期) |
$on(name, fn) |
监听事件 |
$emit(name, data) |
向上冒泡事件 |
$broadcast(name, data) |
向下广播事件 |
$destroy() |
销毁 scope |
13.3 $http 快捷方法
| 方法 | 说明 |
|---|---|
$http.get(url, [config]) |
GET 请求 |
$http.post(url, data, [config]) |
POST 请求 |
$http.put(url, data, [config]) |
PUT 请求 |
$http.patch(url, data, [config]) |
PATCH 请求 |
$http.delete(url, [config]) |
DELETE 请求 |
$http.head(url, [config]) |
HEAD 请求 |
$http.jsonp(url, [config]) |
JSONP 请求 |
13.4 $location 方法
| 方法 | 说明 |
|---|---|
absUrl() |
完整 URL |
url([url]) |
获取/设置 path+search+hash |
path([path]) |
获取/设置路径 |
search([search]) |
获取/设置查询参数 |
hash([hash]) |
获取/设置哈希 |
protocol() |
协议 |
host() |
主机名 |
port() |
端口 |
replace() |
替换历史记录 |
state([state]) |
获取/设置 history state |
13.5 $q 方法
| 方法 | 说明 |
|---|---|
$q(resolveFn) |
创建 Promise |
$q.defer() |
创建 Deferred |
$q.all(promises) |
全部完成 |
$q.race(promises) |
竞速 |
$q.resolve(val) |
创建 resolved Promise |
$q.reject(reason) |
创建 rejected Promise |
$q.when(val) |
包装为 Promise |
十四、总结思维导图
AngularJS API
├── angular 全局函数
│ ├── 模块:module, bootstrap
│ ├── 元素:element (jqLite)
│ ├── 拷贝:copy, extend, merge
│ ├── 比较:equals
│ ├── 遍历:forEach
│ ├── 类型检查:isArray/isDate/isDefined/...
│ ├── 转换:lowercase/uppercase/toJson/fromJson
│ └── 工具:noop, identity
├── jqLite API
│ ├── 查找:find, children, parent, next, eq
│ ├── 类操作:addClass/removeClass/toggleClass/hasClass
│ ├── 属性:attr/removeAttr/prop
│ ├── CSS:css
│ ├── 内容:html/text/val
│ ├── DOM:append/prepend/after/before/remove/empty/clone
│ └── 事件:on/off/triggerHandler
├── $scope API
│ ├── 监听:$watch/$watchCollection
│ ├── 脏检查:$apply/$eval/$evalAsync/$digest
│ ├── 事件:$on/$emit/$broadcast
│ └── 生命周期:$destroy
├── 表单 API
│ ├── NgModelController:$validators/$asyncValidators/$setValidity/...
│ └── FormController:$valid/$invalid/$setPristine/$setSubmitted/...
├── $http API
│ ├── 快捷方法:get/post/put/patch/delete
│ ├── 配置:headers/params/timeout/transformRequest/...
│ └── 拦截器:request/requestError/response/responseError
├── $location API
│ └── absUrl/url/path/search/hash/protocol/host/port
├── $timeout / $interval
│ └── 自动 $apply / cancel
├── $filter API
│ └── currency/date/filter/json/limitTo/number/orderBy/lowercase/uppercase
├── $q API
│ ├── 创建:defer / 构造函数
│ ├── 链式:then/catch/finally
│ └── 批量:all/race
└── $injector API
└── invoke/get/has/annotate
以上内容系统覆盖了 AngularJS 的全局函数、jqLite、scope、表单控件、scope、表单控件、scope、表单控件、http、location、location、location、timeout/interval、interval、interval、filter、q、q、q、injector 等核心 API,可作为完整的开发参考手册使用。