Meteor 渲染回调和应用 jQuery 插件

Posted

技术标签:

【中文标题】Meteor 渲染回调和应用 jQuery 插件【英文标题】:Meteor rendered callback and applying jQuery Plugins 【发布时间】:2014-10-18 15:57:53 【问题描述】:

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

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

根据Blaze wiki template.rendered 现在只调用一次。听起来不错。然而,它没有提到 template.rendered 在模板的内容被应用到 DOM 之前 被调用。

因此推荐的方法是将内部元素放入 #each 子模板中,然后在其rendered 回调中调用 jQuery。

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

有些人甚至推荐a setTimeout on the parent element to approximate when the child elements will be rendered。这对我来说听起来不够可靠。

这是一个常见的例子:

page_slider.html

<template name="page_slider">
  <div class="slider">
    <ul class="slides">
      #each slide
        > slider_item
      /each
    </ul>
  </div>
</template>

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

<template name="slider_item">
  <li class="slide"><img src="image"/></li>
</template>

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 插件。

想知道我是否忽略了某些东西,或者目前是否有其他人正在使用的常见模式。

【问题讨论】:

看看这 2 个答案,我认为您正在解决的具体问题已得到详细解决。 ***.com/questions/25354070/… & ***.com/questions/25450826/… 【参考方案1】:

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

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

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

【讨论】:

【参考方案2】:

我用于解决此目的的模式如下:

首先,我将用于提供 #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 name="pageSlider">
  > slider mySlider
</template>

Template.pageSlider.helpers(
  mySlider:function()
    return Sliders.findOne(
      name:"mySlider"
    );
  
);

现在我们要做的是在 #each 块完成将我们的项目插入 DOM 之后执行代码,因此我们将“侦听”#each 块正在侦听的同一个响应式数据源to :这就是我们将游标声明为单独函数的原因。

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

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 提供了一种专门设计用于在当前刷新周期结束后运行代码的方法。

快速回顾一下,这就是这段代码在后台发生的事情:

Template.slider.rendered 已被调用,但 #each 块尚未呈现您的滑块项。 我们的反应式计算已设置完毕,我们会监听来自 Slides 集合的更新(就像 #each 块在其自己的不同计算中所做的那样)。 一段时间后,Slides 集合被更新,#each 块计算以及我们的自定义计算都无效 - 因为它们依赖于 SAME 游标 - 因此将重新运行。现在棘手的部分是我们无法确定哪个计算将首先重新运行,它可能是一个或另一个,以一种不确定的方式。这就是为什么我们需要在 Deps.afterFlush 回调中运行插件初始化。 #each 块逻辑被执行,项目被插入到 DOM 中。 刷新周期(重新运行每个无效的计算)完成,我们的Deps.afterFlush 回调因此被执行。

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

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

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

http://manual.meteor.com/

【讨论】:

哇。非常感谢您花时间解释这一点。我还花了 30 分钟阅读手册中的 Deps。了解 Deps 的工作原理确实有助于我对 Meteor 的整体理解。 老兄,太棒了。我希望我能 +10。

以上是关于Meteor 渲染回调和应用 jQuery 插件的主要内容,如果未能解决你的问题,请参考以下文章

由于 Meteor 升级到 0.8.0,当 Session 变量依赖发生变化时,不会触发模板“rendered”回调

带有方法和全局回调的 jQuery 插件

如何将第三方 JavaScript 库添加到 Meteor 应用程序?

jquery组织架构图插件

React-Router 和 Meteor 无法在刷新时使用参数渲染路由

使用 Backbone 路由器重新渲染 Meteor 页面