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

问题描述 投票:1回答:1

我正在寻找一种使用Reactive Var管理HTML标签类型的解决方案。我查看了Blaze的所有文档,但一无所获。

Simple example

我想在更新布尔值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 solution ?

我发现获得它的“最佳”方式是创建一个标签模板并一次列出每个例子,但我不喜欢这个解决方案。

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}}或更重的方式?

html meteor dynamic tags meteor-blaze
1个回答
0
投票

您要求的功能基本上不受Blaze支持。虽然静态代码生成器可以很容易地包含动态标记,但在运行时这是非常困难的,您必须处理DOM树,其元素的标记类型在设计上是不可变的。

我首先想到了一个解决方法,它使用onRenderedMyTag中使用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)
  })
})

但遗憾的是,这不起作用,因为内容bock失去了它的反应性,当前模板的jQuery实例将其范围丢失到根元素。我只是在这里添加它,以防有人抓住这个并找到一个有效的解决方案。

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

<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>

正如您所看到的,缺点显然是您必须定义许多新模板。优点是,您不必再使用这么多if / else,而且您需要在代码中包含MyTag的频率更高。

各自的助手如下所示:

Template.MyTag.helpers({
  getTemplate() {
    const instance = Template.instance()
    console.log(instance.data)
    return `mytag${instance.data.tag}`
  },
  getData () {
    return Template.instance().data
  }
}) 

这是有效的,但我想知道它是否对Meteor(和DOM更新)有很大帮助。这个解决方案的工作方式是简单的{{#if}} ... {{/ if}}还是更重?

Blaze总体上比例如React或Vue慢。但是,渲染仅在响应数据更新时才更新,因此它与触发的更新量一样重。

© www.soinside.com 2019 - 2024. All rights reserved.