我正在寻找一种使用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>
我发现获得它的“最佳”方式是创建一个标签模板并一次列出每个例子,但我不喜欢这个解决方案。
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}}
或更重的方式?
您要求的功能基本上不受Blaze支持。虽然静态代码生成器可以很容易地包含动态标记,但在运行时这是非常困难的,您必须处理DOM树,其元素的标记类型在设计上是不可变的。
我首先想到了一个解决方法,它使用onRendered
的MyTag
中使用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慢。但是,渲染仅在响应数据更新时才更新,因此它与触发的更新量一样重。