Meteor渲染回调并应用jQuery插件

在将jQuery插件(如滑块或同位素)应用于从Meteor加载动态内容的DOM元素集合时寻找模式。

如果你调用template.rendered ( doc here )似乎是一个合乎逻辑的选择。 渲染模板时应用jQuery。

根据Blaze wiki template.rendered现在只调用一次。 听起来不错。 但是,它没有提到在将template.rendered的内容应用于DOM 之前调用template.rendered。

所以推荐的方法是将内部元素放入{{#each}}子模板,然后在rendered回调上调用jQuery。

但是:大多数jQuery插件不能以这种方式工作。 需要在父DOM元素上调用它们,并且子DOM元素需要已经就位。

有些人甚至建议在父元素上使用setTimeout来近似何时呈现子元素 。 这对我来说听起来不够可靠。

这是一个常见的例子:

page_slider.html

  
    {{#each slide}} {{> slider_item}} {{/each}}

page_slider.js

 Template.page_slider.rendered = function() { /* * Can't initialise jQuery slider here as * all inner DOM elements don't exist. * */ }; 

看子模板。

slider_item.html

  
  • slider_item.js

     Template.slider_item.rendered = function() { /* * Can't initialise jQuery slider here either * as I don't know if all slide elements have been loaded * */ }; 

    从上面的示例中可以看出,没有机会知道所有幻灯片何时加载到DOM中并因此调用jQuery插件。

    想知道是否有一些我忽略的东西,或者是否存在其他人正在使用的共同模式。

    我用来解决这个问题的模式如下:

    首先,我将用于在单独的辅助函数中提供#each块的游标外部化,因为我们稍后将重用它。

     // given a slider, return associated slides from the collection function slides(slider){ return Slides.find({ sliderId:slider._id }); } // assumes the slider template is called with a slider as data context Template.slider.helpers({ slides:function(){ return slides(this); } });  Template.pageSlider.helpers({ mySlider:function(){ return Sliders.findOne({ name:"mySlider" }); } }); 

    现在我们要做的是在#each块完成在DOM中插入我们的项之后执行代码,因此我们将“监听” #each块正在侦听的相同的被动数据源:这是为什么我们将游标声明为一个单独的函数。

    我们将设置一个反应计算来检测对底层Slides集合所做的更改,并且我们将执行一些代码,这些代码将等到#each块在DOM中呈现项目然后重新初始化jQuery滑块。

     Template.slider.rendered=function(){ this.autorun(_.bind(function(){ // we assume that the data context (this.data) is the slider doc itself // this line of code makes our computation depend on changes done to // the Slides collection var slidesCursor=slides(this.data); // we wait until the #each block invalidation has finished inserting items // in the DOM Deps.afterFlush(function(){ // here it is safe to initialize your jQuery plugin because DOM is ready }); }, this)); }; 

    Deps.afterFlush向我们保证,在完成#each块隐含的DOM渲染过程之后,我们运行插件初始化代码。

    setTimeout hack的工作原理是假设它将在刷新周期结束后触发,但是由于Deps API提供了一个专门设计用于在当前刷新周期结束后运行代码的方法,因此Deps

    作为一个快速回顾,这是这个代码在幕后发生的事情:

    • 调用Template.slider.rendered#each块尚未呈现滑块项。
    • 我们设置了反应计算,我们从Slides集合中监听更新(就像#each块正在进行自己独特的计算)。
    • 一段时间后, Slides集合被更新,#each块计算以及我们的自定义计算都失效 – 因为它们依赖于SAME游标 – 因此将重新运行。 现在棘手的部分是我们无法判断哪个计算首先重新运行,它可能是一个或另一个,以一种不确定的方式。 这就是我们需要在Deps.afterFlush回调中运行插件初始化的Deps.afterFlush
    • 执行#each块逻辑并将项插入DOM中。
    • 刷新周期(重新运行每个无效的计算)完成,因此执行我们的Deps.afterFlush回调。

    每当新项目被添加到模型中并随后由Blaze在DOM中呈现时,这种模式允许我们重新初始化我们的jQuery插件(轮播,类似砖石等等)。

    重新初始化过程取决于插件,大多数情况下,如果存在,您将要么调用reinit方法,要么手动销毁并重新创建插件。

    Meteor手册提供了DepsBlaze内部的很好的解释和示例,这绝对是推荐阅读:

    http://manual.meteor.com/

    您也可以使用此答案中指定的Meteor.defer()

    https://stackoverflow.com/a/31414707/3051080

     Template.templateNotInDomYet.onRendered(function(){ Meteor.defer(function(){ $(//code); }); });