【问题标题】:backbone events not triggering in SafariSafari 中未触发的主干事件
【发布时间】:2013-01-18 23:23:36
【问题描述】:

为了学习练习,我将一个 sinatra/backbone 应用程序转换为 Rails 环境。我让它在 Chrome 和 Firefox 上运行,但它在 Safari 上不起作用。原来的应用程序http://backbone-hangman.heroku.com 也不能在 Safari 上运行。当您单击“新游戏”时,它似乎不会触发事件。 Safari 控制台没有显示任何错误(尽管我对 Safari 的开发人员工具并不熟悉,因为我从不使用它们)。

由于这里有应用程序的实时版本http://backbone-hangman.heroku.com 我不会发布很多代码,但这是设置点击事件的视图代码#new_game,触发 startNewGame 功能。 Safari 中什么也没有发生。原文的源代码在这里https://github.com/trivektor/Backbone-Hangman

我在 Google 上搜索了一下,发现有人提到 Safari 以不同的方式处理事件,但找不到解决方案。有什么可以推荐的吗?

$(function() {

  window.OptionsView = Backbone.View.extend({
    el: $("#options"),
    initialize: function() {
      this.model.bind("gameStartedEvent", this.removeGetAnswerButton, this);
      this.model.bind("guessCheckedEvent", this.showGetAnswerButton, this);
    },
    events: {
      'click #new_game': 'startNewGame',
      'click #show_answer': 'showAnswer'
    },
    startNewGame: function() {
      this.model.new();
    },
    removeGetAnswerButton: function() {
      $("#show_answer").remove();
    },
    showGetAnswerButton: function(response) {
      console.log("showGetAnswerButton");
      console.log(response);
      var threshold = this.model.get("threshold");
      console.log(threshold);
      if (response.incorrect_guesses == this.model.get("threshold")) {
        $(this.el).append('<input type="button" id="show_answer" class="action_button" value="Show answer" />');
      }
    },
    showAnswer: function() {
      this.model.get_answer();
    }
  })

})

更新

基于 OP 下面的 cmets 之一,我发布了更多代码。这是hangman.js,其中对象被实例化

var game = new Game

  var options_view = new OptionsView({model: game});

  var characters_view = new CharactersView({model: game});

  var hint_view = new HintView({model: game});

  var word_view = new WordView({model: game});

  var hangman_view = new HangmanView({model: game});

  var answer_view = new AnswerView({model: game});
  var stage_view = new StageView({model: game});

视图和模型像这样附加到窗口

window.AnswerView = Backbone.View.extend({ ...

更新 除了在站点范围内加载的 Backbone、jQuery 和 Underscore 之外,还为 Rails 系统中的这个特定应用程序加载了以下文件。

【问题讨论】:

  • 这个问题对我来说似乎很奇怪:Backbone 只使用 jQuery(或 Zepto,如果你喜欢这种东西)来做它的事件连接,而 jQuery 以为你处理浏览器问题而闻名.并不是说我说你是骗子或任何东西;-) 只是说,这个问题很奇怪。
  • 嗯,你可以自己查看演示应用中的代码。它在 Safari 中对你有用吗?
  • 页面加载中是否存在选项?可能是文件准备时间的东西
  • 呃,你忘记新建对象了吗?新的 Window.OptionsView()?也可能是您将它直接附加到窗口,我不会那样做,只是让全局成为任何东西。不确定 Safari 在页面加载之前如何管理全局窗口。
  • @amchang87 根据我对您评论的理解,我用更多代码更新了 OP。但是,由于我没有那么有经验,因此我不确定可能需要进行哪些更改...您是否介意写一个答案来说明我如何更改代码,这样我就不会“直接将其附加到窗口” “?如果这确实是我正在做的......谢谢

标签: backbone.js


【解决方案1】:

This is jQuery + Safari issue (document.ready)

您可以将脚本移动到 body 标记内,然后删除每个文件中的 $(function(){ /**/ }) 包装器。

我还添加了 requirejs 支持并制作了pull request

编辑:

首先对不起我的英语:)


文件视图/index.haml:

我们应该在页面底部嵌入js(避免Safari错误)

= javascript_include_tag "javascript/require.js", :"data-main" =&gt; "javascript/config"

这里javascript/config是requirejs配置的路径。


文件 public/javascript/config.js:

"deps" : ["hangman"]

这意味着应用程序将以hangman.js开头


文件 public/javascript/hangman.js:

我们不需要$(function() { 包装器,因为我们从正文和文档初始化的脚本已经“准备好”

define([
  'models/game',
  'views/answerView',
  /* ... */
],
function(Game, OptionsView, /* ... */) {
  // ...
}

在这里我们加载我们的模块(第一个数组元素将在第一个函数参数中可用,依此类推)


其他文件

我们只需将$(function() { 替换为define(['backbone'], function(Backbone) {

在第一行我们加载主干模块。当它被获取时,它将在匿名函数中可用(第一个参数 - Backbone)

接下来我们应该返回视图以避免undefined模块值(public/javascript/hangman.js文件应该初始化很多视图。它不能初始化undefined它应该初始化我们应该返回的Backbone.View


要了解更多信息,您应该阅读 requirejs 文档。 我建议你从this article开始

【讨论】:

  • 那不是我的 github 帐户,所以我不能接受拉取请求,但我会尝试在我的代码上复制它。我之前看过 require.js 文档,但对设置它感到困惑。您能否用简单的语言简要说明您在每个文件中做了什么(如果您有时间),以便我可以在其他项目中复制它。
  • @Michael 没问题,看上面
  • 谢谢,我下载了您的代码并在 Safari 中试用。开始。需要猜测的单词的行是可见的,但用户单击以进行猜测的实际字母没有显示,尽管它们在 Chrome 中是可见的。这是预期的吗?你只是部分实现了 require.js 吗?
  • 哦...这个 Safari :) this.el.show() 无法正常工作。我将其更改为this.el.css('display','block'),现在一切正常github.com/vermilion1/Backbone-Hangman/commit/…
【解决方案2】:

试试这个。

var OptionsView = Backbone.View.extend({
    el: $("#options"),
    initialize: function() {
      this.model.bind("gameStartedEvent", this.removeGetAnswerButton, this);
      this.model.bind("guessCheckedEvent", this.showGetAnswerButton, this);
    },
    events: {
      'click #new_game': 'startNewGame',
      'click #show_answer': 'showAnswer'
    },
    startNewGame: function() {
      this.model.new();
    },
    removeGetAnswerButton: function() {
      $("#show_answer").remove();
    },
    showGetAnswerButton: function(response) {
      console.log("showGetAnswerButton");
      console.log(response);
      var threshold = this.model.get("threshold");
      console.log(threshold);
      if (response.incorrect_guesses == this.model.get("threshold")) {
        $(this.el).append('<input type="button" id="show_answer" class="action_button" value="Show answer" />');
      }
    },
    showAnswer: function() {
      this.model.get_answer();
    }
  });

您的代码不需要在文档中准备好(它不是直接操作 DOM,它只是声明一个对象);

请确保 game.js 遵循您的所有声明。

Safari 在向全局对象添加变量时似乎存在问题。在全局上下文中使用 var 确保 window.OptionsView 存在。将来您可能会考虑使用 require.js 来管理所有这些全局对象问题。

【讨论】:

  • 将 'window' 更改为 'var' 并没有解决问题(我在所有视图和模型上都这样做了。我更新了 OP,其中包含为此应用程序加载的所有文件的快照. 你能否在你的答案中添加几行来解释我如何使用 require.js 来解决这个问题。
  • 您需要删除 $() 包装器 .... 字面意思是将我粘贴的整个代码粘贴到您的文件中
  • 你能解释一下为什么 Game.js 必须遵循所有的声明吗?如果可以的话,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多