在div外部单击时,如何捕捉ng keypress/$事件



我正在AngularJS中构建一个数独游戏。我想要实现的是,即使我在页面上的div之外单击,也能抓住ng键。看看http://sudoku.com/例如,如果您选择一个单元格,然后单击页面上的任何位置,然后,如果您仍然单击任何数字,它将更改单元格中的数字。我怎样才能做到这一点?

请看下面的HTML代码:

<table class="sudoku-board" ng-init="getSudoku()" id="sudoku"
ng-class="{'paused': visible}">
<tbody>
<tr class="sudoku-row" ng-repeat="sudoku in sudokuGrid track by $index"
ng-init="row = $index">
<td class="sudoku-col sudoku-cell" ng-repeat="number in sudoku track by $index"
ng-init="col = $index" ng-class="{'highlight': colSelected === col || isHighlight(row, col) || rowSelected === row,
'highlight-number':getValue === number.substring(0, 1), 'selected':isSelected === ((row*10) + col), 'paused': visible}"
ng-click="selectedCell(row, col)"
ng-keydown="insertNum($event, row, col);" tabindex="1">
<span class="cell-value"
ng-class="{'empty': number === null || number.charAt(number.length-1) === '!', 'default': number !== null, 'paused': visible}"
ng-bind="number.substring(0, 1)"></span>
</td>
</tr>
</tbody>
</table>

在ng键按下时,我正在启动此功能:

// handle inserted value
$scope.insertNum = function (e, row, col, number) {
console.log("Number: " + number);
$scope.selectedCol = col; // get selected column
$scope.selectedRow = row; // get selected row
console.log(e);
if (e !== undefined) {
var keyCode = e.keyCode || e.charCode; // assign key & char code
if ((keyCode < 49 || ((keyCode > 57 && keyCode < 97) || keyCode > 105)) && (keyCode !== 8 && keyCode !== 46))
return false; // if clicked button/ event is not a number or delete/ backspace button -> return false
if (e.currentTarget.children[0].classList[2] === 'empty') // check if clicked cell is empty
if (keyCode === 8 || keyCode === 46) { // if clicked delete/ backspace remove the current value
e.currentTarget.children[0].innerHTML = null;
$scope.sudokuGrid[row][col] = null;
$(e.target).removeClass("incorrect");
$(e.target).removeClass("correct");
$scope.handleErrorClass();
$scope.getValue = false;
}
else { // when number is clicked
e.currentTarget.children[0].innerHTML = e.key; //  insert that number in the cell
$scope.sudokuGrid[row][col] = e.key + "!";
$scope.checkCurrentNumber(row, col);
$scope.getCurrentNumber(row, col);
// if inserted number is correct add class
if (e.key === $scope.sudokuGridSolved[row][col]) {
console.log("Correct");
$(e.target).removeClass("incorrect");
$(e.target).addClass("correct");
}
// add incorrect class if inserted number is not correct
else {
console.log("Incorrect");
$(e.target).removeClass("correct");
$(e.target).addClass("incorrect");
}
//$scope.sudokuGrid[row][col] = e.key;
}
}
else {
if (number !== null && $("tr:eq(" + $scope.selectedRow + ") td:eq(" + $scope.selectedCol + ") span").hasClass("empty")) {
$("tr:eq(" + $scope.selectedRow + ") td:eq(" + $scope.selectedCol + ") span").html(number);
$scope.sudokuGrid[row][col] = number + "!";
$scope.checkCurrentNumber(row, col);
$scope.getCurrentNumber(row, col);
// if inserted number is correct add class
if ($scope.getValue === $scope.sudokuGridSolved[row][col]) {
console.log("Correct");
$("tr:eq(" + $scope.selectedRow + ") td:eq(" + $scope.selectedCol + ")").removeClass("incorrect");
$("tr:eq(" + $scope.selectedRow + ") td:eq(" + $scope.selectedCol + ")").addClass("correct");
}
// add incorrect class if inserted number is not correct
else {
console.log("Incorrect!");
$("tr:eq(" + $scope.selectedRow + ") td:eq(" + $scope.selectedCol + ")").removeClass("correct");
$("tr:eq(" + $scope.selectedRow + ") td:eq(" + $scope.selectedCol + ")").addClass("incorrect");
}
}
}
$scope.checkForIdenticalValues();
}

所以问题是因为ng-keydown<td>标记上,所以只有当它是当前关注的元素时才会调用该函数,但听起来你想从页面上的任何位置响应按键按下事件。

您可以通过在body标记上使用ng-keydown而不是<td>来实现这一点,然后使函数广播一个可以从数独组件收听的事件,以运行insertNum逻辑。像这样:

<body ng-keydown="onMyKeydownEvent($event)"> 

然后在run()中的$rootScope上绑定函数以广播事件。

app.run(function($rootScope) {
$rootScope.onMyKeydownEvent = function(e) {
$rootScope.$broadcast("MyKeydownEvent", e);
};
});

之后,将侦听器添加到组件中。

$scope.$on("MyKeydownEvent", function(e) {
// insertNum logic goes here.
});

您还需要对逻辑进行一些调整,因为像e.currentTarget$scope.selectedCol = col;$scope.selectedRow = row;这样的东西将不再按预期工作。相反,<td>标签上的ng-click="selectedCell(row, col)"应该负责将所需的单元格数据设置到范围中,以便在事件中使用。

最新更新