1

我有一个在服务器和客户端上同时使用 Backbone 和 Handlebars 的应用程序。

服务器

已安装主干和 Express-Handlebars

应用程序.js

app.set('views', path.join(__dirname, '/views'));
app.engine('.hbs', expHbs({
  defaultLayout: 'index', 
  extname: '.hbs'
}));
app.set('view engine', '.hbs');

index.js

exports.init = function(req, res){
  res.render('contact/index');
};

索引.hbs

<div class="row">
  <div class="col-sm-6">
    <div class="page-header">
      <h1>Send A Message</h1>
    </div>
    <div id="contact"></div>
  </div>
  ....some code

<script id="tmpl-contact" type="text/x-handlebars-template">
  <form>

      bootstrap with handlebars temlates {{....}} in here

  </form>
</script>

客户

在客户端上,我通过 Bower 安装了 Backbone 和 Handlebars

index.js Backbone.view

var Handlebars = require('handlebars');
  app.ContactView = Backbone.View.extend({
    el: '#contact',
    template: Handlebars.compile( $('#tmpl-contact').html() ),
    events: {
      'submit form': 'preventSubmit',
      'click .btn-contact': 'contact'
   },
    initialize: function() {
      this.model = new app.Contact();
      this.listenTo(this.model, 'sync', this.render);
      this.render();
    },
    render: function() {
      this.$el.html(this.template( this.model.attributes ));
      this.$el.find('[name="name"]').focus();
   },
    preventSubmit: function(event) {
      event.preventDefault();
   },
    contact: function() {
      this.$el.find('.btn-contact').attr('disabled', true);

      this.model.save({
        name: this.$el.find('[name="name"]').val(),
        email: this.$el.find('[name="email"]').val(),
        message: this.$el.find('[name="message"]').val()
      });
    }
  });

发生的情况是 index.hbs 在服务器端正常呈现,但它没有在脚本内呈现表单;它显示为空<div id="contact"></div>,并且在控制台中没有显示任何错误。

如此处所示Using Handlebars with Backbone,用车把替换下划线模板的一种方法是简单地替换_.templateHandlebars.compile,但这些选项都不适合我。我还尝试了不同的类型属性<script>,但它仍然无法正常工作。

我怎样才能解决这个问题?任何帮助表示赞赏。谢谢。

在客户端添加了完整的 index.js

/* global app:true */

var Handlebars = require('Нandlebars');

(function() {
  'use strict';

  app = app || {};

  app.Contact = Backbone.Model.extend({
    url: '/contact/',
    defaults: {
      success: false,
      errors: [],
      errfor: {},
      name: '',
      email: '',
      message: ''
    }
  });

  app.ContactView = Backbone.View.extend({
    el: '#contact',
    template: Handlebars.compile( $('#tmpl-contact').html() ),
    events: {
      'submit form': 'preventSubmit',
      'click .btn-contact': 'contact'
    },
    initialize: function() {
      this.model = new app.Contact();
      this.listenTo(this.model, 'sync', this.render);
      this.render();
    },
    render: function() {
      this.$el.html(this.template( this.model.attributes ));
      this.$el.find('[name="name"]').focus();
    },
    preventSubmit: function(event) {
      event.preventDefault();
    },
    contact: function() {
      this.$el.find('.btn-contact').attr('disabled', true);

      this.model.save({
        name: this.$el.find('[name="name"]').val(),
        email: this.$el.find('[name="email"]').val(),
        message: this.$el.find('[name="message"]').val()
          });
        }
     });

  $(document).ready(function() {
    app.contactView = new app.ContactView();
  });
}());
4

1 回答 1

1

所以这里提到的Handlebars.compile必须在把手模板<script></script>加载到 DOM 之后加载。在这种情况下,当使用 express-hanldebars 时,必须将指向 js 文件的链接放在{{{ body }}}主布局中的元素之后。这是正确的答案。

这里还有一个问题app不能像index.js中那样全局定义

为了app全局定义,您必须移出app = app || {};IIFE 范围并将其放在文件的开头并将其声明为全局变量:var app = app || {};. 如果有多个主干文件,它们都应该实现类似的结构以便app全局化。

于 2017-02-25T21:32:19.710 回答