Какой наиболее эффективный способ создания динамических тегов на MeteorJS / Blaze? - PullRequest
0 голосов
/ 19 февраля 2019

Я ищу решение для управления типом тега HTML с помощью Reactive Var.Я просмотрел всю документацию Blaze, но ничего не нашел ..

Простой пример

Я хочу изменить тег с div на form при обновлении логического ReactiveVar.

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}} или оно намного тяжелее?

1 Ответ

0 голосов
/ 19 февраля 2019

Запрашиваемая вами функция в основном не поддерживается Blaze.В то время как генераторы статического кода могут легко включать динамические теги, это очень сложный способ во время выполнения, когда вам приходится иметь дело с деревом DOM, чьи типы тегов элементов являются неизменяемыми по конструкции.

Сначала я подумал об обходном пути, который использует дочернюю перестановку с использованием jQuery в onRendered из MyTag:

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

Но, к сожалению, , к сожалению, не работает , поскольку блок содержимого теряет свою реактивность и экземпляр 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
  }
}) 

Это работает, но мне интересно, много ли это для Метеора (и обновлений DOM).Это решение работает как простой {{#if}} ... {{/ if}} или оно намного тяжелее?

Blaze в целом медленнее, чем, например, React или Vue.Однако рендеринг обновляется только в том случае, если обновляются реактивные данные, поэтому он так же велик, как и количество запускаемых обновлений.

...