AngularJS 进阶入门:从基础到工程化开发

在完成 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>

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容