【问题标题】:View not initializing in Backbone.js查看未在 Backbone.js 中初始化
【发布时间】:2023-02-24 05:16:31
【问题描述】:

我创建了一个简单的主干应用程序,它从 MySQL 数据库中获取有关用户的数据,以显示在名为 LeaderBoard View 的视图中。 下面是视图的 HTML 代码,

<body>
<div id="container"></div>
<h1>Leaderboard</h1>
<table class="table" id="modtable">
  <tr>
     <th>Username</th>
     <th>Level</th>
  </tr>
 </table>
 <div id="bbcontent"></div>

我试图获取数据并使用 bbcontent 作为 id 填充到 div 中。 下面是我的 Backbone 模型、集合和视图,

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/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.2.3/backbone-min.js"> 
</script>


<script language="javascript">
  $(document).ready(function() {
     alert("heyyyyyy")
     //model
     var User = Backbone.Model.extend({
        idAttribute: "userId",
        defaults: {
           username: null,
           userLevel: null
        }
     });

     //collection
     var Users = Backbone.Collection.extend({
        model: User,
        url: "/CW2/ASSWDCW2/cw2app/index.php/Leaderboard/leaderboard",
     });

     var usersC = new Users();

     var LeaderboardDeetsView = Backbone.View.extend({
        model: usersC,
        el: $('#bbcontent'),
        intialize: function() {
           alert("asndasnxdjksa")
           usersC.fetch({
              async: false
           })
           this.render()
        },
        render: function() {
           var self = this;
           usersC.each(function(c) {
              var block = "<div class='name'><h1>" + c.get('username') + "</h1></div>"
              self.$el.append(block)
           })
        }
     })

     var leaderboardDeetsView = new LeaderboardDeetsView();
  });

此代码的问题:LeaderboardDeetsView 未被调用,因此 LeaderboardDeetsView 的初始化函数内的集合获取函数未被调用。如何更正我的代码?请帮忙

【问题讨论】:

  • 你是说initialize不是intialize@Kavishka Rajapakshe。

标签: javascript jquery backbone.js underscore.js backbone-views


【解决方案1】:

我发现您的代码有 11 个问题。前两个阻止您的代码按预期工作:

  1. 作为 DSDmark pointed out,您的代码中有一个拼写错误:intialize 而不是 initialize。由于这个原因,该方法将不会运行。
  2. initialize 方法中,您正在尝试同步获取用户,以便立即呈现它们。 las,没有同步请求这样的东西,所以您的视图将呈现一个空集合。在良好的 Backbone 风格中,你需要监听事件所以你知道什么时候是渲染的正确时间:
    initialize: function() {
       // { async: false } does not do anything, so we may as well 
       // remove it.
       usersC.fetch()
       // You can still render immediately, in case the users have
       // already been fetched before the view was constructed,
       this.render()
       // ... but in any case, you probably want to re-render whenever
       // the data change (such as when the above request completes).
       this.listenTo(usersC, 'update', this.render);
    },
    

    接下来的六个问题是错失的遵循最佳实践的机会。这些目前不会破坏您的代码,但它们很可能在未来:

    1. 您将usersC设置为LeaderboardDeetsViewmodel,但它是一个集合。视图同时具有 modelcollection 属性,因此您应该根据各自的用途使用它们。
    2. 您正在设置model(应该是collection在原型上.虽然这在原则上可行,但您不能使用此机制来拥有多个 LeaderboardDeetsView 实例,每个实例都呈现不同的用户列表(因为它们都共享相同的原型)。出于这个原因,View 构造函数接受一个带有 modelcollection 属性的选项对象,因此您可以为每个视图提供自己独特的模型:
    var LeaderboardDeetsView = Backbone.View.extend({
       el: $('#bbcontent'),
       initialize: function() {
          this.collection.fetch()
          this.render()
          this.listenTo(this.collection, 'update', this.render);
       },
       render: function() {
          var self = this;
          this.collection.each(function(c) {
             var block = "<div class='name'><h1>" + c.get('username') + "</h1></div>"
             self.$el.append(block)
          })
       }
    })
    
    var leaderboardDeetsView = new LeaderboardDeetsView({
       collection: usersC,
    });
    
    1. 在几个地方,您没有用分号 (;) 结束您的语句。大多数时候,JavaScript 会让你摆脱这种情况,但并非总是如此。训练自己严格遵守这一点,并避免一些不愉快和令人困惑的意外发生!
    2. 在 MVC 范例中,视图不应该决定何时获取数据,除非它是为了响应用户操作(在这种情况下视图扮演控制器的角色)。在您的情况下,由于您希望在启动应用程序后立即获取数据,因此对 fetch 的调用属于视图之外。
    3. LeaderboardDeetsView 的类定义中,您将el 设置为已解析的jQuery 实例。它在这种情况下工作正常,但在一般情况下,具有给定选择器的元素可能还不存在。将 el 设置为一个选择器字符串,视图将在构建视图时自动为您执行此查找。
    4. 按照约定,视图的 render 方法应返回 this,以便您可以在它之后继续链接方法。大多数其他尚未返回其他值的方法也是如此。考虑到目前的所有问题,您的代码现在应该如下所示:
    //model
    var User = Backbone.Model.extend({
       idAttribute: "userId",
       defaults: {
          username: null,
          userLevel: null
       }
    });
    
    //collection
    var Users = Backbone.Collection.extend({
       model: User,
       url: "/CW2/ASSWDCW2/cw2app/index.php/Leaderboard/leaderboard",
    });
    
    var usersC = new Users();
    // Fetch the collection right after construction.
    usersC.fetch();
    
    var LeaderboardDeetsView = Backbone.View.extend({
       // Selector string will be jQuery-wrapped automatically.
       el: '#bbcontent',
       initialize: function() {
          // We can chain listenTo after render because of "return this".
          this.render().listenTo(this.collection, 'update', this.render);
       },
       render: function() {
          var self = this;
          this.collection.each(function(c) {
             var block = "<div class='name'><h1>" + c.get('username') + "</h1></div>";
             self.$el.append(block);
          });
          // This last line enables chaining!
          return this;
       }
    });
    
    var leaderboardDeetsView = new LeaderboardDeetsView({
       collection: usersC,
    });
    

    最后三个问题错失了从可用的最新最好的库中获益的机会:

    1. 您使用的是非常过时的 jQuery、Underscore 和 Backbone 版本。这些都是非常稳定的库,因此您可以受益于七年多的错误修复、性能提升和与现代浏览器的改进兼容性,所有这些都无需更改代码中的单个字符!
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"> 
    </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.13.6/underscore-  
    min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.4.1/backbone-min.js"> 
    </script>
    
    1. 为集合中的每个模型呈现相同的东西是几乎每个 Web 应用程序都需要做的事情。当然有些图书馆可以为您简化这项工作。下面,我展示了如何使用我编写的小型库 backbone-fractal 重写 LeaderboardDeetsView。或者,您可以使用 Marionette 中的 CollectionView(但在这种情况下语法不同)。这使您的代码更加模块化、更易于理解以及更易于测试和维护。
    // A simple, dedicated view for a single entry in the leaderboard.
    var UserView = Backbone.View.extend({
       className: 'name',
       initialize: function() { this.render(); },
       render: function() {
          this.$el.html('<h1>' + c.get('username') + '</h1>');
          return this;
       }
    });
    
    // A simple view for the entire leaderboard, all automatic.
    var LeaderboardDeetsView = BackboneFractal.CollectionView.extend({
       el: '#bbcontent',
       subview: UserView,
       initialize: function() {
          this.initItems().render().initCollectionEvents();
       }
    });
    
    1. 使用模板生成 HTML 代码,而不是将字符串与手写的 JavaScript 代码连接起来。这使得负责生成 HTML 的代码更易于阅读和编辑。如果您想保持便宜,可以使用 Underscore 的内置 template function。如果您想更认真地对待您的模板,您还可以使用专用模板库,例如HandlebarsWontache。下面,我演示了 Underscore 的 _.template 如何适用于上一点的 UserView
    var UserView = Backbone.View.extend({
       className: 'name',
       // The template: a declarative description of the HTML you want to
       // generate.
       template: _.template('<h1><%- username %></h1>'),
       initialize: function() { this.render(); },
       render: function() {
          // Using the template. Conventional notation.
          this.$el.html(this.template(this.model.toJSON()));
          return this;
       }
    });
    

    这是代码的最终版本,实现了上述所有要点。是不是看起来时尚、简洁和模块化?

    var User = Backbone.Model.extend({
       idAttribute: "userId",
       defaults: {
          username: null,
          userLevel: null
       }
    });
    
    var Users = Backbone.Collection.extend({
       model: User,
       url: "/CW2/ASSWDCW2/cw2app/index.php/Leaderboard/leaderboard",
    });
    
    var usersC = new Users();
    usersC.fetch();
    
    var UserView = Backbone.View.extend({
       className: 'name',
       template: _.template('<h1><%- username %></h1>'),
       initialize: function() { this.render(); },
       render: function() {
          this.$el.html(this.template(this.model.toJSON()));
          return this;
       }
    });
    
    var LeaderboardDeetsView = BackboneFractal.CollectionView.extend({
       el: '#bbcontent',
       subview: UserView,
       initialize: function() {
          this.initItems().render().initCollectionEvents();
       }
    });
    
    var leaderboardDeetsView = new LeaderboardDeetsView({
       collection: usersC,
    });
    

【讨论】:

    猜你喜欢
    • 2015-01-12
    • 2017-11-25
    • 2012-08-30
    • 2013-03-09
    • 2012-06-27
    • 1970-01-01
    • 2012-01-29
    • 1970-01-01
    • 2012-04-16
    相关资源
    最近更新 更多