AngularJS实战应用:电商后台核心业务场景落地方案

在完成AngularJS项目初始化与基础功能搭建后,实战应用的核心是“解决业务场景中的具体问题”——比如电商后台的商品数据表格需支持筛选、排序、批量操作,商品编辑表单需处理动态规格字段,不同角色用户需看到不同功能菜单。本文基于已搭建的电商后台框架,深入三大核心实战场景,提供“需求分析-技术实现-优化避坑”的全流程方案,帮你掌握AngularJS在实际业务中的应用技巧。

一、实战场景1:商品数据表格——支持筛选、排序与批量操作

商品管理是电商后台的核心模块,数据表格作为“数据展示与操作入口”,需满足“高效查询、便捷操作、性能稳定”三大需求。本场景将基于AngularJS Material的md-table组件,实现支持多条件筛选、字段排序、批量删除/上架的商品表格。

1. 需求拆解

数据展示:展示商品ID、名称、分类、价格、库存、状态(上架/下架)、操作按钮;

筛选功能:支持按商品名称模糊搜索、按分类下拉筛选、按状态(上架/下架)筛选;

排序功能:支持按价格(升序/降序)、库存(升序/降序)点击表头排序;

批量操作:支持勾选商品后批量删除、批量上架/下架;

性能优化:表格数据分页加载(默认10条/页),避免大数据量渲染卡顿。

2. 技术实现方案

(1)核心服务封装:商品数据服务(ProductService)

负责商品数据的获取、筛选、排序、批量操作,隔离数据逻辑与视图逻辑,便于后续维护。

// src/business/product/services/ProductService.js

import angular from 'angular';

export default angular.module('productModule.productService', [])

  .factory('ProductService', ['$http', function($http) {

    // 私有工具方法:处理数据筛选(多条件组合)

    const filterProducts = (products, filters) => {

      return products.filter(product => {

        // 商品名称模糊匹配(忽略大小写)

        const nameMatch = !filters.name ||

          product.name.toLowerCase().includes(filters.name.toLowerCase());

        // 分类精确匹配(未选择分类则不筛选)

        const categoryMatch = !filters.categoryId ||

          product.categoryId === filters.categoryId;

        // 状态精确匹配(未选择状态则不筛选)

        const statusMatch = filters.status === undefined ||

          product.status === filters.status;

        return nameMatch && categoryMatch && statusMatch;

      });

    };

    // 私有工具方法:处理数据排序

    const sortProducts = (products, sortConfig) => {

      if (!sortConfig.field) return products; // 未指定排序字段则不排序

      return [...products].sort((a, b) => {

        // 按指定字段排序(数字类型直接比较,字符串类型按ASCII排序)

        if (a[sortConfig.field] < b[sortConfig.field]) {

          return sortConfig.direction === 'asc' ? -1 : 1;

        }

        if (a[sortConfig.field] > b[sortConfig.field]) {

          return sortConfig.direction === 'asc' ? 1 : -1;

        }

        return 0;

      });

    };

    return {

      // 获取商品列表(支持分页、筛选、排序参数)

      getProductList: (params = {}) => {

        const { page = 1, pageSize = 10, filters = {}, sortConfig = {} } = params;

        // 实际项目中调用后端API,此处模拟数据(实际需替换为$http请求)

        return $http.get('/api/products', {

          params: { page, pageSize, ...filters, sortField: sortConfig.field, sortDir: sortConfig.direction }

        }).then(response => {

          const { list: products, total } = response.data;

          // 前端二次筛选与排序(若后端未支持则需处理,建议优先由后端实现)

          const filtered = filterProducts(products, filters);

          const sorted = sortProducts(filtered, sortConfig);

          return {

            list: sorted,

            total: total, // 总条数(用于分页计算)

            page: page,

            pageSize: pageSize

          };

        });

      },

      // 批量操作商品(批量删除/上架/下架)

      batchOperateProducts: (productIds, operateType) => {

        const operateMap = {

          delete: '/api/products/batch/delete',

        上架: '/api/products/batch/up',

        下架: '/api/products/batch/down'

        };

        const url = operateMap[operateType];

        if (!url) return Promise.reject('不支持的操作类型');

zhiq.zhaopin.com/question/11491006

zhiq.zhaopin.com/question/11491008

zhiq.zhaopin.com/question/11491009

zhiq.zhaopin.com/question/11491010

zhiq.zhaopin.com/question/11491012

zhiq.zhaopin.com/question/11491014

zhiq.zhaopin.com/question/11494132

zhiq.zhaopin.com/question/11494191

zhiq.zhaopin.com/question/11494207

zhiq.zhaopin.com/question/11494212

zhiq.zhaopin.com/question/11494220

zhiq.zhaopin.com/question/11494226

zhiq.zhaopin.com/question/11494237

zhiq.zhaopin.com/question/11494249

zhiq.zhaopin.com/question/11494252

zhiq.zhaopin.com/question/11494261

zhiq.zhaopin.com/question/11494269

zhiq.zhaopin.com/question/11494295

zhiq.zhaopin.com/question/11494299

zhiq.zhaopin.com/question/11494303

        return $http.post(url, { productIds });

      },

      // 单个商品操作(编辑/删除/上架/下架)

      operateProduct: (productId, operateType, data = {}) => {

        const operateMap = {

          delete: { method: 'DELETE', url: `/api/products/${productId}` },

          up: { method: 'PUT', url: `/api/products/${productId}/up` },

          down: { method: 'PUT', url: `/api/products/${productId}/down` },

          edit: { method: 'PUT', url: `/api/products/${productId}`, data: data }

        };

        const { method, url, data: reqData } = operateMap[operateType];

        if (!method || !url) return Promise.reject('不支持的操作类型');


        return $http({ method, url, data: reqData });

      }

    };

  }])

  .name;

(2)商品列表控制器(ProductListCtrl)

处理表格的视图交互逻辑,如筛选条件变更、排序切换、分页切换、批量操作触发。

// src/business/product/controllers/ProductListCtrl.js

import angular from 'angular';

import productListTemplate from '../views/productList.html';

export default angular.module('productModule.productListCtrl', [])

  .controller('ProductListCtrl', ['$scope', '$state', 'ProductService', 'NotificationService', function($scope, $state, ProductService, NotificationService) {

    // 1. 初始化状态:筛选条件、排序配置、分页配置、选中商品ID

    $scope.filters = {

      name: '', // 商品名称筛选

      categoryId: '', // 分类筛选(默认空,即不筛选)

      status: undefined // 状态筛选(undefined:不筛选,1:上架,0:下架)

    };

    $scope.sortConfig = {

      field: 'price', // 默认排序字段(价格)

      direction: 'asc' // 默认排序方向(升序)

    };

    $scope.pagination = {

      page: 1, // 当前页

      pageSize: 10, // 每页条数

      total: 0 // 总条数(从接口获取)

    };

    $scope.productList = []; // 商品列表数据

    $scope.selectedProductIds = []; // 选中的商品ID(用于批量操作)

    $scope.isLoading = false; // 加载状态

    // 2. 获取商品分类列表(用于筛选下拉框)

    const getProductCategories = () => {

      // 实际项目中调用后端API获取分类,此处模拟数据

      $http.get('/api/categories').then(response => {

        $scope.categories = response.data; // 格式:[{ id: 1, name: '服装' }, ...]

      });

    };

    // 3. 加载商品列表数据(核心方法,支持筛选、排序、分页)

    const loadProductList = () => {

      $scope.isLoading = true;

      ProductService.getProductList({

        page: $scope.pagination.page,

        pageSize: $scope.pagination.pageSize,

        filters: $scope.filters,

        sortConfig: $scope.sortConfig

      }).then(result => {

        $scope.productList = result.list;

        $scope.pagination.total = result.total;

        $scope.isLoading = false;

        // 重置选中的商品ID(分页后选中状态清空)

        $scope.selectedProductIds = [];

      }).catch(error => {

        $scope.isLoading = false;

        NotificationService.error(error.data?.errorMsg || '加载商品列表失败');

      });

    };

    // 4. 筛选条件变更:点击“搜索”按钮触发

    $scope.onSearch = () => {

      $scope.pagination.page = 1; // 筛选后重置为第一页

      loadProductList();

    };

    // 5. 排序切换:点击表头触发(切换升序/降序)

    $scope.onSort = (field) => {

      if ($scope.sortConfig.field === field) {

        // 同一字段:切换排序方向

        $scope.sortConfig.direction = $scope.sortConfig.direction === 'asc' ? 'desc' : 'asc';

      } else {

        // 不同字段:默认升序

        $scope.sortConfig.field = field;

        $scope.sortConfig.direction = 'asc';

      }

      loadProductList();

    };

    // 6. 分页切换:页码或每页条数变更触发

    $scope.onPageChange = (page) => {

      $scope.pagination.page = page;

      loadProductList();

    };

    // 7. 选中商品变更:勾选/取消勾选商品触发

    $scope.onSelectProduct = (productId, isSelected) => {

      if (isSelected) {

        // 勾选:添加到选中列表

        $scope.selectedProductIds.push(productId);

      } else {

        // 取消勾选:从选中列表移除

        $scope.selectedProductIds = $scope.selectedProductIds.filter(id => id !== productId);

      }

    };

    // 8. 批量操作商品:触发批量删除/上架/下架

    $scope.batchOperate = (operateType) => {

      if ($scope.selectedProductIds.length === 0) {

        NotificationService.warning('请先选择要操作的商品');

        return;

      }

      // 确认操作(使用之前封装的modal指令)

      $scope.batchOperateModal = {

        show: true,

        config: {

          title: `批量${operateType}商品`,

          content: `确定要${operateType}选中的${$scope.selectedProductIds.length}个商品吗?`,

          type: 'confirm',

          onButtonClick: (result) => {

            if (result.buttonType === 'confirm') {

              // 确认操作:调用服务批量处理

              ProductService.batchOperateProducts($scope.selectedProductIds, operateType)

                .then(() => {

                  NotificationService.success(`批量${operateType}商品成功`);

                  loadProductList(); // 重新加载列表

                })

                .catch(error => {

                  NotificationService.error(error.data?.errorMsg || `批量${operateType}商品失败`);

                });

            }

            $scope.batchOperateModal.show = false;

          }

        }

      };

    };

    // 9. 单个商品操作:编辑/删除/上架/下架

    $scope.operateProduct = (productId, operateType, productData = {}) => {

      if (operateType === 'edit') {

        // 编辑操作:跳转到编辑页(携带商品ID)

        $state.go('app.product.edit', { productId: productId });

        return;

      }

      // 其他操作(删除/上架/下架):确认后执行

      const operateName = { delete: '删除', up: '上架', down: '下架' }[operateType];

      NotificationService.confirm(`确定要${operateName}该商品吗?`, () => {

        ProductService.operateProduct(productId, operateType, productData)

          .then(() => {

            NotificationService.success(`${operateName}商品成功`);

            loadProductList(); // 重新加载列表

          })

          .catch(error => {

            NotificationService.error(error.data?.errorMsg || `${operateName}商品失败`);

          });

      });

    };

    // 10. 初始化:加载分类与商品列表

    const init = () => {

      getProductCategories();

      loadProductList();

    };

    init();

  }])

  // 配置商品列表路由

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

    $stateProvider.state('app.product.list', {

      url: '/list',

      template: productListTemplate,

      controller: 'ProductListCtrl',

      data: {

        requireLogin: true, // 需要登录权限

        menuName: '商品管理' // 用于导航栏高亮

      }

    });

  }])

  .name;

(3)商品列表视图(productList.html)

基于AngularJS Material的md-table实现表格布局,集成筛选、排序、分页组件。

<md-card>

  <!-- 卡片头部:标题 + 筛选区域 -->

  <md-card-header>

    <md-card-header-text>

      <h2>商品列表</h2>

    </md-card-header-text>

    <md-card-actions layout="row" layout-align="end center">

      <!-- 新增商品按钮 -->

      <md-button class="md-primary md-raised" ng-click="$state.go('app.product.add')">

        <i class="fa fa-plus"></i> 新增商品

      </md-button>

    </md-card-actions>

  </md-card-header>

  <!-- 筛选区域 -->

  <md-card-content>

    <div layout="row" layout-wrap gap="16px" class="filter-container">

      <!-- 商品名称筛选 -->

      <md-input-container flex="25">

        <label>商品名称</label>

        <input type="text" ng-model="filters.name" placeholder="请输入商品名称搜索">

      </md-input-container>

      <!-- 分类筛选 -->

      <md-input-container flex="25">

        <label>商品分类</label>

        <md-select ng-model="filters.categoryId" placeholder="请选择分类">

          <md-option value="">全部分类</md-option>

          <md-option ng-repeat="category in categories" value="{{category.id}}">

            {{category.name}}

          </md-option>

        </md-select>

      </md-input-container>

      <!-- 状态筛选 -->

      <md-input-container flex="25">

        <label>商品状态</label>

        <md-select ng-model="filters.status" placeholder="请选择状态">

          <md-option value="">全部状态</md-option>

          <md-option value="1">上架</md-option>

          <md-option value="0">下架</md-option>

        </md-select>

      </md-input-container>

      <!-- 搜索按钮 -->

      <md-input-container flex="20" layout-align="end center">

        <md-button class="md-primary md-raised" ng-click="onSearch()">

          <i class="fa fa-search"></i> 搜索

        </md-button>

      </md-input-container>

    </div>

    <!-- 批量操作按钮 -->

    <div class="batch-operate-container" ng-if="productList.length > 0">

      <md-button class="md-warn" ng-click="batchOperate('delete')" ng-disabled="selectedProductIds.length === 0">

        <i class="fa fa-trash"></i> 批量删除

      </md-button>

      <md-button class="md-primary" ng-click="batchOperate('上架')" ng-disabled="selectedProductIds.length === 0">

        <i class="fa fa-arrow-up"></i> 批量上架

      </md-button>

      <md-button class="md-accent" ng-click="batchOperate('下架')" ng-disabled="selectedProductIds.length === 0">

        <i class="fa fa-arrow-down"></i> 批量下架

      </md-button>

    </div>

    <!-- 商品表格 -->

    <md-table-container ng-if="productList.length > 0">

      <table md-table md-row-select="false" ng-model="selectedProductIds">

        <!-- 复选框列 -->

        <thead md-head>

          <tr md-row>

            <th md-column width="50px">

              <md-checkbox ng-model="selectAll" ng-click="selectAllProducts(selectAll)"></md-checkbox>

            </th>

            <!-- 表头:支持点击排序 -->

            <th md-column md-sort-header="id" ng-click="onSort('id')">商品ID</th>

            <th md-column md-sort-header="name" ng-click="onSort('name')">商品名称</th>

            <th md-column md-sort-header="categoryName" ng-click="onSort('categoryName')">分类</th>

            <th md-column md-sort-header="price" ng-click="onSort('price')">

</doubaocanvas>

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

相关阅读更多精彩内容

友情链接更多精彩内容