javascript - 如何使用 JSON 为交互式 Backbone.js 应用程序提供支持

标签 javascript json backbone.js

我正在致力于将一系列交互式教育应用程序从 Flash 转换为 Javascript,我的团队计划使用 Backbone.js 作为框架。这些应用程序基本上都是场景的集合,以问题或交互式小部件的形式向用户呈现信息和/或提示一些交互。我们正在考虑的应用程序的基本结构如下:

  • 一组 JSON 文件,其中包含每个应用的特定信息,例如应用有多少个不同的“场景”或对象、向用户显示的不同消息和/或小部件等。
  • 一组 Backbone(可能是下划线)模板,用于管理如何显示导航、消息等。
  • 主干 View /路由器/模型的集合,以方便在应用中的场景之间导航并处理用户交互
  • 一些内置 Javascript 的交互式小部件

当然,问题是我在 Backbone 方面还是个新手。我已经完成了一些基本教程,但在将 Backbone 与静态 JSON 文件集成时遇到问题。

假设我有以下非常基本的 JSON 文件,其中列出了要显示的三个场景:

var scenes = [
{
    "name": "Introduction",
    "label": "Introduction",
    "message": "Welcome to this app"
},
{
    "name": "Exercise",
    "label": "Exercise",
    "message": "If this were a real app, there'd be some sort of exercise here"
},
{
    "name": "Conclusion",
    "label": "Conclusion",
    "order": "Thank you for completing this app"
}
]

我需要的,也是我正在尝试做的,是让 Backbone 生成一个导航小部件,让用户可以在这些场景之间导航并显示每个场景的消息。 (这显然是现实应用程序的一个极其简化的版本。)

这是我尝试过的:

// simplified object containing stage information
  var stages = [
    {
        "name": "Introduction",
        "label": "Introduction",
        "message": "Welcome to this app"
    },
    {
        "name": "Exercise",
        "label": "Exercise",
        "message": "If this were a real app, there'd be some sort of exercise here"
    },
    {
        "name": "Conclusion",
        "label": "Conclusion",
        "order": "Thank you for completing this app"
    }
  ];
$(function(){



  // create model for each stage
  StageModel = Backbone.Model.extend({});

  // create collection for StageModel
  StageModelList = Backbone.Collection.extend({
    model: StageModel
  });

  var stageModelList = new StageModelList();

  // create view for list of stages
  StageListView = Backbone.View.extend({

    el: $("#stageNav"),

    initialize: function() {
      // if stages are added later
        stagemodellist.bind('add',this.createStageList, this);
    },

    events: {
      'click .stageListItem' : 'selectStage'
    },

    createStageList: function(model) {
        $("#stageList").append("<li class='stageListItem'>"+model.label+"</li>");
    },

    selectStage: function() {
      this.router.navigate("stage/"+this.stage.name,true);
    }

    });

    // create view for each stages

  StageView = Backbone.View.extend({
    el: $("#stage"),

    initialize: function(options) {
      // get stage variable from options
      this.stage = this.options.stage;
      // display stage
      createOnEnter(this.stage);

    },

    createOnEnter: function(stage) {
      $("#stageLabel").html(stage.label);  
      $("#stageMsg").html(stage.message);
    }
  });

    // create router
    AppRouter = Backbone.Router.extend({

        initialize: function() {
          Backbone.history.start();
          // create collection
          new StageModelList();
          // create view when router is initialized
          new StageListView();
          // loop through stages and add each to StageModelList
          for (var s in stages) {
            StageModelList.add(stages[s]); 
          }
        },

        routes: {
            "stage/:stage" : "renderStage"
        },

        renderStage: function(stage) {
          // display StageView for this stage
          new StageView({stage:stage});

        }

    });


    var App = new AppRouter();

});

和 html:

<!DOCTYPE html>
<html>
<head>
<script class="jsbin" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script class="jsbin" src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<script class="jsbin" src="http://documentcloud.github.com/backbone/backbone.js"></script>
<script src="js/ilo4.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
  <p>My pathetic attempt at a Backbone.js app</p>
  <div id="stageNav">
    <ul id="stageList">

    </ul>
  </div>
  <div id="stage">
    <div id="stageLabel">

    </div>
    <div id="stageMsg">

    </div>
  </div>
</body>
</html>

(您还可以在此处查看 jsbin 版本: http://jsbin.com/iwerek/edit#javascript,html,live )。

不幸的是,目前这没有任何作用。

我知道我在这里做错了很多事情,还有一些我正在讨论的问题:

  • 我还需要路由器吗?
  • 我需要将集合初始化为变量吗?
  • 是否有更好的方法将模型绑定(bind)到阶段列表?

一个

最佳答案

其实你离得并不远。

我已经克隆了你的 jsbin 并对其进行了修复,使其可以正常工作:link

我将其作为对您问题的回答。我已经对其进行了非常彻底的评论以解释发生了什么。

看看吧,希望对你有帮助。

编辑:到底是什么,我也将代码放在这里:

// simplified object containing stage information
window.stages = [
  {
    "name": "Introduction",
    "label": "Introduction",
    "message": "Welcome to this app"
  },
  {
    "name": "Exercise",
    "label": "Exercise",
    "message": "If this were a real app, there'd be some sort of exercise here"
  },
  {
    "name": "Conclusion",
    "label": "Conclusion",
    "message": "Thank you for completing this app"
  }
];

$(function(){

  // StageModel: no need to extend if you're not adding anything.
  StageModel = Backbone.Model;

  // StageCollection
  StageCollection = Backbone.Collection.extend({
    model: StageModel
  });

  // create view for list of stages
  StageCollectionView = Backbone.View.extend({

    el: $("#stageNav"),

    initialize: function() {
      // if stages are added later
      this.collection.bind('add', this.createStageListItem, this);
    },

    events: {
      'click .stageListItem' : 'selectStage'
    },

    // I'm adding the model's cid (generated by backbone) as the 
    // id of the 'li' here. Very non-ideal, as one of the points
    // of backbone et al. is to keep from embedding and retrieving
    // data from the DOM like this.
    //
    // Perhaps better would be to create a StageListItemView and 
    // render one for each model in the collection, perhaps like:
    //    
    //    createStageListItem: function(model) {
    //      this.$('#stageList').append(new StageListItemView({model: model});
    //    }
    //
    // where you have a StageListItemView that knows how to render
    // itself and can handle click events and communicate with the
    // collectionview via events.
    //
    // At any rate, this string-munging will suffice for now.
    createStageListItem: function(model) {
      this.$("#stageList").append("<li id=\"" + model.cid + "\" class='stageListItem'>" + model.get('label') + "</li>");
    },

    // Use backbone's event system, it's pretty awesome. Not to mention
    // that it helps to decouple the parts of your app.
    //
    // And note that you can pass arguments when you trigger an event.
    // So any event handler for the 'new-stage' event would receive
    // this model as its first argument.
    selectStage: function(event) {
      var cid = $(event.target).attr('id');
      this.trigger('new-stage', this.collection.getByCid(cid));
    },

    // This was a missing puzzle piece. Your StageCollectionView wasn't
    // being rendered at all.
    //
    // Backbone convention is to call this function render, but you could
    // call it whatever you want, as long as you, well, end up _calling_ it.
    render: function() {
      var self = this;
      this.collection.each(function(model) {
        self.createStageListItem(model);
      });
      return this;
    }

  });

  // StageView, 
  StageView = Backbone.View.extend({
    el: $("#stage"),

    // We're going to assume here that we get passed a 
    // newStageEventSource property in the options and 
    // that it will fire a 'new-stage' event when we need
    // to load a new stage.
    initialize: function(options) {
      this.eventSource = options.newStageEventSource;
      this.eventSource.bind('new-stage', this.loadAndRenderStage, this);
    },

    // A load function to set the StageView's model.
    load: function(model) {
      this.model = model;
      return this;
    },

    render: function() {
      $("#stageLabel").html(this.model.get('label'));  
      $("#stageMsg").html(this.model.get('message'));
    },

    loadAndRenderStage: function(stage) {
      this.load(stage);
      this.render();
    }
  });

  // Instatiate a StageCollection from the JSON list of stages.
  // See Backbone docs for more, but you can pass in a list of
  // hashes, and the Collection will use its model attribute to 
  // make the models for you
  var stageCollection = new StageCollection(stages);

  // View constructors take an options argument. Certain properties
  // will automatically get attached to the view instance directly,
  // like 'el', 'id', 'tagName', 'className', 'model', 'collection'.
  var stageCollectionView = new StageCollectionView({
    collection: stageCollection
  });

  // Instantiate the StageView, passing it the stageCollectionView in
  // the options for it to listen to.
  var stageView = new StageView({
    newStageEventSource: stageCollectionView
  });

  // Last step, we need to call 'render' on the stageCollectionView
  // to tell it to show itself.
  stageCollectionView.render();

});

关于javascript - 如何使用 JSON 为交互式 Backbone.js 应用程序提供支持,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8670077/

相关文章:

javascript - 为什么 xpath 选择空格?

javascript - 将数据传递到 d3js

javascript - angularjs 将 json 对象转换为数组

c# - 错误 CS0433 : The type 'JsonValue' exists in both 'System.Json, Version=2.0.5.0' and 'Xamarin.Auth' (CS0433)

javascript - 主干数据类型 - 类型转换?

javascript - 使用 JavaScript 从 HTML 元素中删除类

javascript - 如何使用 FormData 将文件发送到 Nodejs 并让 Node 发回确认消息?

javascript - 主干模板方法差异

javascript - 无法从@Url.Action 访问变量

javascript - 关于使用 backbone.js 的 setTimeout 的各种问题。清除并恢复超时