Подтвердить что ты не робот

Обратный вызов после обновления DOM в Meteor.js

У меня есть этот проект Meteor: https://github.com/jfahrenkrug/code_buddy

Это в основном инструмент с большой текстовой областью и предварительной областью, которая позволяет вводить фрагменты исходного кода, которые автоматически становятся доступными для всех подключенных клиентов.

Я хотел бы автоматически запускать функцию highlightSyntax при изменении кода, но на самом деле это не работает.

Я пробовал query.observe, но это не сработало: подсветка синтаксиса вспыхнула один раз, а затем снова исчезла.

Итак, мой вопрос: как запустить код после обновления DOM?

4b9b3361

Ответ 1

Хакерный способ сделать это:

foo.html

<template name="mytemplate">
  <div id="my-magic-div">
    .. stuff goes here ..
    {{add_my_special_behavior}}
  </div>
</template>

foo.js

Template.mytemplate.add_my_special_behavior = function () {
  Meteor.defer(function () {
    // find #my-magic-div in the DOM
    // do stuff to it
  });
  // return nothing
};

Функция будет вызываться всякий раз, когда шаблон визуализируется (или перерисовывается), поэтому вы можете использовать его как крючок для выполнения любых специальных манипуляций с DOM, которые вы хотите сделать. Вам нужно использовать Meteor.defer(что делает то же самое, что и setimeout (f, 0)), потому что во время визуализации шаблона он еще не находится в DOM.

Имейте в виду, что вы можете отобразить шаблон без его вставки в DOM! Например, это полностью законно для этого:

console.log(Template.mytemplate())

Итак, когда шаблон визуализируется, нет 100% -ной гарантии, что он окажется в DOM. Это зависит от пользователя шаблона.

Ответ 2

Начиная с Meteor 0.4.0, Template.myTemplate.rendered обеспечивает обратный вызов, который

называется один раз, когда экземпляр Template.myTemplate отображается в узлы DOM и помещается в документ в первый раз.

Дополнительная информация на http://docs.meteor.com/#template_rendered

Ответ 3

Что касается текущей версии Meteor (1.0), мы можем теперь использовать функцию afterFlush() Tracker.

Tracker.autorun(function(e){
   var data = Router.current().data();
   if(data.key !== undefined){
       //the data is there but dom may not be created yet
     Tracker.afterFlush(function(){
       //dom is now created.
    });
   }
});

Ответ 4

После обновления DOM нет обратного вызова, однако вы можете заставить все ожидающие обновления DOM с Tracker.flush().

После вызова flush() вы знаете, что DOM был обновлен и поэтому вы можете выполнить любые изменения вручную DOM, которые вам нужны.

Ответ 5

Этот вопрос довольно старый, но решение на два года позже было бы интегрировать библиотеку оперативной трансформации с помощью Meteor и использовать Ace или CodeMirror на клиенте, который автоматически выделяет синтаксис. Это дает дополнительное преимущество, позволяя людям редактировать одновременно.

Я уже сделал для вас работу:)

Ответ 6

В Blaze Components (я один из авторов) у вас есть API, который вызывает методы, когда DOM вставлен, перемещен или удален. Вы можете видеть здесь, как сделать реактивную переменную при изменении DOM.

Недостатком этого подхода является то, что он не изменяется при изменении атрибутов элемента DOM (например, class change). Только при изменении самих элементов DOM. Это работает в большинстве случаев, но если вам нужно второе, я предлагаю вам просто использовать MutationObserver. В этом случае вы также сможете реагировать на внешние изменения.

Ответ 7

Кажется, что Template.myTemplate.rendered работает неправильно или я не понимаю его...

Мне нужно загрузить TinyMCE inline после создания шаблона со всеми сообщениями, поэтому у меня есть:

- шаблон

<div id="wrapper">     
         {{#each posts}}
             <div class="editable">{{post}}</div>
         {{/each}}        
  </div>

- и функция

Template.myPosts.rendered = function(){
      console.dir($("div"));
      tinymce.init({
          selector: "div.editable",
          inline: true,
          plugins: [
              "advlist autolink lists link image charmap print preview anchor",
              "searchreplace visualblocks code fullscreen",
              "insertdatetime media table contextmenu paste"
          ],
          toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
});

}

Однако консоль регистрирует только теги <div id="wrapper">, а не <div class="editable">, которые содержат мои сообщения. Итак, кажется, что Template.myTemplate.rendered обратный вызов возникает до того, как шаблон будет обработан, правильно?

EDIT: я помещаю код Template.myTemplate.rendered внутри setTimeout(), и все, похоже, работает, поэтому я уверен, что Template.myTemplate.rendered вызывает проблему.

Ответ 8

Я просто нашел маленький хак, который, кажется, работает очень хорошо:

Template.myTemplate.onRendered(function() {
    this.autorun(function() {
        Meteor.setTimeout(function() {
            // DOM has been updated
        }, 1);
    });
});

Я не эксперт Meteor, поэтому у него могут быть некоторые недостатки, но я пока не нашел их, кроме того, что это немного грязно!