在完成 AngularJS 入门应用(表单、列表渲染)后,进阶入门的核心是 “摆脱零散代码,建立工程化开发思维”—— 通过封装复用逻辑(服务)、扩展视图能力(自定义过滤器 / 指令)、实现页面跳转(路由)、优化表单处理等方式,让代码更具可维护性和扩展性。本文围绕 AngularJS 进阶阶段的高频知识点,结合实战案例拆解,帮你平稳过渡到工程化开发模式。
一、核心进阶:服务(Service)—— 封装复用逻辑
入门阶段,我们习惯将所有逻辑写在控制器中,但随着功能增多,会导致控制器臃肿、代码重复(如多个控制器都需要发送 Ajax 请求)。服务(Service)正是为解决 “逻辑复用” 而生,它是 AngularJS 中可注入的单例对象,可封装 Ajax 请求、数据缓存、工具方法等通用逻辑,供多个控制器调用。
1. 服务的核心特性
单例模式:服务在应用启动后只创建一次实例,后续调用均使用同一实例(适合缓存数据);
依赖注入:服务可通过参数注入到控制器、指令、其他服务中,无需手动创建实例;
职责单一:一个服务只负责一类逻辑(如HttpService专门处理 Ajax 请求,ToolService专门处理工具方法)。
2. 实战案例:封装 Ajax 请求服务
以 “统一处理 API 请求” 为例,封装HttpService,实现 “请求拦截、响应处理、错误统一提示” 功能,避免每个控制器重复写$http配置。
完整代码实现
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AngularJS进阶 - 服务封装</title>
<script src="https://apps.bdimg.com/libs/angular.js/1.8.2/angular.min.js"></script>
<style>
.container {
width: 600px;
margin: 50px auto;
padding: 20px;
border: 1px solid #eee;
border-radius: 8px;
}
.btn {
padding: 8px 16px;
border: none;
background: #4285f4;
color: white;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
}
.result {
margin-top: 20px;
padding: 15px;
background: #f9fafb;
border-radius: 4px;
white-space: pre-wrap;
font-size: 14px;
}
.error {
color: #e53935;
}
</style>
</head>
<body ng-app="advancedApp">
<div class="container" ng-controller="MainCtrl">
<h3>服务封装实战:统一API请求</h3>
<button class="btn" ng-click="getUserInfo()">获取用户信息</button>
<button class="btn" ng-click="getProductList()">获取商品列表</button>
live.f7ShRe.cN
live.gpxJyzX.coM
LIvE.GtyXdc.cN
LIVe.hAOJIecAr.cN
liVe.hJFwZX.cN
Live.HNlYlIb.cN
LiVE.hS-DoOR.cN
LIVe.HUAAoSportS.coM
LIvE.jiaMENg688.coM
liVE.JNyKf.coM
liVE.jOHzHoE.coM
livE.jqNV3c.cN
LiVe.JsHB56.coM.cN
liVE.KQcYWl.coM
livE.lvkeYUaNyI.coM
LivE.MXjGSWGLj.cN
LIVE.NHJ6Gb.cN
Live.NIl5Kf.cN
lIve.NxsAFE.coM.cN
lIvE.NzXYDP.cN
<div class="result" ng-if="result">
<span ng-if="!isError">请求成功:</span>
<span ng-if="isError" class="error">请求失败:</span>
{{ result }}
</div>
</div>
<script>
// 1. 创建应用模块
const advancedApp = angular.module('advancedApp', []);
// 2. 封装HttpService:统一处理Ajax请求
advancedApp.service('HttpService', function($http, $timeout) {
// 私有方法:处理请求参数(如添加token)
const handleParams = function(params) {
const defaultParams = {
token: localStorage.getItem('token') || '' // 从本地存储获取token
};
return Object.assign({}, defaultParams, params);
};
// 私有方法:统一错误提示
const handleError = function(error) {
let errorMsg = '网络错误,请重试!';
if (error.data && error.data.msg) {
errorMsg = error.data.msg; // 后端返回的错误信息
} else if (error.status === 401) {
errorMsg = '登录已过期,请重新登录!';
// 模拟跳转到登录页(实际项目用$location.path('/login'))
$timeout(() => alert('即将跳转到登录页'), 1000);
}
return errorMsg;
};
// 公有方法:GET请求
this.get = function(url, params = {}) {
return $http({
method: 'GET',
url: url,
params: handleParams(params), // 处理请求参数
headers: {
'Content-Type': 'application/json'
}
}).then(function(response) {
// 统一处理成功响应(如只返回data字段)
return response.data;
}).catch(function(error) {
// 统一处理错误
throw handleError(error);
});
};
// 公有方法:POST请求
this.post = function(url, data = {}) {
return $http({
method: 'POST',
url: url,
data: data,
params: handleParams(), // 处理URL参数(如token)
headers: {
'Content-Type': 'application/json'
}
}).then(function(response) {
return response.data;
}).catch(function(error) {
throw handleError(error);
});
};
});
// 3. 控制器:注入并使用HttpService
advancedApp.controller('MainCtrl', function($scope, HttpService) {
// 获取用户信息(调用HttpService的get方法)
$scope.getUserInfo = function() {
$scope.result = '';
HttpService.get('/api/user/info', { userId: 1001 })
.then(function(data) {
$scope.isError = false;
$scope.result = JSON.stringify(data, null, 2); // 格式化JSON显示
})
.catch(function(errorMsg) {
$scope.isError = true;
$scope.result = errorMsg;
});
};
// 获取商品列表(调用HttpService的get方法)
$scope.getProductList = function() {
$scope.result = '';
HttpService.get('/api/product/list', { page: 1, size: 5 })
.then(function(data) {
$scope.isError = false;
$scope.result = JSON.stringify(data, null, 2);
})
.catch(function(errorMsg) {
$scope.isError = true;
$scope.result = errorMsg;
});
};
});
</script>
</body>
</html>
3. 核心要点
依赖注入:控制器通过参数HttpService注入服务,AngularJS 自动创建服务实例(无需new关键字);
统一处理:服务中封装了 “参数添加 token、错误提示、响应格式处理” 等通用逻辑,控制器只需关注 “调用哪个接口、如何使用数据”,代码更简洁;
异常捕获:服务中通过catch捕获错误并抛出自定义提示,控制器中通过catch接收错误,避免全局错误未处理。
二、视图增强:自定义过滤器(Filter)—— 格式化数据
入门阶段我们用过 AngularJS 内置过滤器(如filter筛选、orderBy排序),但实际开发中常需自定义数据格式(如日期格式化、金额保留两位小数、状态文字转换)。自定义过滤器可实现 “数据格式化逻辑复用”,在视图中通过{{ 数据 | 过滤器名:参数 }}调用。
1. 自定义过滤器的核心语法
// 语法:模块.filter('过滤器名', function() {
// return function(输入数据, 可选参数1, 可选参数2) {
// // 处理数据并返回格式化后的结果
// };
// });
2. 实战案例:常用自定义过滤器集合
封装 “日期格式化、金额格式化、状态转换” 三个高频过滤器,供视图直接使用。
完整代码实现
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AngularJS进阶 - 自定义过滤器</title>
<script src="https://apps.bdimg.com/libs/angular.js/1.8.2/angular.min.js"></script>
<style>
.table {
width: 800px;
margin: 50px auto;
border-collapse: collapse;
text-align: left;
}
.table th, .table td {
padding: 12px 15px;
border-bottom: 1px solid #eee;
}
.table th {
background: #f9fafb;
font-weight: 600;
}
.status-success {
color: #43a047;
}
.status-pending {
color: #f57c00;
}
.status-failed {
color: #e53935;
}
</style>
</head>
<body ng-app="filterApp">
<table class="table" ng-controller="OrderCtrl">
<thead>
<tr>
<th>订单号</th>
<th>下单时间(格式化后)</th>
<th>订单金额(格式化后)</th>
<th>订单状态(转换后)</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="order in orders">
<td>{{ order.orderNo }}</td>
<!-- 日期格式化过滤器:dateFormat,参数为'yyyy-MM-dd HH:mm:ss' -->
<td>{{ order.createTime | dateFormat:'yyyy-MM-dd HH:mm:ss' }}</td>
<!-- 金额格式化过滤器:moneyFormat,参数为2(保留两位小数) -->
<td>{{ order.amount | moneyFormat:2 }}</td>
<!-- 状态转换过滤器:statusFilter,无参数 -->
<td>
<span ng-class="'status-' + (order.status | statusFilter:'class')">
{{ order.status | statusFilter }}
</span>
</td>
</tr>
</tbody>
</table>
<script>
const filterApp = angular.module('filterApp', []);
// 1. 自定义过滤器1:日期格式化(处理时间戳转日期字符串)
filterApp.filter('dateFormat', function() {
return function(timestamp, format = 'yyyy-MM-dd') {
if (!timestamp) return ''; // 空值处理
const date = new Date(timestamp); // 时间戳转Date对象(单位:毫秒)
// 提取日期组件
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份0-11,补0
const day = String(date.getDate()).padStart(2, '0');
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
const second = String(date.getSeconds()).padStart(2, '0');
// 替换格式字符串
return format.replace('yyyy', year)
.replace('MM', month)
.replace('dd', day)
.replace('HH', hour)
.replace('mm', minute)
.replace('ss', second);
};
});
// 2. 自定义过滤器2:金额格式化(保留小数位,添加千分位)
filterApp.filter('moneyFormat', function() {
return function(amount, decimal = 2) {
if (isNaN(amount)) return '0.00'; // 非数字处理
// 保留指定小数位
const fixedAmount = Number(amount).toFixed(decimal);
// 分割整数和小数部分
const [integerPart, decimalPart] = fixedAmount.split('.');
// 整数部分添加千分位(正则匹配)
const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
// 拼接结果
return decimal > 0 ? `${formattedInteger}.${decimalPart}` : formattedInteger;
};
});
// 3. 自定义过滤器3:状态转换(数字状态转文字/样式类)
filterApp.filter('statusFilter', function() {
// 状态映射表
const statusMap = {
0: { text: '待支付', class: 'pending' },
1: { text: '已支付', class: 'success' },
2: { text: '已取消', class: 'failed' },
3: { text: '已退款', class: 'failed' }
};
return function(status, type = 'text') {
const statusInfo = statusMap[status] || { text: '未知状态', class: '' };
return type === 'text' ? statusInfo.text : statusInfo.class;
};
});
// 控制器:提供订单数据
filterApp.controller('OrderCtrl', function($scope) {
$scope.orders = [
{ orderNo: '20240501001', createTime: 1714531200000, amount: 199.9, status: 1 },
{ orderNo: '20240501002', createTime: 1714532000000, amount: 2999, status: 0 },
{ orderNo: '20240501003', createTime: 1714533000000, amount: 59.5, status: 2 },
{ orderNo: '20240501004', createTime: 1714534000000, amount: 1250.8, status: 3 }
];
});
</script>
</body>
</html>
3. 核心要点
参数传递:过滤器支持多参数,在视图中通过:分隔(如moneyFormat:2表示传递参数2);
逻辑复用:将 “日期格式化” 等通用逻辑封装为过滤器,避免在多个控制器中重复写相同代码;
链式调用:过滤器支持链式使用(如{{ data | filter1 | filter2 }}),先执行filter1,再将结果传给filter2。
三、页面跳转:路由(angular-route)—— 实现多页面应用
入门阶段的应用多为 “单页面无跳转”,但实际项目需要多页面(如登录页、首页、详情页)。AngularJS 通过angular-route模块实现路由功能,核心是 “根据 URL 路径匹配对应的视图和控制器”,无需页面刷新即可实现跳转。
1. 路由的核心概念
路由模块:需额外引入angular-route.js(AngularJS 的官方路由模块);
路由配置:通过$routeProvider配置 “URL 路径→视图模板→控制器” 的映射关系;
视图占位符:通过ng-view指令标记视图渲染的位置(URL 匹配后,模板会插入到该位置)。
2. 实战案例:搭建多页面路由应用
实现 “登录页→首页→商品详情页” 的跳转逻辑,包含路由参数传递(如详情页接收商品 ID)。
完整代码实现
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AngularJS进阶 - 路由应用</title>
<!-- 1. 引入AngularJS核心库 -->
<script src="https://apps.bdimg.com/libs/angular.js/1.8.2/angular.min.js"></script>
<!-- 2. 引入angular-route路由模块(必须在核心库之后) -->
<script src="https://apps.bdimg.com/libs/angular-route/1.8.2/angular-route.min.js"></script>
<style>
.nav {
width: 8</doubaocanvas>