ng-repeat 中的一个按钮每秒变化 10 次导致它不可点击

A button in an ng-repeat that is changing 10 times per second causes it not to be clickable

描述

我有一个网页的一部分,显示每个团队的名称和分数,每个团队都有两个按钮(分数 -1 和分数 +1)。

Teams 是一个数组,使用 ng-repeat 显示团队。

    <!-- Teams Info & Control -->
    <div class="row center-text" style="height: 40%;">
      <div class="col" ng-repeat="team in game.teams">
        <h5 style="display: inline;">{{team.name}}</h5>
        <i class="fa fa-edit" ng-click="editTeamName($index)" class="btn btn-link"></i>
        <h6>{{team.score}}</h6>
        <div class="row">
          <div class="col">
            <button type="button" ng-click="scoreChange($index, -1)" class="btn btn-primary fill-height fill-width">Score -1</button>
          </div>
          <div class="col">
            <button type="button" ng-click="scoreChange($index, 1)" class="btn btn-primary fill-height fill-width">Score +1</button>
          </div>
        </div>
      </div>
    </div>

teams 数组是名为 "game" 的更大对象的一部分,该对象每秒从 socket.io 服务器接收 10 次。需要每秒10次,因为游戏对象中有定时器需要高精度显示给用户。

如何在客户端更新游戏对象:

socket.on('gameUpdate', function(game) {
  $scope.$apply(function() {
    $scope.game = game
  });
});

示例游戏对象:

{
  gameRunning: false,
  shotClockTime: defaultFullShotClock, //Value changing 10 times per second other values may change too but not as frequently
  oldShotClockValue: defaultFullShotClock,
  teams: [{
    name: "White",
    score: 0
  }, {
    name: "Blue",
    score: 0
  }],
  inOvertime: false,
  currentPeriod: 0,
  periods: {
    mainGame: generateMainGame(defaultPeriodTime, defaultBreakTime, defaultHalfTime),
    overtime: generateOverTime(defaultOverTimePeriodTime, defaultBreakTime)
  }
}

我认为是什么问题

当游戏对象发生变化时,团队显示 HTML 会更新($$!),即使团队数组本身没有发生任何变化。问题是鼠标按下然后鼠标弹起事件通常需要超过 0.1 秒,这意味着它们不会发生在同一个按钮上,因此它们不会被注册为点击,这意味着 ng-click 不会被调用。

$$! (我认为发生这种情况是因为在 inspect 元素中该部分呈紫色闪烁。此外,按钮颜色在悬停时会在悬停颜色和默认颜色之间快速交替。Video

可能的解决方案

  1. 让 angular-js 意识到什么都没有改变,因此它不会改变 HTML 意味着一切都会好起来的(IDK 如何做到这一点,但如果你这样做,那么这可能是一个解决方案)
  2. 让按钮保持不变,因为它们永远不会根据团队数组的不同而改变(除非它变大意味着有更多的按钮)
  3. 不要使用 ng-repeat 复制粘贴代码,因为应该总是有两个团队(这是不得已的解决方案,因为我将来可能需要添加更多团队及其 "bad" 代码)

在您的 ng-repeat 中使用 track by 子句,例如:

<div class="col" ng-repeat="team in game.teams track by $index">

Track by 是一个有用的子句,它可以做一些事情,但其中之一是它让 angular 跟踪列表中的项目,以便它知道哪些项目需要重新呈现或哪些已经存在。但是,如果这些项目来自数据库并具有唯一标识符,实际上最好使用 属性 作为跟踪器而不是索引,因为它性能更好并允许重新排序:

<div class="col" ng-repeat="team in game.teams track by team.id">

文档: https://docs.angularjs.org/api/ng/directive/ngRepeat