从脚本标记中排除HTML

use*_*485 5 html javascript handlebars.js

我正在尝试学习Handlebars.js,想到了一种在网站中使用它的方法.这是一个单页网站,它将有两个容器,每个容器有三个div,它们将通过API包含嵌入式Soundcloud播放器.

当在Handlebars处理的脚本标记中包含包含API请求的div时,该站点表现得非常不可靠并且仅显示六个玩家中的一些.这不是真的一致,但可以一直展示不同的球员.问题似乎是在Soundcloud javascript SDK中,但我觉得不太熟悉在那里挖掘太多.

因此我想到了一些方法来排除玩家div(见代码),以便他们立即加载而不是作为javascript处理,但仍然显示在艺术家的下方 - 占位符div中的标题(设置为包含结果Handlebar脚本).

问题是我无法想出一个很好的方法,有没有任何简单的功能(可能有Handlebars助手),这将帮助我做我想要的?

<div id="placeholder"></div>
<script id="player-template" type="text/x-handlebars-template">
            <div id="container1">
                    Artist1 - {{title1}}
                    <div id="player1"></div>
                    Artist2 - {{title2}}
                    <div id="player2"></div>
                    Artist3 - {{title3}}
                    <div id="player3"></div>
           </div>
           <div id="container2">
                    Artist4 - {{title4}}
                    <div id="player4"></div>
                    Artist5 - {{title5}}
                    <div id="player5"></div>
                    Artist6 - {{title6}}
                    <div id="player6"></div>
            </div>
    </script>
    <script src="js/handlebars_title_script.js"></script>
Run Code Online (Sandbox Code Playgroud)

一个解决方案当然是为每个Artist - Title div制作一个Handlebar模板,并将每个模板的占位符设置为仅包含Artist1 - {{title1}}的div,但这实际上破坏了使用Handlebars来最小化HTML编码的重点.

有人给我任何提示如何解决这个问题?

编辑1:

我通过更改我的javascript找到了另一种解决方案(我最初没有发帖,所以很明显你无法帮助我).

$(document).ready(function() {
    var hey = "heya";
    SC.get("/users/artist/tracks", {limit: 1}, function(tracks){
    var title_data1 = tracks[0].title;
    hey = tracks[0].title;
    alert(title_data1);
    alert(hey)
    });


//Data that will replace the handlebars expressions in our template
var playerData = {
    title1 : hey,
};

document.getElementById( 'player-placeholder' ).innerHTML = playerTemplate( playerData );

});
Run Code Online (Sandbox Code Playgroud)

抱歉不好意思.这段代码唯一的问题是title1(在变量playerData中是Handlebars上下文)得到变量的第一个值hey("heya").当它被警告它会弹出真实的标题时,如何让title1使用这个值而不将变量嵌入更多的javascript中(因为这是导致前面提到的错误,玩家出现奇怪的原因)?

kly*_*lyd 2

注意:在整个评论中,这个答案发生了巨大的变化。如果您想了解此答案的演变,请查看早期修订版。

在掌握了你的 JsFiddle 示例之后,我能够让它以我认为你想要的方式工作。

工作演示

HTML:

<body>
    <div id="wrapper">
        <div id="player-placeholder"><!-- rendered template goes here --></div>

        <!-- handlebars template: -->
        <script id="player-template" type="text/x-handlebars-template">
            {{#each tracks}}
                <div class="track">
                    <header class="header">
                        <span class="artist">{{user.username}}</span> - <span class="title">{{title}}</span>
                    </header>
                    <section class="player" data-uri="{{permalink_url}}">
                    </section>
                </div>
            {{/each}}
        </script>
    </div>
</body>
Run Code Online (Sandbox Code Playgroud)

JavaScript:

$(document).ready(function() {

  /*
    get your template string See:

    http://api.jquery.com/id-selector/
    http://api.jquery.com/html/
  */
  var source = $('#player-template').html();

  // compile the template into a handlebars function
  var template = Handlebars.compile(source);

  // initialize sound cloud api
  SC.initialize({
    client_id: '90fb9e15c1e26f39b63f57015ab8da0d'
  });

  /*
    This function will be called once the HTTP transaction
    started by SC.get(...) completes. Note, there's nothing
    wrong with doing this as an anonymous function, I'm
    simply assigning it to a variable to show that this
    is a distinct function that's called later
  */
  var callback = function(tracksResponse){
    /*
       once a response has been received, we'll use the response
       to generate a new context to pass to the template function.
       Note, you can use the template function in here because its
       within a closure. See:
       https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
    */
    var context = { tracks: tracksResponse };
    var html = template(context);

    /*
      assign the rendered html to your placeholder on the page
      see: http://api.jquery.com/html/
    */
    $('#player-placeholder').html(html);

    /*
      Now that the html is rendered and on the page, its time to
      setup the sound cloud players. Note the css classes I assigned
      to the track/player. This line selects all of the player's and
      runs the function over each. See:

      http://api.jquery.com/class-selector/
      http://api.jquery.com/each/
    */
    $('.track .player').each(function(index, e){
      var $this = $(this); // jQuery reference to the current object in 'each loop'

      /*
        I assigned the permalink_url of each track to an attribute called 'data-uri'
        This line gets the value of that attribute. See:

        http://api.jquery.com/data/#data2
      */
      var permalink = $this.data('uri'); 
      var urlParameters = '/&maxheight=100&maxwidth=300&format=json&sharing=false';

      /*
        finally we call the sound cloud oEmbed function feeding it the url
        stored in the element, as well as the actual element.

        (see the second argument of the each function: http://api.jquery.com/each/)
      */
      SC.oEmbed(permalink + urlParameters, e);
    });
  };

  // get tracks for your artist
  // Note the "limit" in the object controls the number of items returned
  // by sound cloud
  SC.get("/users/theshins/tracks", {limit: 5}, callback);
});
Run Code Online (Sandbox Code Playgroud)

什么地方出了错?

JavaScript 是一种单线程、异步、事件驱动的语言。这个巨大的满嘴意味着 JavaScript 并没有真正的线程概念(我故意忽略 WebWorkers)。为了解决这个限制,JavaScript 中几乎所有 IO 都是非阻塞(异步)的。

每当异步 IO 事务开始时,它都会立即返回调用者并继续执行代码。几乎所有 IO 事务都会采取“回调”或具有在 IO 事务完成时调用的事件。这意味着所有 IO 操作的基本模式如下:

  • 创建回调函数
  • 调用 IO 操作,向其传递完成所需的参数以及回调
  • 执行立即返回
  • 将来某个时候,回调函数会被调用

在原始示例中,$(document).ready(function() { ... })当引发 document.onReady 事件时,将匿名函数排队以触发。然而,您最初的示例分配了两个回调。这不是问题,事实上它的.ready(...)设计目的是接受许多回调并将其排队。然而,你出错的地方是你有两个单独的代码块,它们调用了SC.get(...).

从技术上讲,如果做得正确,这不会成为问题,但第一个就绪回调的目的是设置页面的 HTML,而第二个回调尝试根据页面上的 html 初始化播放器控件。请记住,这些事件和 IO 操作是异步的,它们会以任何顺序触发。本质上,这成为一个计时问题,您试图初始化页面上的控件,并同时生成 HTML 以在页面上显示。

它是如何修复的

要解决计时问题,您需要在获取信息、构建 HTML 模板以及初始化控件时进行同步。有很多方法可以做到这一点,并且许多框架都支持Promise的想法,以帮助控制异步事件的触发顺序及其回调的调用。

我采用了简单的路线,将所有SC.get调用合并为一个,然后在其回调中渲染车把模板并初始化 SoundCloud 播放器。