Лучший способ асинхронной загрузки шаблонов подчеркивания

Я планирую использовать backbone.js и underscore.js для создания веб-сайта, и у меня будет много шаблонов подчеркивания:

<script type="text/template" id="search_template">
<p id="header">
//header content will go here
</p>
<p id="form">
    <label>Search</label>
    <input type="text" id="search_input" />
    <input type="button" id="search_button" value="Search" />
</p>
<p id="dynamic_date">
//dynamic data will be displayed here
</p>
</script>

Конечно, мои шаблоны будут намного сложнее.

Поскольку у меня их будет много, я не хочу загружать все шаблоны каждый раз при загрузке страницы. Я хочу найти решение, где я могу загрузить определенный шаблон только тогда, когда он будет использоваться.

Другое дело, что большинство моих шаблонов будут иметь такую ​​же структуру, только теги <p id="form"></p> и <p id="dynamic_date"></p> будут отличаться.

Не могли бы вы предложить мне, как мне это сделать?

Спасибо,

Ответ 1

Редактировать: я провел некоторое исследование и портировал свой код iCanHaz, чтобы подчеркнуть, что он также использует localStorage

Вот репозиторий github: https://github.com/Gazler/Underscore-Template-Loader

Код:

  (function() {
    var templateLoader = {
      templateVersion: "0.0.1",
      templates: {},
      loadRemoteTemplate: function(templateName, filename, callback) {
        if (!this.templates[templateName]) {
          var self = this;
          jQuery.get(filename, function(data) {
            self.addTemplate(templateName, data);
            self.saveLocalTemplates();
            callback(data);
          });
        }
        else {
          callback(this.templates[templateName]);
        }
      },

      addTemplate: function(templateName, data) {
        this.templates[templateName] = data;
      },

      localStorageAvailable: function() {
       try {
          return 'localStorage' in window && window['localStorage'] !== null;
        } catch (e) {
          return false;
        }
      },

      saveLocalTemplates: function() {
        if (this.localStorageAvailable) {
          localStorage.setItem("templates", JSON.stringify(this.templates));
          localStorage.setItem("templateVersion", this.templateVersion);
        }
      },

      loadLocalTemplates: function() {
        if (this.localStorageAvailable) {
          var templateVersion = localStorage.getItem("templateVersion");
          if (templateVersion && templateVersion == this.templateVersion) {
            var templates = localStorage.getItem("templates");
            if (templates) {
              templates = JSON.parse(templates);
              for (var x in templates) {
                if (!this.templates[x]) {
                  this.addTemplate(x, templates[x]);
                }
              }
            }
          }
          else {
            localStorage.removeItem("templates");
            localStorage.removeItem("templateVersion");
          }
        }
      }



    };
    templateLoader.loadLocalTemplates();
    window.templateLoader = templateLoader;
  })();

Вызов будет выглядеть примерно так:

      templateLoader.loadRemoteTemplate("test_template", "templates/test_template.txt", function(data) {
        var compiled = _.template(data);
        $('#content').html(compiled({name : 'world'}));
      });

Вот мой оригинальный ответ

Вот метод, который я написал для ICanHaz (усы), который выполняет эту точную функцию по той же причине.

window.ich.loadRemoteTemplate = function(name, callback) {
  if (!ich.templates[name+"_template"]) {
    jQuery.get("templates/"+name+".mustache", function(data) {
      window.ich.addTemplate(name+"_template", data);
      callback();
    });
  }
  else {
    callback();
  }
}

Затем я вызываю его так:

ich.loadRemoteTemplate(page+'_page', function() {
  $('#'+page+'_page').html(ich[page+'_page_template']({}, true));
});

Ответ 2

Мне очень нравится, как команда stackoverflow сделала шаблоны с помощью mvc-miniprofiler. Взгляните на эти ссылки:

Includes.js (ссылка Github)

Includes.tmpl (ссылка Github)

Они используют локальное хранилище для локального кэширования шаблонов, если ваш браузер поддерживает локальное хранилище. Если нет, они просто загружают его каждый раз. Его довольно гладкий способ обработки шаблонов. Это также позволяет вам сохранять свои шаблоны, которые не требуются сразу в отдельном файле, а не загромождать ваш html.

Удачи.

Ответ 3

Хотя оба вышеупомянутых ответа работают, я нашел следующее более простым подходом.

Помещает ваши шаблоны, заключенные в теги script в файл (скажем, "templates.html" ) следующим образом:

<script type="text/template" id="template-1">
  <%- text %>
</script>

<script type="text/template" id="template-2">
  oh hai!
</script>

Затем следующий бит javascript:

$(document).ready(function() {
  url ='http://some.domain/templates.html'
  templatesLoadedPromise = $.get(url).then(function(data) {
    $('body').append(data)
    console.log("Async loading of templates complete");
  }).fail(function() {
    console.log("ERROR: Could not load base templates");
  });
});

Что тогда позволяет вам выбирать свои шаблоны достаточно просто с помощью идентификаторов, которые вы ранее определили. Я добавил обещание

$.when(templatesLoadedPromise).then(function() {
  _.template($('#template-1').html(), {'text':'hello world'} )
});

Затем вы можете расширить это и загрузить несколько файлов, если хотите.

В качестве побочного примечания я обнаружил, что любые основные шаблоны, необходимые для первоначального рендеринга страницы, лучше встроены в HTML (я использую модули торнадо на сервере), но этот подход работает очень хорошо для любых шаблонов, которые необходимы позже ( например, в моем случае шаблоны для виджета регистрации, которые я хочу использовать на разных страницах, идеально подходят для этого, поскольку он будет загружаться только при взаимодействии с пользователем и не является ядром для страницы).