AngularJS 1.3 完整教程
什么是 AngularJS?
AngularJS 是一个由 Google 维护的开源 JavaScript 框架,它通过引入 MVC(Model-View-Controller) 架构模式来简化单页应用的开发,它的核心思想是:

- 数据绑定:自动同步 JavaScript 中的数据(Model)和 HTML 中的展示(View)。
- 依赖注入:一种设计模式,使得组件之间的解耦变得更容易,代码更易于测试和维护。
- 指令:允许你创建自定义的 HTML 标签和属性,扩展 HTML 的功能。
为什么是 AngularJS 1.3?
虽然 AngularJS 已经发展到了 2+ 版本(并重写为 TypeScript),但 1.3 版本因其成熟、稳定和庞大的社区生态,对于学习前端框架的基本思想或维护旧项目来说,仍然是一个非常好的起点。
准备工作
- 文本编辑器:推荐使用 Visual Studio Code, Sublime Text 或 Atom。
- 现代浏览器:推荐使用 Chrome 或 Firefox,它们有强大的开发者工具。
- 一个 HTML 文件:我们将在这个文件中编写所有代码。
第一部分:入门基础
引入 AngularJS
在 HTML 文件的 <head> 或 <body> 标签内,通过 <script> 标签引入 AngularJS 的库文件,你可以从 AngularJS 官网 下载,或者使用 CDN(推荐)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">AngularJS 1.3 教程</title>
<!-- 引入 AngularJS 1.3.20 版本 -->
<script src="https://code.angularjs.org/1.3.20/angular.min.js"></script>
</head>
<body>
</body>
</html>
核心概念:ng-app 和 ng-model
AngularJS 应用总是通过一个 ng-app 指令来启动的,它告诉 AngularJS:“嘿,你负责管理这个 <div> 或 <body> 里面的所有东西。”
ng-model 指令用于将 HTML 元素(如输入框)与一个变量进行双向数据绑定。

示例:数据绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">AngularJS 1.3 教程 - Hello World</title>
<script src="https://code.angularjs.org/1.3.20/angular.min.js"></script>
</head>
<body>
<!-- 1. 声明一个 AngularJS 应用,并指定一个控制器 -->
<div ng-app="myApp" ng-controller="myCtrl">
<!-- 2. 使用 ng-model 将输入框的值绑定到 name 变量 -->
<p>请输入你的名字:</p>
<input type="text" ng-model="name">
<!-- 3. {{ name }} 是 AngularJS 的表达式,它会自动显示 name 变量的值 -->
<p>你好, <strong>{{ name }}</strong>!</p>
</div>
<script>
// 4. 获取你的应用模块
var app = angular.module('myApp', []);
// 5. 定义控制器 myCtrl
app.controller('myCtrl', function($scope) {
// $scope 是控制器和视图之间的桥梁
// 在这里初始化 name 变量
$scope.name = "AngularJS";
});
</script>
</body>
</html>
代码解析:
ng-app="myApp": 定义了一个名为 "myApp" 的 AngularJS 应用。ng-controller="myCtrl": 将这个<div>的控制权交给名为 "myCtrl" 的控制器。ng-model="name": 将输入框的值与$scope对象上的name属性绑定。{{ name }}: AngularJS 表达式,用于在页面上显示$scope.name的值,当你输入时,它会实时更新。angular.module('myApp', []): 创建或获取一个应用模块。[]表示它没有依赖其他模块。app.controller('myCtrl', function($scope) { ... }): 定义控制器。$scope: 这是 AngularJS 的核心对象,它是连接控制器和视图的“胶水”,在控制器中定义的所有属性和方法都会被附加到$scope上,从而在视图中可用。
第二部分:核心指令详解
ng-init (初始化数据)
ng-init 用于在作用域内初始化变量,虽然它很方便,但在实际开发中,推荐在控制器中初始化数据,以保持逻辑的清晰。
<div ng-app="myApp" ng-controller="myCtrl" ng-init="firstName='John', lastName='Doe'">
<p>姓名: {{ firstName + " " + lastName }}</p>
</div>
ng-repeat (循环数组/对象)
这是最常用的指令之一,用于循环渲染一个列表。

<div ng-app="myApp" ng-controller="namesCtrl">
<ul>
<!-- 循环 names 数组,为每个元素创建一个 <li> -->
<li ng-repeat="x in names">
{{ x.name + ', ' + x.country }}
</li>
</ul>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('namesCtrl', function($scope) {
$scope.names = [
{name:'Jani',country:'Norway'},
{name:'Hege',country:'Sweden'},
{name:'Kai',country:'Denmark'}
];
});
</script>
ng-repeat 中的特殊变量:
$index: 当前元素的索引 (0, 1, 2, ...)。$first: 是否为第一个元素 (true/false)。$middle: 是否为中间元素 (true/false)。$last: 是否为最后一个元素 (true/false)。
<li ng-repeat="x in names">
#{{$index+1}}: {{ x.name }}
<span ng-if="$last">(最后一个)</span>
</li>
ng-if vs ng-show / ng-hide
这三个指令都用于控制元素的显示和隐藏,但原理不同。
-
ng-if="true/false":- 原理:它会根据表达式的值,从 DOM 中完全添加或移除 元素。
- 特点:如果为
false,元素及其所有子元素和事件监听器都会被销毁,当变为true时,会重新创建和初始化,性能开销较大,但适合条件不频繁变化的场景。
-
ng-show="true/false":- 原理:它不会移除元素,而是通过 CSS 的
display: none;来隐藏元素。 - 特点:元素始终存在于 DOM 中,只是看不见,性能开销小,适合需要频繁切换显示/隐藏的场景。
- 原理:它不会移除元素,而是通过 CSS 的
-
ng-hide="true/false":- 原理:与
ng-show相反,它通过display: none;来显示元素(当表达式为false时)。
- 原理:与
示例:
<div ng-app="myApp" ng-controller="toggleCtrl">
<button ng-click="showIt = !showIt">切换显示</button>
<p ng-if="showIt">这个段落用 ng-if 控制,看不见时会被移除。</p>
<p ng-show="showIt">这个段落用 ng-show 控制,看不见时只是隐藏。</p>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('toggleCtrl', function($scope) {
$scope.showIt = true;
});
</script>
第三部分:控制器与作用域
控制器
控制器是 JavaScript 构造函数,用于向 $scope 添加功能(属性和方法)。
最佳实践:
- 保持控制器精简:控制器只负责初始化数据和暴露行为给视图。
- 将业务逻辑移至服务中:复杂的逻辑、数据访问、API 调用等应该放在 服务 中。
作用域
作用域是视图和控制器之间的数据桥梁,理解作用域的继承关系至关重要。
- 根作用域:由
ng-app创建,是所有$scope的祖先。 - 子作用域:当在父元素内部使用
ng-controller时,会创建一个子作用域,它会继承父作用域的属性。
示例:作用域继承
<div ng-app="myApp">
<!-- 根作用域 -->
<h1>根作用域的变量: {{ parentVar }}</h1>
<!-- parentCtrl 的作用域是根作用域的子作用域 -->
<div ng-controller="parentCtrl">
<h2>父控制器作用域</h2>
<p>可以访问父变量: {{ parentVar }}</p>
<p>自己的变量: {{ childVar }}</p>
<button ng-click="parentFunc()">调用父控制器方法</button>
</div>
<!-- anotherCtrl 的作用域也是根作用域的子作用域,与 parentCtrl 平级 -->
<div ng-controller="anotherCtrl">
<h2>另一个控制器作用域</h2>
<p>可以访问父变量: {{ parentVar }}</p>
<p>这个控制器有自己的变量: {{ anotherVar }}</p>
<!-- 这个按钮会报错,因为 anotherCtrl 没有 parentFunc -->
<button ng-click="parentFunc()">调用父控制器方法 (会报错)</button>
</div>
</div>
<script>
var app = angular.module('myApp', []);
// 在根作用域上添加一个属性
app.run(function($rootScope) {
$rootScope.parentVar = "我是根作用域的变量";
});
app.controller('parentCtrl', function($scope) {
$scope.childVar = "我是父控制器的变量";
$scope.parentFunc = function() {
alert("父控制器的方法被调用了!");
};
});
app.controller('anotherCtrl', function($scope) {
$scope.anotherVar = "我是另一个控制器的变量";
});
</script>
第四部分:服务
服务是 AngularJS 中一个核心的单例对象,通过依赖注入 系统来使用,它们非常适合用来存放共享的数据、工具函数或与后端 API 交互的逻辑。
内置服务
AngularJS 提供了许多内置服务,如 $http (AJAX 请求), $timeout (延迟), $interval (定时器) 等,使用时,只需在控制器的函数参数中声明它们,AngularJS 会自动注入。
示例:使用 $http 服务获取数据
<div ng-app="myApp" ng-controller="httpCtrl">
<ul>
<li ng-repeat="user in users">
{{ user.name }} - {{ user.email }}
</li>
</ul>
<p ng-if="loading">加载中...</p>
<p ng-if="error">{{ error }}</p>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('httpCtrl', function($scope, $http) {
$scope.loading = true;
$scope.error = null;
// 使用 $http 服务从 JSONPlaceholder 获取模拟数据
$http.get('https://jsonplaceholder.typicode.com/users')
.then(function(response) {
// 成功回调
$scope.users = response.data;
$scope.loading = false;
}, function(error) {
// 失败回调
$scope.error = "无法获取数据: " + error.statusText;
$scope.loading = false;
});
});
</script>
创建自定义服务
你可以创建自己的服务来封装特定功能。
<div ng-app="myApp" ng-controller="mainCtrl">
<p>{{ currentTime }}</p>
</div>
<script>
var app = angular.module('myApp', []);
// 创建一个名为 'timeService' 的自定义服务
app.service('timeService', function() {
this.getTime = function() {
return new Date().toString();
};
});
// 在控制器中注入并使用这个服务
app.controller('mainCtrl', function($scope, timeService) {
$scope.currentTime = timeService.getTime();
});
</script>
第五部分:路由
单页应用通常需要在不刷新整个页面的情况下切换视图,AngularJS 1.3 的核心模块不包含路由功能,你需要引入 angular-route.js 模块。
-
引入
angular-route.js<script src="https://code.angularjs.org/1.3.20/angular-route.min.js"></script>
-
配置路由
<!DOCTYPE html> <html lang="en" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>AngularJS 路由示例</title> <script src="https://code.angularjs.org/1.3.20/angular.min.js"></script> <script src="https://code.angularjs.org/1.3.20/angular-route.min.js"></script> </head> <body> <!-- 导航链接 --> <a href="#/">首页</a> <a href="#/about">lt;/a> <!-- ng-view 是一个占位符,匹配的模板会被加载到这里 --> <div ng-view></div> <script> var app = angular.module('myApp', ['ngRoute']); // 依赖 'ngRoute' 模块 // 配置路由 app.config(function($routeProvider) { $routeProvider .when('/', { templateUrl: 'home.html', // 指向视图模板 controller: 'homeCtrl' // 指向控制器 }) .when('/about', { templateUrl: 'about.html', controller: 'aboutCtrl' }) .otherwise({ // 其他所有请求都重定向到首页 redirectTo: '/' }); }); // 首页控制器 app.controller('homeCtrl', function($scope) { $scope.message = "欢迎来到首页!"; }); // 关于页面控制器 app.controller('aboutCtrl', function($scope) { $scope.message = "这是关于我们页面。"; }); </script> </body> </html>
你需要创建两个 HTML 文件:
-
home.html:<h2>首页</h2> <p>{{ message }}</p> -
about.html:<h2>关于我们</h2> <p>{{ message }}</p>
第六部分:创建自定义指令
自定义指令是 AngularJS 最强大的特性之一,它允许你创建可重用的 UI 组件。
示例:创建一个显示当前时间的指令
<div ng-app="myApp">
<!-- 使用自定义指令 -->
<my-current-time></my-current-time>
</div>
<script>
var app = angular.module('myApp', []);
app.directive('myCurrentTime', function($interval, dateFilter) {
// 返回指令的定义对象
return {
// E: Element (元素名) <my-current-time></my-current-time>
// A: Attribute (属性名) <div my-current-time></div>
// C: Class (类名) <div class="my-current-time"></div>
// M: Comment (注释) <!-- directive: my-current-time -->
restrict: 'E',
// scope: true, // 创建一个子作用域,隔离外部作用域
template: '<span>当前时间是: {{ time }}</span>',
link: function(scope, element, attrs) {
var format = 'HH:mm:ss';
var update_time = function() {
scope.time = dateFilter(new Date(), format);
};
// 立即更新一次
update_time();
// 每秒更新一次
var interval_id = $interval(update_time, 1000);
// 当指令作用域被销毁时,清除定时器,防止内存泄漏
scope.$on('$destroy', function() {
$interval.cancel(interval_id);
});
}
};
});
</script>
第七部分:最佳实践与总结
-
命名约定:
- 模块名:
myApp,userApp(小写,可以加点号) - 控制器名:
myCtrl,userListCtrl(驼峰命名) - 服务名:
userService,dataService(驼峰命名) - 指令名:
myDirective,userAvatar(驼峰命名,在 HTML 中使用时用 分隔,如my-directive)
- 模块名:
-
模块化: 将你的应用拆分成多个模块,每个模块负责一个功能区域。
-
控制器: 保持控制器“瘦”,只做
$scope的初始化和视图交互。 -
服务: 将业务逻辑、数据访问、工具函数都放到服务中。
-
依赖注入: 始终使用数组形式的语法来声明依赖,这样可以避免代码压缩后因变量名改变而出错。
// 不推荐 (压缩后会报错) app.controller('myCtrl', function($scope, $http) { ... }); // 推荐 (安全) app.controller('myCtrl', ['$scope', '$http', function($scope, $http) { ... }]); -
性能优化:
- 合理使用
ng-if和ng-show。 - 对于大型列表,考虑使用
track by来提高ng-repeat的性能。<li ng-repeat="item in items track by item.id">
- 使用
$watch的第三个参数 (objectEquality) 要谨慎,因为它开销很大。
- 合理使用
这份教程涵盖了 AngularJS 1.3 的核心概念,通过学习和实践这些内容,你将能够构建功能完善的单页应用,AngularJS 1.3 虽然有些年头,但其核心思想(数据绑定、依赖注入、指令)深刻影响了后来的前端框架,学习它对理解现代前端开发非常有帮助。
