【问题标题】:Prevent re-rendering Ember view if model data hasn't changed如果模型数据未更改,则防止重新渲染 Ember 视图
【发布时间】:2014-06-22 16:00:17
【问题描述】:

我正在尝试创建一个自动完成功能,该功能从 Trakt API 抓取电影并将前 3 个结果呈现到页面上。每次更改“查询”文本(来自输入)时,我都会获得新数据。但是,即使这 3 个模型保持不变,Ember 也会重新呈现页面。我该如何防止这种情况发生?有没有办法在 Handlebars 模板中添加某种检查来查看 movie.title 和 movie.year 是否不同?还是控制器内的检查仅在新模型不同时才设置新模型?

示例:

如果我输入 "how" 作为查询,页面将呈现:

  • 驯龙高手 (2010)
  • Grinch 如何偷走圣诞节 (2000)
  • Grinch 如何偷走了圣诞节! (1966)

如果我添加一个't',使我的查询变为“how t”,页面将重新呈现相同的内容,创建一个不必要的闪现的数据消失和相同数据再次出现:

  • 驯龙高手 (2010)
  • Grinch 如何偷走圣诞节 (2000)
  • Grinch 如何偷走了圣诞节! (1966)

代码:

HTML

<script type="text/x-handlebars" data-template-name="application">
    <div class="hero-unit">
    <h1>App</h1>
    {{outlet}}
    </div>
</script>
<script type="text/x-handlebars" data-template-name="index">
    {{input value=query}}
    <div class="prompt">
      {{prompt}}
    </div>

    {{#if moviesAvailable}}
      {{#each movie in movies}}
        <li>{{movie.title}} ({{movie.year}})</li>
      {{/each}}
    {{/if}}
</script>

Javascript(IndexController 中“查询”的更改会触发 MovieController 中“查询”的更改,从而提示它设置新模型)

var App;

App = Ember.Application.create();

App.Movie = DS.Model.extend({
  title: DS.attr('string'),
  year: DS.attr('number'),
  fanart: DS.attr('string'),
  poster: DS.attr('string'),
  overview: DS.attr('string')
});

App.IndexController = Ember.ArrayController.extend({
  needs: "movies",
  movies: Ember.computed.alias("controllers.movies"),
  query: '',
  prompt: '',
  moviesAvailable: false,
  queryChanged: (function() {
    var length;
    length = this.get('query').length;
    if (length === 0) {
      this.set('moviesAvailable', false);
      return this.set('prompt', 'Please type two more characters.');
    } else if (length === 1) {
      this.set('moviesAvailable', false);
      return this.set('prompt', 'Please type one more character.');
    } else {
      this.set('moviesAvailable', true);
      this.set('prompt', '');
      return this.get('movies').set('query', this.get('query'));
    }
  }).observes('query')
});

App.MoviesController = Ember.ArrayController.extend({
  queryChanged: (function() {
    var newmodel;
    newmodel = this.store.find('movie', {
      query: this.get('query'),
      limit: 3
    });
    return this.set('model', newmodel);
  }).observes('query')
});


App.MovieAdapter = DS.RESTAdapter.extend({
  host: 'http://api.trakt.tv/search/movies.json',
  namespace: '5aa5a25cfc06d869c136725b2b29d645',
  ajaxOptions: function(url, type, hash) {
    hash = this._super(url, type, hash);
    hash.dataType = 'jsonp';
    return hash;
  }
});

App.MovieSerializer = DS.RESTSerializer.extend({
  normalizeHash: {
    movie: function(hash) {
      hash.id = hash.tmdb_id;
      hash.fanart = hash.images.fanart;
      hash.poster = hash.images.poster;
      delete hash.images;
      return hash;
    }
  },
  normalizePayload: function(payload) {
    var json;
    json = {
      "movie": payload
    };
    return json;
  }
});

【问题讨论】:

    标签: javascript ember.js ember-data


    【解决方案1】:

    问题是它们是相似的结果,但不是同一个集合。

    ['a', 'b', 'c'] === ['a', 'b', 'c'] 是假的。它们是两个不同的集合,可能包含相同的值,看起来相似,但它们是不同的实例等。

    示例:http://emberjs.jsbin.com/OxIDiVU/698/edit

    如果您愿意,您可以滚动自己的收藏,并手动更新记录,这样可以避免整个收藏在它们是相同项目时消失和重新出现。但是,当它们不同时,它仍然会破坏。

      watchInput: function(){
        //model here is just an []
        var model = this.get('model');
    
        this.store.find('color', {
          limit:10
        }).then(function(results){
          var len = results.get('length'),
              curItem,
              newItem;
    
          for(var i = 0;i<len;i++){
            curItem = model.objectAt(i);
            newItem = results.objectAt(i);
            if(curItem!=newItem){
              if(!curItem){
                model.pushObject(newItem);
              } else{
                model.replace(i,1,[newItem]);
              }
    
            }
          }
          // maybe remove additional items if it only returns 1, or 2 or even 0 for that matter.
        })
      }.observes('stuff'),
    

    示例:http://emberjs.jsbin.com/OxIDiVU/697/edit

    另外,只是为了好玩,根据您的服务器的速度等,您可能希望在用户输入tththe 时消除更改请求以减轻一百万个请求...

    watchInput: function(){
        Ember.run.debounce(this, this.slowFetch, 400);
      }.observes('stuff'),
    

    http://emberjs.jsbin.com/OxIDiVU/721/edit

    附:尝试降低去抖率以获得乐趣,看看你打字时它触发的频率

    【讨论】:

      猜你喜欢
      • 2012-11-14
      • 1970-01-01
      • 1970-01-01
      • 2018-04-20
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      • 2021-02-26
      • 1970-01-01
      相关资源
      最近更新 更多