在MeteorJS / Blaze上创建动态标签的更有效方法是什么?

时间:2019-02-19 17:55:27

标签: html meteor dynamic tags meteor-blaze

我正在寻找一种使用Reactive Var管理HTML标签类型的解决方案。我看了所有Blaze文档,但什么也没发现。

简单示例

我想在更新布尔型ReactiveVar时将标签从div更改为form

Template.MyExample.onCreated(function() {
  this.is_form = new ReactiveVar(false)
})
Template.MyExample.helpers({
  getTag() {
    return Template.instance().is_form.get() ? 'form' : 'div'
  }
})

这显然行不通:

<Template name="MyExample">
  <{{getTag}}>

  </{{getTag}}>
</Template>

Nicer解决方案?

我找到的“最佳”方法是创建一个标记模板,并一次列出每种情况,但是我不喜欢这种解决方案。

Template.MyExample.onCreated(function() {
  this.is_form = new ReactiveVar(false)
})
Template.MyExample.helpers({
  getTag() {
    return Template.instance().is_form.get() ? 'form' : 'div'
  }
})
Template.MyExample.events({
  'click .switch'(e, instance) {
    e.preventDefault()
    instance.is_form.set(!instance.is_form.get())
  }
})

Blaze模板:

<Template name="MyExample">
  <div>
    <a href="#" class="switch">Switch type</a>
    {{#MyTag tag=getTag}}
      Parent tag is {{getTag}}
    {{/MyTag}}
    {{#MyTag tag="a" attributes=(object href="#" target="_blank")}}
      Link
    {{/MyTag}}
  </div>
</Template>

<Template name="MyTag">
  {{#if equals tag 'form'}}
    <form {{attributes}}>
      {{> Template.contentBlock }}
    </form>
  {{else if equals tag 'a'}}
    <a {{attributes}}>
      {{> Template.contentBlock }}
    </a>
    <!-- and more and more.... -->
  {{else}}
    <div {{attributes}}>
      {{> Template.contentBlock }}
    </div>
  {{/if}}
</Template>

所需的助手:

Template.registerHelper('object', function({hash}) {
  return hash;
})
Template.registerHelper('equals', function (a, b) {
  return a === b
})

这是有效的,但我想知道对于Meteor(和DOM更新)是否有太多帮助。此解决方案是像简单的{{#if}}...{{/if}}一样工作还是更笨重?

1 个答案:

答案 0 :(得分:0)

Blaze基本上不支持您请求的功能。虽然静态代码生成器可以轻松地包含动态标签,但这在运行时非常困难,在这种情况下,您必须处理DOM树,该树的元素的标签类型在设计上是不可变的。

我首先想到了一种解决方法,该方法使用onRendered的{​​{1}}中的jQuery使用子交换:

MyTag

但这不幸的是不起作用,因为内容框失去了它的反应性,而当前Template的jQuery实例失去了它对根元素的作用域。我只是在这里添加它,以防有人赶上并找到可行的解决方案。

现在,仍然有一种使用动态模板的解决方案:

Template.MyTag.onRendered(function () {
  const instance = this

  instance.autorun(() => {
    const data = Template.currentData()
    const attributes = data.attributes || {}
    const elementName = data.tag
    const refTag = instance.$('.my-tag-ref')
    const newTag = $(`<${elementName}>${refTag.html()}</${elementName}>`)

    Object.keys(attributes).forEach(attKey => newTag.attr(attKey, attributes[ attKey ]))
    newTag.addClass('my-tag-ref')
    refTag.replaceWith(newTag)
  })
})

如您所见,缺点显然是您必须定义许多新模板。优点是,您不必再使用那么多的if / else,它就会使您支付更多的钱,而您必须在代码中包含<Template name="MyTag"> {{#Template.dynamic template=getTemplate data=getData}} {{> Template.contentBlock }} {{/Template.dynamic}} </Template> <template name="mytaga"> <a {{attributes}}> {{> Template.contentBlock }} </a> </template> <template name="mytagform"> <form {{attributes}}> {{> Template.contentBlock }} </form> </template> <template name="mytagdiv"> <div {{attributes}}> {{> Template.contentBlock }} </div> </template>

各个助手如下所示:

MyTag
  

这是有效的,但我想知道对于Meteor(和DOM更新)是否有太多帮助。此解决方案是否像简单的{{#if}} ... {{/ if}}那样工作?还是比较笨重?

总体来说,Blaze比React或Vue慢。但是,渲染仅在反应性数据更新时才更新,因此与要触发的更新量一样重。