流星:强制渲染元素

Meteor: Force rendering an element

我有一个通用模板在我的应用中多次使用:

<template name="genericCollapse">
  {{data-1}}
  <a href=# class='collapsed' data-toggle='collapse'
     data-target='#uniqueId'>Show/hide data-2</a>
  <div class='collapse' id='uniqueId'>
    {{data-2}}
  </div>
</template>

通过点击应用中的其他位置,data-1 和 data-2 会同时更改(使用会话变量)。但是,如果模板已经在屏幕上,则只有 data-1 和 data-2 发生变化,但 div 的折叠状态保持(显然)不变。如果它之前打开过,它将保持打开状态。

我想实现的是,每当 data-1/data-2 发生变化时,div 和 a 都被迫再次处于折叠状态。 我尝试添加

<a href=# class='{{collapsed}}'

Template.genericCollapse.helpers({
  collapsed () {return "collapsed " + Random.Id()},
})

这不仅非常丑陋,而且也没有帮助,因为 div 的 class 仍然保留 "collapse show",即使 div 有第二个助手,我无法摆脱 "show".

重新渲染整个模板也是可以接受的,但我很难确定调用 Blaze.render() 的父节点——它永远不一样——而且我也不确定放在哪里这样调用正确。

这是怎么做到的?

您可以通过将 class 返回到助手的元素来以流星的方式做到这一点,如下所示:

模板:

<template name="genericCollapse">
  {{data-1}}
  <a href=# class={{isCollapsed}} data-toggle='collapse'
     data-target='#uniqueId'>Show/hide data-2</a>
...
...
</template>

帮手:

Template.genericCollapse.helpers({

isCollapsed: function(){

    if()// logic to check if it needs to be collapsed
       return "collapsed"
    else
       return "collapse"
    }
});

看起来你在和 bootstrap 打架。当您单击 link 时, show class 是由 bootstrap 添加的,对吗​​?因为此 class 不是由您的 html 标记设置的,所以您需要在基础数据更改时自行删除它。您可以通过观察数据的变化,然后直接修改 DOM。

这是一个基本示例:

Template.myTemplate.onCreated(function () {
  const query = MyCollection.find({},{fields: {data-1: 1, data-2: 1}});
  const handle = query.observeChanges({
    changed(id, fields) {
      $('.show').removeClass('show');
    }
});

这假定存在一个包含您要控制的字段 data-1data-2 的集合。如果您的 data-1data-2 是执行某些计算的助手,那么您可能希望使用基于反应变量的 Tracker 来解决这个问题。

@Michel Floyd 关于战斗的说法是正确的 bootstrap。

但是,既然你说你正在使用 Session 变量,那么只需使用 auto运行 即可:

Template.genericCollapse.onRendered(function() {
  this.autorun(() => {
    const data1 = Session.get('data-1');
    const data2 = Session.get('data-2');
    if (data1 === someCondition || data2 === someOtherCondition) {
      this.$('.collapse').collapse('show');
    } else {
      this.$('.collapse').collapse('hide');
    }
});

任何时候 data-1data-2 发生变化,此功能将重新 运行

非常感谢您的帮助!

@Michel Floyd 让我意识到我的问题不是由任何与 Meteor 相关的问题引起的,而是 bootstrap.

@Fred Stark 为解决方案添加了一个很好的变体,他使用 auto运行 更像 Meteor 风格,他使用 .collapse('hide') 而不是 .removeClass('show') 至少在 iOS.

上提供了一些不错的淡出效果

因为我混淆了几个问题,我会一一澄清:

查找触发器: 您可以按照建议使用 auto运行 或 observeChanges,但最终两者都不是必需的,因为总是会调用 Meteor 助手。 第一次尝试:

<a href=# class='{{collapsed}}'

Template.genericCollapse.helpers({
  collapsed () {return "collapsed"},
})

当模板中的某些内容发生变化时,此助手中的代码将始终 运行。如果 data-1 或 data-2 由于任何原因发生变化,代码将被执行,所以这是我的触发器。

正确使用助手: 第一次尝试在 html 上没有任何作用,因为空格键 {{collapsed}} 没有改变它的内容。尽管执行了帮助程序代码,但 return 值不会更改,因此对 html 端没有影响。 为了看到任何变化,return 值每次都必须不同。 第二次尝试:

Template.genericCollapse.helpers({
  collapsed () {return "collapsed " + Random.Id()},
})

正如我已经说过的那样丑陋,但至少它为 a 设置了正确的 class。

去掉"show":米歇尔来了:因为div中的"show"是由Bootstrap控制的,你不能用任何类型的 spacebar/helper 来控制它——但是用 javascript。 第三次尝试:

Template.genericCollapse.helpers({
  collapsed () {
    $('.show').removeClass('show');
    return "collapsed " + Random.Id()},
})

这有效!如果存在具有 class "show" 的其他元素,可能有必要缩小“.show”的范围,但这是可行的方法。

美化: 将 Random.Id() 作为 class 仍然很糟糕。因此,让我们像对待 div 一样对待 a。此外,我们应该使用 "uniqueId" 作为两者的标识符。 第四次尝试:

Template.genericCollapse.helpers({
  collapsed () {
    $('[data-target="#uniqueId"]').addClass('collapsed');
    $('#uniqueId').removeClass('show');
    return "collapsed"},
})

让它闪亮: 助手 {{collapsed}} 不再需要 return 任何值,这一切都用 javascript.我们只需要触发功能,所以这是最终代码:

<template name="genericCollapse">
  {{data-1}}
  <a href=# class='collapsed' data-toggle='collapse' {{hook}}
     data-target='#uniqueId'>Show/hide data-2</a>
  <div class='collapse' id='uniqueId'>
    {{data-2}}
  </div>
</template>

Template.genericCollapse.helpers({
  hook () {
    $('[data-target="#uniqueId"]').addClass('collapsed');
    $('#uniqueId').removeClass('show');
  }
})

很有魅力。