【问题标题】:Javascript event handler `this` binding inside closure not workingJavascript事件处理程序`this`在闭包内绑定不起作用
【发布时间】:2017-02-20 17:59:26
【问题描述】:

可能是一个简单的修复,但我已经坚持了几天。我正在构建一个井字游戏项目,我想在我的 user 对象中构建一个名为 userClick() 的方法,该方法满足以下条件:

  • 当用户点击一个tictactoe tile时:
  • 将该磁贴 (div) 内的 HTML 文本更改为用户的 marker(X 或 O);
  • taken 的CSS 类添加到磁贴;
  • 将用户的得分/移动计数增加 1。

以下是我尝试摆弄的相关 Javascript/jQuery 代码: 变种用户 = { 得分:0, 标记:“X”,

userClick: function() {
  $('.box').onClick(function() {
    this.text(marker);
    this.addClass('taken');
    score += 1;
  });
};

我的 HTML 有 9 个 div 排列在一个 tictactoe 网格中,所有 div 的类都是 box。我的 CSS 文件还有一个 taken 类,它在单击时更改 div 的背景颜色。但是,当我单击任何 div 时,什么也没有发生。我已经尝试对该功能进行多次调整以使其正常工作,但没有运气。我对闭包、事件处理程序和this 绑定仍然相当缺乏经验,所以也许有更多经验的人可以为我解释一下。

谢谢!

编辑:这是到目前为止整个代码库的JSFiddle,以防万一。 (有问题的方法从第 74 行开始)。

【问题讨论】:

  • 那是 jQuery 吗? .onClick 应该是 .on('click', function() {.click(function() {$(this) 内部处理程序以在单击的元素上使用 jQuery 方法。
  • this 是你使用的元素$(this)
  • 当您使用.click(...).on('click', ...) 时,jQuery 会为您将作用域绑定到当前元素。您自己的 .onClick() 函数不会这样做,因此您需要将其显式绑定到您需要的范围。您可以为此使用.bind,或使用call()apply() 调用它(这是JS 原生函数,而不是jQ)

标签: javascript jquery closures this jquery-events


【解决方案1】:

根据您的提及,我在这里为一个非常简单的 jQuery tic-tac-toe 设置了一个小提琴:https://jsfiddle.net/6ynyr7hx/

HTML

<div id="game_container">
   <div class="box"></div>
   <div class="box"></div>
   <div class="box"></div>
   <div class="box"></div>
   <div class="box"></div>
   <div class="box"></div>
   <div class="box"></div>
   <div class="box"></div>
   <div class="box"></div>
</div>

jQuery

$(function() {

    var marker_count = 1;
    $('.box').click(function() {
        if (marker_count === 9) {
            $('#game_container').append('GAME OVER');
        }
        if (marker_count % 2 === 00) {
            marker = "X";
        } else {
            marker = "O";
        }
        $(this).text(marker).addClass("taken");
        //Increment the counter
        marker_count = marker_count + 1;
    });
});

CSS

#game_container {
    width: 140px;
    text-align: center;
}

.box {
    display: block;
    float: left;
    width: 40px;
    height: 40px;
    line-height: 40px;
    text-align: center;
    margin: 2px;
    border: 1px solid #CCC;
}

*注意:我没有费心清理浮动,因为这只是一个快速...

  // PROBLEM METHOD
  userClick: function userClick(marker) { <--- You have to pass the marker
    marker = "x";  <- That should be the passed marker
    $(".box").click(function() {
      $(this).text(marker).addClass("taken");
      score += 1;
    });
  }
}

你需要在改变转弯等时来回传递标记状态和分数......这至少让你更接近使用它。还要删除所有包含 js 的 html 头代码,然后使用 javascript 面板齿轮图标包含 jquery x.x.x 并将其设置为 onDomready。请注意我在上面的代码中更改的终止符。那里有一个落后者导致脚本失败。并在小提琴中取消注释您准备好的 userClick 函数。

【讨论】:

  • 其中一些代码实际上对于我尚未实现的功能非常有用。我对你为什么将整个函数放在 $(); 中感到困惑,但我假设它的工作方式与分配给对象属性的值相同。但是,即使我根据您的建议更改了相关部分,它仍然不起作用。这是所有代码的 jsFiddle 链接,以防万一:jsfiddle.net/cbLxps8o
【解决方案2】:

userClick 处缺少} 关注函数;在game.initializeGame() 内拨打user.userClick();将user.markeruser.score 替换为markerscore 内的.click() 函数附加到.box 选择器。

  // Game functions
  initializeGame: function() {
    user.chooseMarker();
    computer.chooseMarker();
    user.setMarkerInUI();
    user.updateScore();
    computer.setMarkerInUI();
    computer.updateScore();
    user.userClick();
    $('#score strong').text(totalScore);
  }


  // PROBLEM METHOD
  userClick: function userClick() {
    $(".box").click(function() {
      console.log(this, user.marker)
      $(this).text(user.marker);
      $(this).addClass(".taken");
      user.score += 1;
    })
  }

一个开始 plnkr https://plnkr.co/edit/cAOj0Xa0rcNucM9lft1G?p=preview

【讨论】:

  • 我完全不清楚这段代码如何帮助回答我的问题。我不确定如何定义 data() 方法或将其附加到我的一个对象以执行您建议的功能。它也没有解决我将如何更改函数,因为我当前编写它以将用户的标记(X 或 O)添加到 div 或将“taken”类添加到 div,这是当前不工作的我的问题所问的功能
  • @M.Layton 您可以使用 jQuery 作为对象将每个 .box 元素存储为“用户”对象。 .data() 可以存储对象{score:0},其中score 的值在事件中递增。 className "taken" 在元素的click 事件中添加到元素。不确定“添加用户的标记”是什么意思?您是否在问如何使用htmljavascript 构建整个井字游戏?注意,jsfiddle 链接没有出现在原始问题中?
  • @M.Layton 注意,请尝试使用 plnkr plnkr.co 将文件链接到 html; jsfiddle 没有将&lt;script type="text/javascript" src="tictactoe.js"&gt;&lt;/script&gt; 链接到JAVSCRIPT 面板。
  • 所以在游戏开始时,用户会选择玩“X”还是“O”,这个选择会以字符串的形式存储在 Object 属性 user . 标记。当用户点击其中一个井字游戏时(用 HTML 编写为
    ,点击事件应触发点击的 div 内的文本以添加存储在用户中的字符串.marker.
  • @M.Layton 您是否考虑过在实际问题中包含该描述?在提出当前问题时,出现的问题被描述为 “我对闭包、事件处理程序和这种绑定仍然相当缺乏经验,所以也许有更多经验的人可以为我阐明这一点。”stackoverflow.com/help/how-to-ask,也见Answer
【解决方案3】:

处理程序中的 this 代表 DOM 元素,但 text 和 addClass 都属于 jQuery Object。所以你需要像这样使用它们。

$(this).text(marker)

【讨论】:

    【解决方案4】:

    对我(更不用说解析器)来说,您期望“this”在您的上下文中是什么并不完全清楚。它是你想要的 jquery selected 元素吗?还是用户对象?

    鉴于您正在尝试向其添加 CSS 类,我假设您想要 clicked 元素。您的处理程序分配应如下所示:

    $('.box').on('click', function() {
        var box = $(this); // refers to the clicked element
        box.text(marker);
        box.addClass('taken');
        score += 1;
      });
    

    【讨论】:

    • 呃,对不起;我只是在复制他的部分并关注他说他遇到的问题,而不是检查他的所有代码。已在编辑中修复,谢谢!。
    • 所以我将this 引用更改为$(this),或者尝试将$(this) 分配给变量框并使用box.text(...),但它仍然不起作用。我想知道,因为单击处理程序中的匿名函数位于另一个匿名函数内部(分配给我的用户对象的 userClick 属性的值,是无法确定 markerscore 是参考的方法到?如果是这样,有什么好的解决办法?
    • @M.Layton 您在代码中使用的是click / on 还是onClick
    • @YemSalat,我已经尝试了所有三个版本——它们都不能正常工作。
    猜你喜欢
    • 1970-01-01
    • 2016-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-01
    • 1970-01-01
    • 2023-02-09
    相关资源
    最近更新 更多