AngularJS API

AI3天前发布 beixibaobao
7 0 0

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、locationtimeout/interval、interval、intervalfilter、q、q、qinjector 等核心 API,可作为完整的开发参考手册使用。

© 版权声明

相关文章