2017-06-11 35 views
1

我正在使用Backbone和ReactJS來保留其他div(允許調用此容器)內的一些HTML div s(讓它們稱爲框)。用戶可以放大此容器,這也可以放大框(與CSS縮放屬性無關)。當在容器上觸發縮放事件時,我計算放大框的總高度,並用堆棧的新高度更新容器。實際的代碼很麻煩,遵循代碼模仿確切的場景,導致無限循環。在骨幹模型更改事件中具有更新屬性的無限循環

在以下代碼中,用戶更改ClickButton模型的縮放值。基於zoom值,我計算新的j並更新它。當j更改時,我也更新了k。現在我處於增加k的價值的無限循環中。點擊「點擊」按鈕在代碼上進行測試。可變k七嘴八舌地100(故意破壞100,否則瀏覽器將凍結)

我的理解: 它看起來像當我更新k或任何內部骨幹模型對變化的處理程序,它創建另一個變化事件。這個新事件在上一個事件結束後開始執行。但是,對於函數調用this.hasChanged("j")而言,這個新事件仍然返回true,該函數發生在前一個事件之前並在其上進行處理。

當前解決方案: 我使用{silent : true}選項作爲Backbone set方法的輸入併成功地能夠停止無限循環。

我想另一種方式做到這一點,而不會抑制更改事件,因爲我更新HTML頁面依賴於更改事件。我的ReactJS應用程序連接到模型,並更新模型更改的視圖。

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

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]; 
 
}
input { 
 
    width: 35px; 
 
} 
 

 
div#holder { 
 
    display: flex; 
 
} 
 

 
div#holder input { 
 
    margin-right: 23px; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script> 
 
<div id="holder"> 
 
    <label>K: </label><input class="k" type="text"><br> 
 
    <label>J: </label><input class="j" type="text"><br> 
 
    <label>zoom: </label><input class="zoom" type="text"><br> 
 
    <label>Number of times zoom changed: </label><input class="zoomchanged" type="text"><br> 
 
    <div class="display"> 
 

 
    </div> 
 
    <button class="button"> 
 
    Click 
 
    </button> 
 
</div>

回答

1

這種行爲可能與骨幹silent:trueoption被阻止。但是,如文檔中所述,更好的解決方案是傳遞特定的標誌(例如我在下面的代碼段中傳遞並檢查的ignore: true標誌)。

從骨幹文檔:

一般來說,稱發射事件的功能時(等model.set,collection.add,和...),如果你想阻止該事件被觸發,您可以通過{silent:true}作爲選項。請注意,這很少,甚至從來不是一個好主意。通過事件回調的選項中的特定標誌來查看並選擇忽略,通常會更好。

this.on("change", function(e, options){ 
    if(options.ignore !== true && 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"), {ignore: true}); 
    } 
}); 
+0

謝謝。這解決了這個問題。 +1,因爲我從來不知道我可以將自定義數據作爲選項傳遞。我一直認爲選項就像{silent:true}之類的骨幹內部指令會抑制change事件。 – printfmyname

0

雖然lucasjackson提供具體到你的情況工作的補丁,我想反正分享最佳實踐。

發生了什麼事?

.hasChanged只會返回通過set所做的最新更改,並且不會跟蹤任何其他後續更改,除非它們是在相關的觸發事件中進行的。一旦set完成,任何後續調用set將覆蓋changed property

既然你改變zoomjk通用change事件中,任何後續set觸發新change事件,其中hasChanged始終返回true,因爲changed屬性看起來是這樣的:

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

如何解決這個無限循環?

可以做很多事情來簡化和改進你的模型。首先,不使用骨幹模型中的DOM。這是一個視圖的工作,所以反應在你的情況。

考慮到這一點,請使用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); 
    } 
}); 

話雖這麼說,我不知道用骨幹模式是一個不錯的選擇來處理按鈕點擊。但是,再次,你沒有分享React代碼...