渲染没有被一个API调用,而被另一个API调用

render not getting called for one api and is for another

本文关键字:API 调用 一个 另一个      更新时间:2023-09-26

我已经使用下划线模板配置了一个简单的骨干模型和视图。对于两个独立的api使用完全相同的配置。

API 1按预期工作。

要重现此问题,请注释掉API 1的url并取消API 2的url注释。

可以看到,我已经对两个api的响应数据进行了规范化,两个api返回的数据结构完全相同。但是,没有调用API 2的呈现方法。更奇怪的是,在极少数情况下渲染会被API 2调用。

我在这里错过了什么?

// Model
var Quote = Backbone.Model.extend({
  // API 1
  //urlRoot: 'http://quotes.stormconsultancy.co.uk/quotes/1.json',
  
  // API 2
  urlRoot: 'http://quotes.rest/qod.json',
  parse: function (data){
    try{
      data = data['contents'].quotes[0];
    }
    catch(e){
    }
    var rd = {author:data.author, quote:data.quote}
    console.log("parsed", typeof rd, rd);
    return rd;
  },
  
  // UPDATE as suggested by cory
  initialize: function() {
    this.on('all', function(eventName) {
      console.log('QuoteModel: ' + eventName);
    });
  }
});
// View
var QuoteView = Backbone.View.extend({
  initialize: function() {
    this.template = _.template($('#quote-template').html());
    this.listenTo(this.model, 'change', this.render);
  },
  render: function(){
    console.log("render", this.model.attributes)
    this.$el.html(this.template(this.model.attributes));
  }
});
var quoteM = new Quote();
quoteM.fetch();
$(document).ready(function() {
	var quoteV = new QuoteView({
		el: $('#quote'),
		model: quoteM
	});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js"></script>
<script type="text/html" id="quote-template">
		<p>The author is : <%= author %></p>
		<p>The content is : <%= quote %></p>
</script>
<div id="quote"></div>

您有一个竞争条件,您在创建视图之前获取。

因此,如果在文档准备好之前获取完成,则在视图开始侦听模型之前触发更改事件。

最简单的解

$(document).ready(function() {
    var quoteM = new Quote();
    var quoteV = new QuoteView({
        el: $('#quote'),
        model: quoteM
    });
    // fetch after
    quoteM.fetch();
});

最佳解决方案

var API_DOMAIN = "http://quotes.rest/";
// Reusable model
var Quote = Backbone.Model.extend({});
// reusable quotes collection
var QuoteCollection = Backbone.Collection.extend({
  model: Quote,
  // simple generic parse
  parse: function(response) {
    return response.contents.quotes;
  },
});
// View
var QuoteView = Backbone.View.extend({
  // GOOD: gets called once
  template: _.template($('#quote-template').html()),
  
  initialize: function() {
    // BAD: gets called for every view
    // this.template = _.template($('#quote-template').html());
    
    this.listenTo(this.model, 'change', this.render);
  },
  render: function() {
    console.log("render", this.model.attributes)
    this.$el.html(this.template(this.model.toJSON()));
    // Backbone standard for chaining
    return this;
  }
});
$(function() {
  var quoteV,
    collection = new QuoteCollection();
  collection.fetch({
    url: API_DOMAIN + 'qod.json',
    success: function(collection, response, options) {
      // only create the view when you need it
      quoteV = new QuoteView({
        el: $('#quote'),
        model: collection.first()
      });
      
      // manually render to be 100% in control. The event now only
      // serves if the model really changes.
      quoteV.render();
    }
  });
});
<div id="quote"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js"></script>
<script type="text/html" id="quote-template">
  <p>The author is :
    <%= author %>
  </p>
  <p>The content is :
    <%= quote %>
  </p>
</script>

为Quote模型上的事件添加一些日志记录,您应该能够快速跟踪问题。

var Quote = Backbone.Model.extend({
    initialize: function() {
        this.on('all', function(eventName) {
            console.debug('QuoteModel: ' + eventName);
        });
    }
});