AngularJS入門應(yīng)用:從場景落地到能力拓展

在掌握AngularJS核心概念(模塊、控制器、指令)后,入門應(yīng)用的關(guān)鍵是“解決實際業(yè)務(wù)場景”——比如用戶注冊表單、數(shù)據(jù)列表加載、本地數(shù)據(jù)持久化等。本文以“高頻應(yīng)用場景”為核心,通過三個完整應(yīng)用案例,帶你掌握AngularJS在實際開發(fā)中的應(yīng)用方法,同時梳理應(yīng)用開發(fā)中的通用思路與避坑技巧。

一、應(yīng)用場景1:用戶注冊表單(表單驗證+數(shù)據(jù)提交)

表單是前端與用戶交互的核心載體,AngularJS提供了完善的內(nèi)置表單驗證能力,無需大量手動JS代碼,即可實現(xiàn)“必填項校驗、格式校驗、實時提示”等功能。以下以“用戶注冊表單”為例,落地表單應(yīng)用開發(fā)。

1. 需求拆解

實現(xiàn)用戶名、手機號、密碼、確認(rèn)密碼的輸入校驗;

實時顯示錯誤提示(如“用戶名不能為空”“手機號格式錯誤”);

所有校驗通過后,才能提交表單;

提交時顯示加載狀態(tài),避免重復(fù)提交。

2. 完整應(yīng)用代碼

<!DOCTYPE html>

<html lang="zh-CN">

<head>

? ? <meta charset="UTF-8">

? ? <meta name="viewport" content="width=device-width, initial-scale=1.0">

? ? <title>AngularJS入門應(yīng)用 - 用戶注冊表單</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;

? ? ? ? }

? ? ? ? /* 輸入框校驗狀態(tài)樣式:成功(綠色邊框)、錯誤(紅色邊框) */

? ? ? ? .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禁用瀏覽器默認(rèn)驗證 -->

? ? ? ? <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 -->


? ? ? ? ? ? ? ? <!-- 錯誤提示:根據(jù)不同校驗結(jié)果顯示不同信息 -->

? ? ? ? ? ? ? ? <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>


? ? ? ? ? ? <!-- 確認(rèn)密碼輸入框 -->

? ? ? ? ? ? <div class="form-group">

? ? ? ? ? ? ? ? <label for="confirmPwd">確認(rèn)密碼 *</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">確認(rèn)密碼不能為空</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">

? ? ? ? ? ? ? ? 注冊成功!即將跳轉(zhuǎn)到登錄頁...

? ? ? ? ? ? </div>

? ? ? ? </form>

? ? </div>

? ? <script>

? ? ? ? // 1. 創(chuàng)建應(yīng)用模塊

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


? ? ? ? // 2. 自定義指令ngMatch:用于確認(rèn)密碼與密碼匹配校驗

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

? ? ? ? ? ? return {

? ? ? ? ? ? ? ? require: 'ngModel', // 依賴ngModel指令

? ? ? ? ? ? ? ? scope: {

? ? ? ? ? ? ? ? ? ? ngMatch: '=' // 綁定要匹配的目標(biāo)值(這里是user.password)

? ? ? ? ? ? ? ? },

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

? ? ? ? ? ? ? ? ? ? // 監(jiān)聽目標(biāo)值(密碼)和當(dāng)前值(確認(rèn)密碼)的變化,觸發(fā)校驗

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

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

? ? ? ? ? ? ? ? ? ? });

? ? ? ? ? ? ? ? }

? ? ? ? ? ? };

? ? ? ? });


? ? ? ? // 3. 創(chuàng)建控制器

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

? ? ? ? ? ? // 初始化用戶數(shù)據(jù)

? ? ? ? ? ? $scope.user = {

? ? ? ? ? ? ? ? username: '',

? ? ? ? ? ? ? ? phone: '',

? ? ? ? ? ? ? ? password: '',

? ? ? ? ? ? ? ? confirmPwd: ''

? ? ? ? ? ? };


? ? ? ? ? ? $scope.isSubmitting = false; // 提交加載狀態(tài)

? ? ? ? ? ? $scope.submitSuccess = false; // 提交成功標(biāo)記


? ? ? ? ? ? // 表單提交方法

? ? ? ? ? ? $scope.submitForm = function() {

? ? ? ? ? ? ? ? // 再次校驗表單(防止繞過前端校驗提交)

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

? ? ? ? ? ? ? ? ? ? // 若表單無效,觸發(fā)所有輸入框的臟值狀態(tài)(顯示錯誤提示)

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

? ? ? ? ? ? ? ? ? ? ? ? field.$setDirty();

? ? ? ? ? ? ? ? ? ? });

? ? ? ? ? ? ? ? ? ? return;

? ? ? ? ? ? ? ? }


? ? ? ? ? ? ? ? // 顯示加載狀態(tài)

? ? ? ? ? ? ? ? $scope.isSubmitting = true;


? ? ? ? ? ? ? ? // 模擬API提交(實際項目中替換為$http請求)

? ? ? ? ? ? ? ? console.log('提交的用戶數(shù)據(jù):', $scope.user);


? ? ? ? ? ? ? ? // 模擬提交成功(2秒后)

? ? ? ? ? ? ? ? $timeout(function() {

? ? ? ? ? ? ? ? ? ? $scope.isSubmitting = false;

? ? ? ? ? ? ? ? ? ? $scope.submitSuccess = true;


? ? ? ? ? ? ? ? ? ? // 模擬3秒后跳轉(zhuǎn)(實際項目中用$location.path('/login'))

? ? ? ? ? ? ? ? ? ? $timeout(function() {

? ? ? ? ? ? ? ? ? ? ? ? alert('跳轉(zhuǎn)到登錄頁');

? ? ? ? ? ? ? ? ? ? }, 3000);

? ? ? ? ? ? ? ? }, 2000);

? ? ? ? ? ? };

? ? ? ? });

? ? </script>

</body>

</html>

3. 應(yīng)用核心要點

內(nèi)置表單驗證指令:ng-required(必填)、ng-minlength(最小長度)、ng-maxlength(最大長度)、ng-pattern(正則匹配),無需手動寫校驗邏輯;

表單狀態(tài)變量:AngularJS自動為表單和輸入框添加狀態(tài)變量(如$dirty:是否修改過、$valid:是否有效、$error:錯誤類型),可直接用于錯誤提示控制;

自定義指令擴展:通過ngMatch自定義指令實現(xiàn)“確認(rèn)密碼匹配”功能,體現(xiàn)AngularJS的擴展性;

防重復(fù)提交:用isSubmitting標(biāo)記加載狀態(tài),禁用提交按鈕,避免用戶重復(fù)點擊。

二、應(yīng)用場景2:商品列表(Ajax數(shù)據(jù)請求+列表渲染)

實際應(yīng)用中,數(shù)據(jù)通常來自后端API,AngularJS提供$http服務(wù)用于發(fā)送Ajax請求,結(jié)合ng-repeat可快速實現(xiàn)“數(shù)據(jù)加載→列表渲染→狀態(tài)提示”的完整流程。以下以“商品列表”為例,落地數(shù)據(jù)請求類應(yīng)用開發(fā)。

1. 需求拆解

頁面加載時,發(fā)送請求獲取商品數(shù)據(jù);

加載過程中顯示“加載中”提示;

加載失敗時顯示錯誤提示,支持重試;

加載成功后,用列表渲染商品(包含圖片、名稱、價格、銷量);

支持按“價格升序/降序”篩選商品。

2. 完整應(yīng)用代碼

<!DOCTYPE html>

<html lang="zh-CN">

<head>

? ? <meta charset="UTF-8">

? ? <meta name="viewport" content="width=device-width, initial-scale=1.0">

? ? <title>AngularJS入門應(yīng)用 - 商品列表</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="">默認(rèn)排序</option>

? ? ? ? ? ? ? ? <option value="priceAsc">價格升序</option>

? ? ? ? ? ? ? ? <option value="priceDesc">價格降序</option>

? ? ? ? ? ? </select>

? ? ? ? </div>


? ? ? ? <!-- 加載中狀態(tài) -->

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

? ? ? ? ? ? <div>加載中...</div>

? ? ? ? </div>


? ? ? ? <!-- 加載錯誤狀態(tài) -->

? ? ? ? <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>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容