AngularJS实战开发:从0到1构建企业级后台管理系统

AngularJS作为经典前端框架,在企业级后台管理系统开发中应用广泛。实战开发的核心并非单纯堆砌技术,而是“以业务需求为导向,用合理技术解决实际问题”——从项目初始化搭建规范架构,到用户管理、数据表格、表单提交等核心功能落地,再到性能优化与上线部署,每一步都需兼顾“功能完整性、代码可维护性、用户体验”。本文以“电商后台管理系统”为案例,带您走完AngularJS项目开发全流程,掌握实战中的关键技术与避坑技巧。

一、实战准备:项目初始化与架构搭建

在写一行业务代码前,需先完成“环境配置、架构设计、基础封装”,这是保证项目长期可维护的前提。本案例基于AngularJS 1.8.x,结合Webpack 5构建工具,搭建标准化项目架构。

1. 环境配置与依赖安装

(1)初始化项目与安装核心依赖

# 1. 创建项目目录并初始化package.json

mkdir angularjs-ecommerce-admin && cd angularjs-ecommerce-admin

npm init -y

# 2. 安装核心依赖

# AngularJS核心库

npm install angular@1.8.3 --save

# 路由(替代原生路由,支持嵌套路由)

npm install angular-ui-router@1.0.30 --save

# HTTP请求拦截与辅助(可选,简化请求处理)

npm install angular-http-auth@1.5.3 --save

# UI组件库(可选,快速搭建界面,如AngularJS Material)

npm install angular-material@1.2.2 --save

# 3. 安装开发依赖(构建与调试)

# Webpack构建工具

npm install webpack@5.88.2 webpack-cli@5.1.4 webpack-dev-server@4.15.1 --save-dev

# Babel(处理ES6+语法兼容)

npm install @babel/core@7.22.9 @babel/preset-env@7.22.9 babel-loader@9.1.3 --save-dev

# HTML/CSS加载器

npm install html-loader@4.2.0 css-loader@6.8.1 style-loader@3.3.3 --save-dev

# 静态资源处理

npm install file-loader@6.2.0 url-loader@4.1.1 --save-dev

(2)Webpack配置(webpack.config.js)

核心配置目标:支持模块化开发、ES6+语法兼容、热更新调试、资源压缩

const path = require('path');

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 需额外安装:npm i html-webpack-plugin@5.5.3 -D

module.exports = {

  entry: './src/app/index.js', // 项目入口文件

  output: {

    path: path.resolve(__dirname, 'dist'), // 打包输出目录

    filename: 'js/[name].[contenthash].js', // 输出JS文件名(带哈希,避免缓存)

    clean: true // 每次打包清空dist目录

  },

  devtool: process.env.NODE_ENV === 'development' ? 'source-map' : 'hidden-source-map', // 开发环境生成source-map便于调试

  devServer: {

    port: 8080, // 开发服务器端口

    open: true, // 自动打开浏览器

    hot: true, // 热更新

    proxy: {

      // 接口代理(解决跨域问题)

      '/api': {

        target: 'http://localhost:3000', // 后端API地址

        changeOrigin: true,

        pathRewrite: { '^/api': '' } // 移除请求路径中的/api前缀

      }

    }

  },

  module: {

    rules: [

      // 处理JS文件:用Babel转换ES6+语法

      {

        test: /\.js$/,

        exclude: /node_modules/,

        use: {

          loader: 'babel-loader',

          options: {

            presets: ['@babel/preset-env']

          }

        }

      },

      // 处理CSS文件

      {

        test: /\.css$/,

        use: ['style-loader', 'css-loader']

      },

      // 处理HTML文件(作为模板引入)

      {

        test: /\.html$/,

        use: 'html-loader'

      },

      // 处理图片等静态资源

      {

        test: /\.(png|jpg|jpeg|gif|svg)$/,

        type: 'asset',

        parser: {

          dataUrlCondition: {

            maxSize: 8 * 1024 // 小于8KB的资源转base64,减少请求

          }

        },

        generator: {

          filename: 'assets/images/[name].[hash][ext]'

        }

      }

    ]

  },

  plugins: [

    // 生成HTML入口文件,自动引入打包后的JS/CSS

    new HtmlWebpackPlugin({

      template: './src/index.html', // 模板HTML路径

      filename: 'index.html',

      minify: process.env.NODE_ENV === 'production' ? {

        removeComments: true, // 移除注释

        collapseWhitespace: true // 压缩空格

      } : false

    })

  ],

  resolve: {

    // 配置模块别名,简化引入路径

    alias: {

      '@': path.resolve(__dirname, 'src'),

      'core': path.resolve(__dirname, 'src/core'),

zhiq.zhaopin.com/question/11490965

zhiq.zhaopin.com/question/11490966

zhiq.zhaopin.com/question/11490967

zhiq.zhaopin.com/question/11490970

zhiq.zhaopin.com/question/11490975

zhiq.zhaopin.com/question/11490976

zhiq.zhaopin.com/question/11490977

zhiq.zhaopin.com/question/11490981

zhiq.zhaopin.com/question/11490982

zhiq.zhaopin.com/question/11490983

zhiq.zhaopin.com/question/11490984

zhiq.zhaopin.com/question/11490985

zhiq.zhaopin.com/question/11490987

zhiq.zhaopin.com/question/11490989

zhiq.zhaopin.com/question/11490991

zhiq.zhaopin.com/question/11490993

zhiq.zhaopin.com/question/11490998

zhiq.zhaopin.com/question/11491000

zhiq.zhaopin.com/question/11491004

zhiq.zhaopin.com/question/11491005

      'business': path.resolve(__dirname, 'src/business')

    },

    // 配置可省略的文件后缀

    extensions: ['.js', '.html', '.css']

  }

};

(3)入口文件与基础模板

入口JS(src/app/index.js:初始化AngularJS模块,依赖核心模块与路由。

import angular from 'angular';

import 'angular-ui-router';

import 'angular-material';

import 'angular-material/angular-material.css'; // 引入UI组件库样式

// 引入核心模块(后续实现)

import coreModule from '@/core/core.module';

// 引入业务模块(后续实现,如用户模块、商品模块)

import userModule from '@/business/user/user.module';

import productModule from '@/business/product/product.module';

// 初始化应用主模块

const appModule = angular.module('ecommerceAdmin', [

  'ui.router', // 路由模块

  'ngMaterial', // UI组件库

  coreModule.name, // 核心模块

  userModule.name, // 用户业务模块

  productModule.name // 商品业务模块

]);

// 配置主路由(空白父路由,嵌套业务路由)

appModule.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {

  $stateProvider.state('app', {

    url: '/app',

    abstract: true, // 抽象路由,不可直接访问

    template: '<div ui-view></div>' // 子路由视图占位符

  });

  // 默认跳转登录页(未登录时)

  $urlRouterProvider.otherwise('/login');

}]);

// 应用启动钩子:初始化用户状态(如检查本地存储的登录信息)

appModule.run(['$rootScope', 'UserStateService', function($rootScope, UserStateService) {

  UserStateService.init(); // 初始化用户状态(后续实现)

  // 监听路由变化,判断是否需要登录

  $rootScope.$on('$stateChangeStart', function(event, toState) {

    const isLoginRequired = toState.data?.requireLogin ?? true; // 路由是否需要登录

    const isLoggedIn = UserStateService.getState().isLoggedIn; // 用户是否已登录

    if (isLoginRequired && !isLoggedIn) {

      event.preventDefault(); // 阻止当前路由跳转

      $rootScope.$state.go('login'); // 跳转到登录页

    }

  });

}]);

基础HTML模板(src/index.html:定义页面骨架,引入打包后的资源。

<!DOCTYPE html>

<html lang="zh-CN" ng-app="ecommerceAdmin">

<head>

  <meta charset="UTF-8">

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

  <title>电商后台管理系统</title>

  <!-- 引入第三方图标库(可选,如Font Awesome) -->

  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css">

</head>

<body>

  <!-- 路由视图占位符:所有页面内容将渲染到这里 -->

  <div ui-view></div>

</body>

</html>

二、核心功能实战:从登录到业务模块落地

后台管理系统的核心功能围绕“用户权限控制、数据管理、表单操作”展开。本节以“登录页”“用户列表页”“商品编辑页”三个高频场景为例,完整实现从前端交互到后端接口联调的全流程。

1. 场景1:用户登录(权限控制入口)

登录功能是后台系统的“第一道门”,需实现“表单验证、登录状态存储、路由拦截”三大核心逻辑。

(1)核心依赖封装:用户状态服务(src/core/services/UserStateService.js)

负责管理用户登录状态、token存储、权限判断,后续所有需登录的功能都依赖此服务。

import angular from 'angular';

export default angular.module('coreModule.userStateService', [])

  .factory('UserStateService', ['$rootScope', '$http', '$localStorage', function($rootScope, $http, $localStorage) {

    // 私有状态:存储用户信息、登录状态、token

    let state = {

      userInfo: $localStorage.userInfo || null, // 从本地存储恢复用户信息

      token: $localStorage.token || null, // 从本地存储恢复token

      isLoggedIn: !!$localStorage.token, // 是否已登录(根据token判断)

      isLoading: false // 登录/登出请求加载状态

    };

    // 公有方法

    const actions = {

      // 初始化用户状态(应用启动时调用)

      init: function() {

        // 若有token,设置HTTP请求头(所有请求携带token)

        if (state.token) {

          $http.defaults.headers.common['Authorization'] = `Bearer ${state.token}`;

        }

      },

      // 用户登录:参数为登录表单数据(username/password)

      login: function(loginData) {

        if (state.isLoading) return Promise.reject('正在登录中,请稍后');


        state.isLoading = true;

        return $http.post('/api/auth/login', loginData)

          .then(response => {

            const { userInfo, token } = response.data;

            // 更新状态

            state.userInfo = userInfo;

            state.token = token;

            state.isLoggedIn = true;

            state.isLoading = false;

            // 存储到本地存储(持久化,刷新页面不丢失)

            $localStorage.userInfo = userInfo;

            $localStorage.token = token;

            // 设置HTTP请求头(后续请求自动携带token)

            $http.defaults.headers.common['Authorization'] = `Bearer ${token}`;

            // 触发登录成功事件(通知其他组件更新视图,如导航栏)

            $rootScope.$broadcast('user:login:success', userInfo);

            return userInfo;

          })

          .catch(error => {

            state.isLoading = false;

            // 统一处理登录错误(如账号密码错误、服务器异常)

            const errorMsg = error.data?.errorMsg || '登录失败,请重试';

            $rootScope.$broadcast('user:login:fail', errorMsg);

            return Promise.reject(errorMsg);

          });

      },

      // 用户登出:清除状态与本地存储

      logout: function() {

        if (state.isLoading) return Promise.reject('正在登出中,请稍后');


        state.isLoading = true;

        return $http.post('/api/auth/logout')

          .finally(() => {

            // 无论登出API是否成功,都清除状态

            state.userInfo = null;

            state.token = null;

            state.isLoggedIn = false;

            state.isLoading = false;

            // 清除本地存储

            delete $localStorage.userInfo;

            delete $localStorage.token;

            // 清除HTTP请求头

            delete $http.defaults.headers.common['Authorization'];

            // 触发登出成功事件

            $rootScope.$broadcast('user:logout:success');

          });

      },

      // 获取当前用户状态(对外提供只读副本,避免外部直接修改)

      getState: function() {

        return angular.copy(state);

      }

    };

    return actions;

  }])

  .name; // 导出模块名,供核心模块依赖

(2)登录控制器与视图

登录控制器(src/business/auth/controllers/LoginCtrl.js:处理登录表单交互逻辑。

import angular from 'angular';

import loginTemplate from '../views/login.html'; // 引入登录视图模板

export default angular.module('authModule.loginCtrl', [])

  .controller('LoginCtrl', ['$scope', '$state', 'UserStateService', function($scope, $state, UserStateService) {

    // 登录表单数据初始化

    $scope.loginForm = {

      username: '',

      password: ''

    };

    // 表单验证错误信息

    $scope.errorMsg = '';

    // 加载状态(控制按钮禁用与加载动画)

    $scope.isLoading = false;

    // 监听用户状态服务的加载状态

    $scope.$watch(() => UserStateService.getState().isLoading, function(isLoading) {

      $scope.isLoading = isLoading;

    });

    // 监听登录失败事件(来自UserStateService)

    $scope.$on('user:login:fail', function(event, errorMsg) {

      $scope.errorMsg = errorMsg;

    });

    // 登录提交方法

    $scope.submitLogin = function() {

      // 表单前端验证(避免空账号/密码提交)

      if (!$scope.loginForm.username.trim()) {

        $scope.errorMsg = '请输入用户名';

        return;

      }

      if (!$scope.loginForm.password.trim()) {

        $scope.errorMsg = '请输入密码';

        return;

      }

      // 调用用户状态服务的登录方法

      UserStateService.login($scope.loginForm)

        .then(() => {

          // 登录成功,跳转到首页

          $state.go('app.dashboard');

        })

        .catch(errorMsg => {

          $scope.errorMsg = errorMsg;

        });

    };

  }])

  // 配置登录路由

  .config(['$stateProvider', function($stateProvider) {

    $stateProvider.state('login', {

      url: '/login',

      template: loginTemplate,

      controller: 'LoginCtrl',

      data: {

        requireLogin: false // 登录页不需要登录权限

      }

    });

  }])

  .name;

登录视图(src/business/auth/views/login.html:基于AngularJS Material实现简洁登录界面。

<div layout="row" layout-align="center center" style="height: 100vh; background: #f5f5f5;">

  <md-card style="width: 400px; padding: 24px;">

    <md-card-title>

      <md-card-title-text>

        <h2 class="md-display-1">电商后台登录</h2>

      </md-card-title-text>

    </md-card-title>

    <md-card-content>

      <!-- 登录表单 -->

      <form name="loginForm" novalidate>

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

        <md-input-container class="md-block">

          <label>用户名</label>

          <input type="text" ng-model="loginForm.username" required>

          <div ng-messages="loginForm.username.$error" ng-if="loginForm.username.$touched">

            <div ng-message="required">请输入用户名</div>

          </div>

        </md-input-container>

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

        <md-input-container class="md-block">

          <label>密码</label>

          <input type="password" ng-model="loginForm.password" required>

          <div ng-messages="loginForm.password.$error" ng-if="loginForm.password.$touched">

            <div ng-message="required">请输入密码</div>

          </div>

        </md-input-container>

        <!-- 错误提示(如账号密码错误</doubaocanvas>

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

相关阅读更多精彩内容

友情链接更多精彩内容