You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular组件中实现$scope.watch功能?

AngularJS组件式购物车总价不更新问题解决

我尝试用两种方式实现简单图书购物车:

  • 模块+控制器方式:通过$scope.watch监听图书数组,总价total能正常随图书增删改更新
  • 模块+组件方式:初始化时总价显示正确,但增删改图书时total无法自动更新

一、模块+控制器(正常运行)

HTML代码

<body ng-controller="CartControler" ng-init="updateTotal()">
  <table>
    <caption><b>My Books</b></caption>
    <thead>
      <tr>
          <th>Title</th>
          <th>Qty</th>
          <th>$UnitPrice</th>
          <th>Line Total</th>
          <th>Total {{total | currency}}</th> <!-- 显示正确金额 -->
      </tr>
      <!-- 省略表格内容 -->
    </thead>
  </table>
</body>

JS代码

angular.module('myApp', [])
.controller('CartControler', function ($scope) {
    
  $scope.books = [
    {title: 'Absolute Java', qty: 1, price: 114.95},
    {title: 'Pro HTML5',     qty: 2, price: 27.95},
    {title: 'Head First HTML5', qty: 1, price: 27.89}
  ];
  
  $scope.total;
  
  $scope.updateTotal = function(value) {
    $scope.total = 0;
    for(v in value){
      $scope.total += value[v].price * value[v].qty;
    }
    return $scope.total;
  }

  // 深度监听books数组变化
  $scope.$watch('books', function() {
    $scope.updateTotal($scope.books);
  }, true)
})

二、模块+组件(总价不更新)

HTML代码

<table>
  <caption><b>My Books</b></caption>
  <thead>
    <tr>
      <th>Title</th>
      <th>Qty</th>
      <th>$UnitPrice</th>
      <th>Line Total</th>
      <th>Total {{$ctrl.total | currency}} </th> <!-- 初始化显示正确,但增删改图书时不更新 -->
    </tr>
  </thead>
  <tbody>
    <!-- 省略表格内容 -->
  </tbody>
</table>

JS代码

angular.module("cartApp")
  .component('cartList', {
    templateUrl: 'cart-list/cart-list.template.html',
    init: 'updateTotal()', // 非标准选项,不生效
    controller: function CartListController() {
  
      this.books = [
        {title: 'Absolute Java', qty: 1, price: 114.95},
        {title: 'Pro HTML5',     qty: 2, price: 27.95},
        {title: 'Head First HTML5', qty: 1, price: 27.89}
      ];
      
      this.total;
      
      this.updateTotal = function(value) {
        this.total = 0;
        for(v in value){
          this.total += value[v].price * value[v].qty;
        }
        return this.total;
      }
      
      // 仅初始化时计算一次总价
      this.total = this.updateTotal(this.books);
    }
  })

问题原因及修复方案

问题原因

组件控制器仅在初始化时调用了updateTotal计算总价,没有监听books数组的变化,后续增删改图书时无法触发重新计算。另外,组件配置里的init不是AngularJS组件的标准选项,不会执行。

修复后的组件JS代码

angular.module("cartApp")
  .component('cartList', {
    templateUrl: 'cart-list/cart-list.template.html',
    // 注入$scope用于监听
    controller: ['$scope', function CartListController($scope) {
      var ctrl = this; // 保存控制器上下文,避免回调中this指向变化
  
      ctrl.books = [
        {title: 'Absolute Java', qty: 1, price: 114.95},
        {title: 'Pro HTML5',     qty: 2, price: 27.95},
        {title: 'Head First HTML5', qty: 1, price: 27.89}
      ];
  
      ctrl.updateTotal = function(value) {
        ctrl.total = 0;
        // 声明局部变量v,避免污染全局作用域
        for(var v in value){
          ctrl.total += value[v].price * value[v].qty;
        }
        return ctrl.total;
      }
  
      // 深度监听books数组的变化(包括元素属性修改、增删)
      $scope.$watch(function() {
        return ctrl.books;
      }, function() {
        ctrl.updateTotal(ctrl.books);
      }, true);
  
      // 初始化计算总价
      ctrl.total = ctrl.updateTotal(ctrl.books);
    }]
  })

关键说明

  • 注入$scope实现监听:AngularJS组件控制器可以注入$scope,通过$scope.$watch监听数据变化
  • 深度监听:第三个参数true会监听数组内每个元素的属性(如qty、price)变化,适合购物车场景;若只需监听数组增删,可去掉该参数提升性能
  • 保存控制器上下文:用var ctrl = this避免回调函数中this指向改变的问题
  • 移除无效的init选项:组件没有init配置,初始化逻辑直接写在控制器内

内容的提问来源于stack exchange,提问作者Munia11

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 03:20:13