AngularJS實(shí)戰(zhàn)應(yīng)用:電商后臺核心業(yè)務(wù)場景落地方案

在完成AngularJS項(xiàng)目初始化與基礎(chǔ)功能搭建后,實(shí)戰(zhàn)應(yīng)用的核心是“解決業(yè)務(wù)場景中的具體問題”——比如電商后臺的商品數(shù)據(jù)表格需支持篩選、排序、批量操作,商品編輯表單需處理動態(tài)規(guī)格字段,不同角色用戶需看到不同功能菜單。本文基于已搭建的電商后臺框架,深入三大核心實(shí)戰(zhàn)場景,提供“需求分析-技術(shù)實(shí)現(xiàn)-優(yōu)化避坑”的全流程方案,幫你掌握AngularJS在實(shí)際業(yè)務(wù)中的應(yīng)用技巧。

一、實(shí)戰(zhàn)場景1:商品數(shù)據(jù)表格——支持篩選、排序與批量操作

商品管理是電商后臺的核心模塊,數(shù)據(jù)表格作為“數(shù)據(jù)展示與操作入口”,需滿足“高效查詢、便捷操作、性能穩(wěn)定”三大需求。本場景將基于AngularJS Material的md-table組件,實(shí)現(xiàn)支持多條件篩選、字段排序、批量刪除/上架的商品表格。

1. 需求拆解

數(shù)據(jù)展示:展示商品ID、名稱、分類、價(jià)格、庫存、狀態(tài)(上架/下架)、操作按鈕;

篩選功能:支持按商品名稱模糊搜索、按分類下拉篩選、按狀態(tài)(上架/下架)篩選;

排序功能:支持按價(jià)格(升序/降序)、庫存(升序/降序)點(diǎn)擊表頭排序;

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

性能優(yōu)化:表格數(shù)據(jù)分頁加載(默認(rèn)10條/頁),避免大數(shù)據(jù)量渲染卡頓。

2. 技術(shù)實(shí)現(xiàn)方案

(1)核心服務(wù)封裝:商品數(shù)據(jù)服務(wù)(ProductService)

負(fù)責(zé)商品數(shù)據(jù)的獲取、篩選、排序、批量操作,隔離數(shù)據(jù)邏輯與視圖邏輯,便于后續(xù)維護(hù)。

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

import angular from 'angular';

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

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

? ? // 私有工具方法:處理數(shù)據(jù)篩選(多條件組合)

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

? ? ? ? // 狀態(tài)精確匹配(未選擇狀態(tài)則不篩選)

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

? ? ? ? ? product.status === filters.status;

? ? ? ? return nameMatch && categoryMatch && statusMatch;

? ? ? });

? ? };

? ? // 私有工具方法:處理數(shù)據(jù)排序

? ? const sortProducts = (products, sortConfig) => {

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

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

? ? ? ? // 按指定字段排序(數(shù)字類型直接比較,字符串類型按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 {

? ? ? // 獲取商品列表(支持分頁、篩選、排序參數(shù))

? ? ? getProductList: (params = {}) => {

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

? ? ? ? // 實(shí)際項(xiàng)目中調(diào)用后端API,此處模擬數(shù)據(jù)(實(shí)際需替換為$http請求)

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

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

? ? ? ? }).then(response => {

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

? ? ? ? ? // 前端二次篩選與排序(若后端未支持則需處理,建議優(yōu)先由后端實(shí)現(xiàn))

? ? ? ? ? const filtered = filterProducts(products, filters);

? ? ? ? ? const sorted = sortProducts(filtered, sortConfig);

? ? ? ? ? return {

? ? ? ? ? ? list: sorted,

? ? ? ? ? ? total: total, // 總條數(shù)(用于分頁計(jì)算)

? ? ? ? ? ? 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 });

? ? ? },

? ? ? // 單個(gè)商品操作(編輯/刪除/上架/下架)

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

處理表格的視圖交互邏輯,如篩選條件變更、排序切換、分頁切換、批量操作觸發(fā)。

// 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. 初始化狀態(tài):篩選條件、排序配置、分頁配置、選中商品ID

? ? $scope.filters = {

? ? ? name: '', // 商品名稱篩選

? ? ? categoryId: '', // 分類篩選(默認(rèn)空,即不篩選)

? ? ? status: undefined // 狀態(tài)篩選(undefined:不篩選,1:上架,0:下架)

? ? };

? ? $scope.sortConfig = {

? ? ? field: 'price', // 默認(rèn)排序字段(價(jià)格)

? ? ? direction: 'asc' // 默認(rèn)排序方向(升序)

? ? };

? ? $scope.pagination = {

? ? ? page: 1, // 當(dāng)前頁

? ? ? pageSize: 10, // 每頁條數(shù)

? ? ? total: 0 // 總條數(shù)(從接口獲取)

? ? };

? ? $scope.productList = []; // 商品列表數(shù)據(jù)

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

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

? ? // 2. 獲取商品分類列表(用于篩選下拉框)

? ? const getProductCategories = () => {

? ? ? // 實(shí)際項(xiàng)目中調(diào)用后端API獲取分類,此處模擬數(shù)據(jù)

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

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

? ? ? });

? ? };

? ? // 3. 加載商品列表數(shù)據(jù)(核心方法,支持篩選、排序、分頁)

? ? 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(分頁后選中狀態(tài)清空)

? ? ? ? $scope.selectedProductIds = [];

? ? ? }).catch(error => {

? ? ? ? $scope.isLoading = false;

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

? ? ? });

? ? };

? ? // 4. 篩選條件變更:點(diǎn)擊“搜索”按鈕觸發(fā)

? ? $scope.onSearch = () => {

? ? ? $scope.pagination.page = 1; // 篩選后重置為第一頁

? ? ? loadProductList();

? ? };

? ? // 5. 排序切換:點(diǎn)擊表頭觸發(fā)(切換升序/降序)

? ? $scope.onSort = (field) => {

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

? ? ? ? // 同一字段:切換排序方向

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

? ? ? } else {

? ? ? ? // 不同字段:默認(rèn)升序

? ? ? ? $scope.sortConfig.field = field;

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

? ? ? }

? ? ? loadProductList();

? ? };

? ? // 6. 分頁切換:頁碼或每頁條數(shù)變更觸發(fā)

? ? $scope.onPageChange = (page) => {

? ? ? $scope.pagination.page = page;

? ? ? loadProductList();

? ? };

? ? // 7. 選中商品變更:勾選/取消勾選商品觸發(fā)

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

? ? ? if (isSelected) {

? ? ? ? // 勾選:添加到選中列表

? ? ? ? $scope.selectedProductIds.push(productId);

? ? ? } else {

? ? ? ? // 取消勾選:從選中列表移除

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

? ? ? }

? ? };

? ? // 8. 批量操作商品:觸發(fā)批量刪除/上架/下架

? ? $scope.batchOperate = (operateType) => {

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

? ? ? ? NotificationService.warning('請先選擇要操作的商品');

? ? ? ? return;

? ? ? }

? ? ? // 確認(rèn)操作(使用之前封裝的modal指令)

? ? ? $scope.batchOperateModal = {

? ? ? ? show: true,

? ? ? ? config: {

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

? ? ? ? ? content: `確定要${operateType}選中的${$scope.selectedProductIds.length}個(gè)商品嗎?`,

? ? ? ? ? type: 'confirm',

? ? ? ? ? onButtonClick: (result) => {

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

? ? ? ? ? ? ? // 確認(rèn)操作:調(diào)用服務(wù)批量處理

? ? ? ? ? ? ? ProductService.batchOperateProducts($scope.selectedProductIds, operateType)

? ? ? ? ? ? ? ? .then(() => {

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

? ? ? ? ? ? ? ? ? loadProductList(); // 重新加載列表

? ? ? ? ? ? ? ? })

? ? ? ? ? ? ? ? .catch(error => {

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

? ? ? ? ? ? ? ? });

? ? ? ? ? ? }

? ? ? ? ? ? $scope.batchOperateModal.show = false;

? ? ? ? ? }

? ? ? ? }

? ? ? };

? ? };

? ? // 9. 單個(gè)商品操作:編輯/刪除/上架/下架

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

? ? ? if (operateType === 'edit') {

? ? ? ? // 編輯操作:跳轉(zhuǎn)到編輯頁(攜帶商品ID)

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

? ? ? ? return;

? ? ? }

? ? ? // 其他操作(刪除/上架/下架):確認(rèn)后執(zhí)行

? ? ? 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, // 需要登錄權(quán)限

? ? ? ? menuName: '商品管理' // 用于導(dǎo)航欄高亮

? ? ? }

? ? });

? }])

? .name;

(3)商品列表視圖(productList.html)

基于AngularJS Material的md-table實(shí)現(xiàn)表格布局,集成篩選、排序、分頁組件。

<md-card>

? <!-- 卡片頭部:標(biāo)題 + 篩選區(qū)域 -->

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

? <!-- 篩選區(qū)域 -->

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

? ? ? <!-- 狀態(tài)篩選 -->

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

? ? ? ? <label>商品狀態(tài)</label>

? ? ? ? <md-select ng-model="filters.status" placeholder="請選擇狀態(tài)">

? ? ? ? ? <md-option value="">全部狀態(tài)</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">

? ? ? ? <!-- 復(fù)選框列 -->

? ? ? ? <thead md-head>

? ? ? ? ? <tr md-row>

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

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

? ? ? ? ? ? </th>

? ? ? ? ? ? <!-- 表頭:支持點(diǎn)擊排序 -->

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

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

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

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