AngularJS入门应用:从场景落地到能力拓展

在掌握AngularJS核心概念(模块、控制器、指令)后,入门应用的关键是“解决实际业务场景”——比如用户注册表单、数据列表加载、本地数据持久化等。本文以“高频应用场景”为核心,通过三个完整应用案例,带你掌握AngularJS在实际开发中的应用方法,同时梳理应用开发中的通用思路与避坑技巧。

一、应用场景1:用户注册表单(表单验证+数据提交)

表单是前端与用户交互的核心载体,AngularJS提供了完善的内置表单验证能力,无需大量手动JS代码,即可实现“必填项校验、格式校验、实时提示”等功能。以下以“用户注册表单”为例,落地表单应用开发。

1. 需求拆解

实现用户名、手机号、密码、确认密码的输入校验;

实时显示错误提示(如“用户名不能为空”“手机号格式错误”);

所有校验通过后,才能提交表单;

提交时显示加载状态,避免重复提交。

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>

        .form-container {

            width: 450px;

            margin: 50px auto;

            padding: 25px;

            border: 1px solid #eee;

            border-radius: 8px;

            box-shadow: 0 2px 10px rgba(0,0,0,0.05);

        }

        .form-title {

            margin-top: 0;

            margin-bottom: 20px;

            color: #333;

            text-align: center;

        }

        .form-group {

            margin-bottom: 20px;

        }

        .form-group label {

            display: block;

            margin-bottom: 8px;

            color: #666;

            font-size: 14px;

        }

        .form-control {

            width: 100%;

            padding: 10px;

            border: 1px solid #ddd;

            border-radius: 4px;

            font-size: 14px;

            box-sizing: border-box;

        }

        /* 输入框校验状态样式:成功(绿色边框)、错误(红色边框) */

        .form-control.ng-valid.ng-dirty {

            border-color: #43a047;

        }

        .form-control.ng-invalid.ng-dirty {

            border-color: #e53935;

        }

        .error-message {

            margin-top: 5px;

            color: #e53935;

            font-size: 12px;

            height: 16px; /* 固定高度,避免提示显示/隐藏时表单跳动 */

        }

        .submit-btn {

            width: 100%;

            padding: 12px;

            border: none;

            background: #4285f4;

            color: white;

            border-radius: 4px;

            font-size: 16px;

            cursor: pointer;

            transition: background 0.3s ease;

        }

        .submit-btn:disabled {

            background: #90caf9;

            cursor: not-allowed;

        }

        .submit-success {

            margin-top: 15px;

            padding: 10px;

            background: #e8f5e9;

            color: #2e7d32;

            border-radius: 4px;

            text-align: center;

            display: none;

        }

    </style>

</head>

<!-- 挂载AngularJS模块 -->

<body ng-app="registerApp">

    <div class="form-container" ng-controller="registerCtrl">

        <h3 class="form-title">用户注册</h3>


        <!-- 表单:ng-submit绑定提交事件,novalidate禁用浏览器默认验证 -->

        <form name="registerForm" ng-submit="submitForm()" novalidate>

            <!-- 用户名输入框 -->

            <div class="form-group">

                <label for="username">用户名 *</label>

                <input type="text"

                      id="username"

                      name="username"

                      class="form-control"

                      ng-model="user.username"

                      ng-required="true" <!-- 必填校验 -->

                      ng-minlength="3" <!-- 最小长度3 -->

                      ng-maxlength="16"> <!-- 最大长度16 -->


                <!-- 错误提示:根据不同校验结果显示不同信息 -->

                <div class="error-message">

                    <span ng-show="registerForm.username.$dirty && registerForm.username.$error.required">用户名不能为空</span>

                    <span ng-show="registerForm.username.$dirty && registerForm.username.$error.minlength">用户名至少3个字符</span>

                    <span ng-show="registerForm.username.$dirty && registerForm.username.$error.maxlength">用户名最多16个字符</span>

                </div>

            </div>


            <!-- 手机号输入框 -->

            <div class="form-group">

                <label for="phone">手机号 *</label>

zhiq.zhaopin.com/moment/86391611

zhiq.zhaopin.com/moment/86391621

zhiq.zhaopin.com/moment/86391629

zhiq.zhaopin.com/moment/86391638

zhiq.zhaopin.com/moment/86391675

zhiq.zhaopin.com/moment/86391696

zhiq.zhaopin.com/moment/86391700

zhiq.zhaopin.com/moment/86391702

zhiq.zhaopin.com/moment/86417690

zhiq.zhaopin.com/moment/86417943

zhiq.zhaopin.com/moment/86418006

zhiq.zhaopin.com/moment/86418083

zhiq.zhaopin.com/moment/86418152

zhiq.zhaopin.com/moment/86418206

zhiq.zhaopin.com/moment/86418366

zhiq.zhaopin.com/moment/86418682

zhiq.zhaopin.com/moment/86419393

zhiq.zhaopin.com/moment/86419459

zhiq.zhaopin.com/moment/86419610

zhiq.zhaopin.com/moment/86419708

                <input type="tel"

                      id="phone"

                      name="phone"

                      class="form-control"

                      ng-model="user.phone"

                      ng-required="true"

                      ng-pattern="/^1[3-9]\d{9}$/"> <!-- 手机号格式正则校验 -->


                <div class="error-message">

                    <span ng-show="registerForm.phone.$dirty && registerForm.phone.$error.required">手机号不能为空</span>

                    <span ng-show="registerForm.phone.$dirty && registerForm.phone.$error.pattern">请输入正确的11位手机号</span>

                </div>

            </div>


            <!-- 密码输入框 -->

            <div class="form-group">

                <label for="password">密码 *</label>

                <input type="password"

                      id="password"

                      name="password"

                      class="form-control"

                      ng-model="user.password"

                      ng-required="true"

                      ng-minlength="6"

                      ng-maxlength="20">


                <div class="error-message">

                    <span ng-show="registerForm.password.$dirty && registerForm.password.$error.required">密码不能为空</span>

                    <span ng-show="registerForm.password.$dirty && registerForm.password.$error.minlength">密码至少6个字符</span>

                    <span ng-show="registerForm.password.$dirty && registerForm.password.$error.maxlength">密码最多20个字符</span>

                </div>

            </div>


            <!-- 确认密码输入框 -->

            <div class="form-group">

                <label for="confirmPwd">确认密码 *</label>

                <input type="password"

                      id="confirmPwd"

                      name="confirmPwd"

                      class="form-control"

                      ng-model="user.confirmPwd"

                      ng-required="true"

                      ng-match="user.password"> <!-- 自定义指令:匹配密码 -->


                <div class="error-message">

                    <span ng-show="registerForm.confirmPwd.$dirty && registerForm.confirmPwd.$error.required">确认密码不能为空</span>

                    <span ng-show="registerForm.confirmPwd.$dirty && registerForm.confirmPwd.$error.match">两次输入的密码不一致</span>

                </div>

            </div>


            <!-- 提交按钮:表单验证通过(registerForm.$valid)且未加载时才启用 -->

            <button type="submit" class="submit-btn" ng-disabled="!registerForm.$valid || isSubmitting">

                <span ng-if="!isSubmitting">注册</span>

                <span ng-if="isSubmitting">注册中...</span>

            </button>


            <!-- 提交成功提示 -->

            <div class="submit-success" ng-show="submitSuccess">

                注册成功!即将跳转到登录页...

            </div>

        </form>

    </div>

    <script>

        // 1. 创建应用模块

        const registerApp = angular.module('registerApp', []);


        // 2. 自定义指令ngMatch:用于确认密码与密码匹配校验

        registerApp.directive('ngMatch', function() {

            return {

                require: 'ngModel', // 依赖ngModel指令

                scope: {

                    ngMatch: '=' // 绑定要匹配的目标值(这里是user.password)

                },

                link: function(scope, element, attrs, ngModel) {

                    // 监听目标值(密码)和当前值(确认密码)的变化,触发校验

                    scope.$watchGroup(['ngMatch', ngModel.$viewValue], function() {

                        ngModel.$setValidity('match', ngModel.$viewValue === scope.ngMatch);

                    });

                }

            };

        });


        // 3. 创建控制器

        registerApp.controller('registerCtrl', function($scope, $timeout) {

            // 初始化用户数据

            $scope.user = {

                username: '',

                phone: '',

                password: '',

                confirmPwd: ''

            };


            $scope.isSubmitting = false; // 提交加载状态

            $scope.submitSuccess = false; // 提交成功标记


            // 表单提交方法

            $scope.submitForm = function() {

                // 再次校验表单(防止绕过前端校验提交)

                if (!$scope.registerForm.$valid) {

                    // 若表单无效,触发所有输入框的脏值状态(显示错误提示)

                    angular.forEach($scope.registerForm.$error.required, function(field) {

                        field.$setDirty();

                    });

                    return;

                }


                // 显示加载状态

                $scope.isSubmitting = true;


                // 模拟API提交(实际项目中替换为$http请求)

                console.log('提交的用户数据:', $scope.user);


                // 模拟提交成功(2秒后)

                $timeout(function() {

                    $scope.isSubmitting = false;

                    $scope.submitSuccess = true;


                    // 模拟3秒后跳转(实际项目中用$location.path('/login'))

                    $timeout(function() {

                        alert('跳转到登录页');

                    }, 3000);

                }, 2000);

            };

        });

    </script>

</body>

</html>

3. 应用核心要点

内置表单验证指令:ng-required(必填)、ng-minlength(最小长度)、ng-maxlength(最大长度)、ng-pattern(正则匹配),无需手动写校验逻辑;

表单状态变量:AngularJS自动为表单和输入框添加状态变量(如$dirty:是否修改过、$valid:是否有效、$error:错误类型),可直接用于错误提示控制;

自定义指令扩展:通过ngMatch自定义指令实现“确认密码匹配”功能,体现AngularJS的扩展性;

防重复提交:用isSubmitting标记加载状态,禁用提交按钮,避免用户重复点击。

二、应用场景2:商品列表(Ajax数据请求+列表渲染)

实际应用中,数据通常来自后端API,AngularJS提供$http服务用于发送Ajax请求,结合ng-repeat可快速实现“数据加载→列表渲染→状态提示”的完整流程。以下以“商品列表”为例,落地数据请求类应用开发。

1. 需求拆解

页面加载时,发送请求获取商品数据;

加载过程中显示“加载中”提示;

加载失败时显示错误提示,支持重试;

加载成功后,用列表渲染商品(包含图片、名称、价格、销量);

支持按“价格升序/降序”筛选商品。

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>

        .product-container {

            width: 1200px;

            margin: 30px auto;

            padding: 20px;

            box-sizing: border-box;

        }

        .header {

            display: flex;

            justify-content: space-between;

            align-items: center;

            margin-bottom: 20px;

        }

        .filter-select {

            padding: 8px;

            border: 1px solid #ddd;

            border-radius: 4px;

            font-size: 14px;

        }

        .loading, .error {

            text-align: center;

            padding: 50px;

            color: #666;

        }

        .error {

            color: #e53935;

        }

        .retry-btn {

            padding: 8px 16px;

            border: none;

            background: #4285f4;

            color: white;

            border-radius: 4px;

            cursor: pointer;

            margin-top: 10px;

        }

        .product-list {

            display: flex;

            flex-wrap: wrap;

            gap: 20px;

        }

        .product-item {

            width: calc(25% - 15px);

            border: 1px solid #eee;

            border-radius: 8px;

            overflow: hidden;

            transition: box-shadow 0.3s ease;

        }

        .product-item:hover {

            box-shadow: 0 5px 15px rgba(0,0,0,0.08);

        }

        .product-img {

            width: 100%;

            height: 200px;

            object-fit: cover;

        }

        .product-info {

            padding: 15px;

        }

        .product-name {

            margin: 0 0 10px;

            font-size: 16px;

            color: #333;

            display: -webkit-box;

            -webkit-line-clamp: 2;

            -webkit-box-orient: vertical;

            overflow: hidden;

            height: 40px;

        }

        .product-price {

            margin: 0 0 5px;

            font-size: 18px;

            color: #e53935;

            font-weight: bold;

        }

        .product-sales {

            margin: 0;

            font-size: 12px;

            color: #999;

        }

        .no-data {

            text-align: center;

            padding: 50px;

            color: #999;

            width: 100%;

        }

    </style>

</head>

<body ng-app="productApp">

    <div class="product-container" ng-controller="productCtrl">

        <div class="header">

            <h2>商品列表</h2>

            <!-- 价格排序筛选 -->

            <select class="filter-select"

                    ng-model="sortType"

                    ng-change="sortProducts()">

                <option value="">默认排序</option>

                <option value="priceAsc">价格升序</option>

                <option value="priceDesc">价格降序</option>

            </select>

        </div>


        <!-- 加载中状态 -->

        <div class="loading" ng-show="isLoading">

            <div>加载中...</div>

        </div>


        <!-- 加载错误状态 -->

        <div class="error" ng-show="isError">

            <div>加载失败,请重试!</div>

            <button class="retry-btn" ng-click="loadProducts()">重试</button>

        </div>


        <!-- 商品列表 -->

        <div class="product-list" ng-show="!isLoading && !isError">

            <div class="product-item" ng-repeat="product in products">

                <img src="{{ product.imgUrl }}" alt="{{ product.name }}" class="product-img">

                <div class="product-info">

                    <h3 class="product-name">{{ product.name }}</h3>

                    <p class="product-price">¥{{ product.price.toFixed(2) }}</p>

                    <p class="product-sales">销量:{{ product.s</doubaocanvas>

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

相关阅读更多精彩内容

友情链接更多精彩内容