在jQuery选择器数组中单击1项将应用于该数组中的所有元素

Click on 1 item in jQuery selector array is applying to all elements in the array

本文关键字:数组 元素 应用于 1项 jQuery 选择器 单击      更新时间:2023-09-26

我试图为一款扫雷游戏实现一个作弊功能,该功能显示了1个随机的非炸弹方块(第279行),以及它的安全相邻方块(周围8个没有炸弹的方块中的任何一个)。

由于某些原因,这样做$(this.nonBombCells.random()[0]).click()会触发所有非炸弹方块显示(第260行),而不仅仅是随机的一个和安全的邻居,直到遇到附近的炸弹。

如果我注释掉第279行并单击非炸弹单元格,它将按预期工作。

我这里有一个活塞:http://plnkr.co/edit/OyC8LbFdsAFPn709pUiw?p=preview

我怎样才能让这个函数正常工作,如果一个人点击了那个方块?

相关代码:

(function($){
    // I am the controller for the mine sweeper game.
    function MineSweeper(selector, columnCount, rowCount, bombCount){
        var self = this;
        this.table = $(selector);
        this.columnCount = (columnCount || 30);
        this.rowCount = (rowCount || 30);
        // Check to see if the bomb count contains a percent sign.
        if ((typeof(bombCount) == "string") && (bombCount.indexOf("%") > 0)){
            // The bomb count is a percentage of the total number
            // of cells.
            this.bombCount = Math.floor(
                (this.columnCount * this.rowCount) *
                (parseInt(bombCount) / 100)
           );
        } else {
            // The bomb count is just a standard number.
            this.bombCount = (bombCount || 15);
        }
        // Bind the click handler for the table. This way, we
        // don't have to attach event handlers to each cell.
        this.table.click(
            function(event){
                // Pass off to the table click handler.
                self.onClick(event);
                // Cancel default event.
                return(false);
            }
       );
        // Initialize the table.
        this.initTable();
    };

    // I build the actual markup of the table using the
    // given number of columns and rows.
    MineSweeper.prototype.buildTable = function(){
        // Build the markup for a given row.
        var rowHtml = ("<tr>" + duplicateContent("<td class='"active'">&nbsp;</td>", this.columnCount) + "</tr>");
        // Build the markup for the table using the row
        // data the given number of times.
        var tableHtml = duplicateContent(rowHtml, this.rowCount);
        // Set the HTML of the table to fill it out.
        this.table.html(tableHtml);
    };

    // I check to see if an end-game has been reached.
    // If so, then I give the option to restart.
    MineSweeper.prototype.checkEndGame = function(){
        var message = "";
        var isEndGame = false;
        // Check to see if any of the bombs have exploded.
        if (this.bombCells.filter(".bomb-revealed").size()){
            // Set the message.
            message = "You LOSE - Play Again?";
            // Flag the end game.
            isEndGame = true;
        // Check to see if there are any more active
        // non-bomb cells. If not, then the user has
        // successfully clicked all non-bomb cells.
        } else if (!this.nonBombCells.filter(".active").size()){
            // Set the message.
            message = "You WIN - Play Again?";
            // Flag the end game.
            isEndGame = true;
        }
        // Check to see if the game is over.
        if (isEndGame){
            // Prompt for replay.
            if (confirm(message)){
                // Restart the game.
                this.restart();
            }
        }
    };

    // I clear the table of any markup.
    MineSweeper.prototype.clearTable = function(){
        this.table.empty();
    };

    // I initialize the table.
    MineSweeper.prototype.initTable = function(){
        var self = this;
        // Clear the table if there is any existing markup.
        this.clearTable();
        // Now that we have ensured that the table is
        // empty, let's build out the HTML for the table.
        this.buildTable();
        // Gather the cells of the table.
        this.cells = this.table.find("td");
        // Set the "near bombs" data for each cell to
        // zero. This is the number of bombs that the cell
        // is near.
        this.cells.data("nearBombs", 0);
        // For each cell, keep a collection of the cells
        // that are near this cell.
        this.cells.each(function(index, cellNode){
            var cell = $(this);
            // Store the near cells.
            cell.data("near", cell.near());
        });
        // Randomly select and gather the bomb cells.
        this.bombCells = this.cells.randomFilter(this.bombCount).addClass("bomb");
        // Now that we've selected the bomb cells, let's
        // get teh non-bomb cells.
        this.nonBombCells = this.cells.filter(
            function(index){
                // If this cell does NOT appear in the bomb
                // cells collection, then it's a non-bomb
                // cell.
                return(self.bombCells.index(this) == -1);
            }
        );
        this.cheat();
        // Now that we have the bomb cells, let's go through
        // each of them and apply its "nearness" to the
        // cells around it.
        this.bombCells.each(
            function(index, node){
                var cell = $(this);
                var nearCells = cell.data("near");
                // For each near cell, increment the near
                // data counter.
                nearCells.each(function(){
                    var nearCell = $(this);
                    // Get the current near data and
                    // increment it.
                    nearCell.data("nearBombs", (nearCell.data("nearBombs") + 1));
                });
            }
        );
    };
    // I handle the clicks at the table level.
    MineSweeper.prototype.onClick = function(event){
        // Get the trigger for the event.
        var target = $(event.target);
        // Check to make sure the target is an active cell.
        // If it is not, then we are not interested.
        if (target.is("td.active")){ 
            // Check to see if the ALT key was pressed. If it
            // was, then we are handling the caution toggle.
            // If not, then we are going to process a normal
            // click event.
            if (event.altKey){
                // Toggle the caution nature of this cell.
                this.toggleCaution(target);
            } else {
                // Check to see if the target was a bomb cell.
                if (target.hasClass("bomb")){
                    // The user clicked on a bomb, which will end
                    // the game. Reveal the whole board (end-game
                    // check comes below).
                    this.revealBoard();
                } else {
                    // The target was not a bomb, so show it.
                    this.revealCell(target);
                }
                // Check end game.
                this.checkEndGame();
            }
        }

    };

    // I restart the game.
    MineSweeper.prototype.restart = function(){
        // Re-initialize the table.
        this.initTable();
    };

    // I reveal the entire board.
    MineSweeper.prototype.revealBoard = function(){
        // Remove the transient classes.
        this.cells.removeClass("active").removeClass("caution");
        // Add the bomb-revealed classes to the bombs.
        this.bombCells.addClass("bomb-revealed");
        // Set the cell contents.
        this.cells.each(
            function(index, cellNode){
                var cell = $(this);
                // Check to see if this is a bomb cell.
                if (cell.hasClass("bomb")){
                    // Show an *.
                    cell.html("*");
                } else if (cell.data("nearBombs")){
                    // Show the count.
                    cell.html(cell.data("nearBombs"));
                }
            }
       );
    };

    // I reveal the given cell.
    MineSweeper.prototype.revealCell = function(cell){
        var self = this;
        // Remove the active nature of the cell.
        cell.removeClass("active").removeClass("caution");
        // Check to see if the current cell is near any
        // bombs. If it is, then we'll just show the
        // current cell and it's nearness. If not, then
        // we'll continue to show the surrounding cells.
        if (cell.data("nearBombs")){
            // Set the content of the cell.
            cell.html(cell.data("nearBombs"));
        } else {
            // Make sure the cell has no markup.
            cell.html("");
            // This cell was not near any bombs. Therefore,
            // it is reasonable to assume the user would
            // quickly reveal all cells around it. As such,
            // we will do that for them.
            cell.data("near").filter(".active").each(
                function(index, cellNode){
                    if(!$(this).hasClass('bomb'))
                        self.revealCell($(this));
                }
           );
        }
    };
    // Toggle a cell with the caution symbol ("?")
    MineSweeper.prototype.toggleCaution = function(cell){
        if (cell.hasClass("caution")){
            cell.removeClass("caution");
            cell.html("&nbsp;");
        } else {
            cell.addClass("caution");
            cell.html("?");
        }
    }
    // Just don't have the patience? Me neither.
    MineSweeper.prototype.cheat = function() {
        var reveal = $(this.nonBombCells.random()[0]);
        reveal.click();
    }
    function duplicateContent(content, count){
        return new Array(count + 1).join(content);
    }
    $.fn.random = function() {
        return this.eq(Math.floor(Math.random() * this.length));
    }   
    // ------------------------------------------------------ //
    // ------------------------------------------------------ //

    // Store the mine sweeper class in the window scope so
    // that people can reach it ouside of this bubble.
    window.MineSweeper = MineSweeper;
})(jQuery);

如果你对Plunker有问题,因为它弹出"你赢了"的东西,因为问题:

按ESC,这是因为第279行(问题)导致它点击所有非炸弹单元格,因此,触发获胜条件

我刚刚把第260行改成$(this).revealCell();这似乎很有效。我不确定这是不是你想要的,但我想是的。

终于把问题弄明白了。当我用this.cheat时,cell.data("nearBombs")总是零。所以我猜你是在附加数据之前调用this.cheat

所以我把this.cheat()移到第155行,一切都很好。