在Backbone Model更改事件

时间:2017-06-11 21:51:22

标签: javascript backbone.js infinite-loop backbone-events

我正在使用Backbone和ReactJS来保留很少的HTML div(让我们称之为盒子)堆叠在另一个div内(让我们调用这个容器)。用户可以放大这个也放大框的容器(与CSS缩放属性无关)。当在容器上触发缩放事件时,我计算放大框的总高度,并使用堆栈的新高度更新容器。实际代码很麻烦,遵循代码模拟确切场景导致无限循环。

在以下代码中,用户更改ClickButton模型的缩放值。根据{{​​1}}值,我计算新的zoom并更新它。 j更改后,我还更新了k。现在我处于递增j值的无限循环中。点击"点击"在代码上对此进行测试按钮。变量k冲到100(故意在100处中断,否则浏览器将冻结)

我的理解: 看起来当我在更改处理程序中更新k或Backbone模型中的任何内容时,它会创建另一个更改事件。一旦前一个事件结束,这个新事件就开始执行。但是,对于函数调用k,此新事件仍然返回true,该函数在上一个事件之前发生并处理。

目前的解决方案: 我使用this.hasChanged("j")选项作为Backbone {silent : true}方法的输入,并成功地阻止了无限循环。

我希望采用另一种方法来做到这一点,而不会抑制更改事件,因为我更新HTML页面依赖于更改事件。我的ReactJS应用程序连接到模型,它更新了模型更改的视图。

任何人都知道更好的解决方案吗?



set

var ClickButton = Backbone.Model.extend({
  defaults: function() {
    return {
      className: "display",
      zoom: 0,
      j: 0,
      k: 0,
      children: [],
    }
  },
  initialize() {
    getElement("zoom").value = this.get("zoom");
    getElement("zoomchanged").value = 0;
    this.on("change", function(e) {
      if (this.hasChanged("j")) {
        getElement("j").value = this.get("zoom");
        if (this.get("k") < 100) {
          // Just added hundred that your browser wont get stuck
          this.set("k", parseInt(this.get("k")) + 1);
          getElement("k").value = parseInt(this.get("k"));
        }
      }
      if (this.hasChanged("zoom")) {
        getElement("zoomchanged").value = parseInt(getElement("zoomchanged").value) + 1;
        console.log(this.get("zoom"));
        getElement("zoom").value = this.get("zoom");
        this.set("j", this.get("zoom"));
      }
    });
  }
});

var clickButton = new ClickButton();

var button = getElement("button");
button.addEventListener("click", (function(e) {
  var currentValueOfZoom = clickButton.get("zoom");
  clickButton.set("zoom", currentValueOfZoom + 1);
}).bind(this));

// Helpers
function getElement(className) {
  return document.getElementsByClassName(className)[0];
}
&#13;
input {
  width: 35px;
}

div#holder {
  display: flex;
}

div#holder input {
  margin-right: 23px;
}
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

Backbone的userName = _spPageContextInfo.userDisplayName option可以防止这种行为。但是,如文档中所述,更好的解决方案是传递一个特定的标志(例如我正在传递的silent:true标志并在下面的代码片段中进行检查。)

来自骨干文档:

  

一般来说,当调用发出事件的函数(model.set,collection.add等等)时,如果你想阻止事件被触发,你可以通过{silent:是的}作为一种选择。请注意,这很少,甚至从来都不是一个好主意。通过选项中的特定标志来查看事件回调,并选择忽略,通常会更好。

ignore: true

答案 1 :(得分:0)

虽然lucasjackson提供了针对您情况的工作补丁,但我还是希望分享最佳做法。

发生了什么事?

.hasChanged仅返回通过set所做的最新更改,并且不会跟踪任何其他后续更改,除非它们是在相关的触发事件中进行的。完成set后,对set的任何后续调用都将覆盖changed property

由于您在通用zoom事件中更改了jkchange,因此任何后续set都会触发新的change事件hasChanged总是返回true,因为changed属性如下所示:

{
    zoom: 1,
    j: 1,
    k: 100,
}

如何解决这个无限循环?

可以做很多事情来简化和改进您的模型。首先,不要在Backbone模型中使用DOM。这是视图的工作,所以React在你的情况下。

考虑到这一点,请使用specific attribute change event处理程序(change:[attribute])。

var ClickButton = Backbone.Model.extend({
    defaults: {
        zoom: 0,
        j: 0,
        k: 0,
    },
    initialize() {
        this.listenTo(this, {
            'change:zoom': this.onZoomChange,
            'change:j': this.onJChange
        });
    },
    onZoomChange(model, value, options) {
        this.set("j", this.get("zoom"));
    },
    onJChange(model, value, options) {
        this.set("k", parseInt(this.get("k")) + 1);
    }
});

话虽这么说,我不确定Backbone Model是处理按钮点击的好选择。但话说回来,你还没有分享React代码......