With Meteor, why should DOM manipulation NEVER be done with jQuery?

末鹿安然 提交于 2019-12-22 06:36:05

问题


I'm curious about the validity of this statement:

A good rule of thumb is that if you're using jQuery to manipulate any DOM elements, you're probably doing it wrong.

from the answer to this question: Meteor - How can I pass data between helpers and events for a template?

The way I see it, jQuery is good because it can be surgical and manipulate many small parts of the DOM without having to change an entire code block.

Templates in Meteor are great because that's precisely what they do - they can swap out entire code blocks or small tiny things for something else, but at the expensive of having to define it explicitly every time and redefining code that actually doesn't change.

Example - on focus, jQuery removes the idleField class, adds the focusField class, and changes the placeholder to some other text:

<input class="idleField" id="first_name" name="firstName" type="text" placeholder="First Name" maxlength="10"/>

$('input[type="text"]').focus(function() {
  $(this).removeClass("idleField").addClass("focusField").attr("placeholder", "First Name NOW");
});

The result is

<input class="focusField" id="first_name" name="firstName" type="text" placeholder="First Name NOW" maxlength="10"/>

The jQuery is short and sweet and targeted just at toggling the class and placeholder.

But with Meteor templates, the same result would be something like:

<input {{toggleClassAndEditPlaceholder}} maxlength="10"/>

Session.set('toggleClassEditPlaceholderSessionVar', ' class="idleField" id="first_name" name="firstName" type="text" placeholder="First Name" ');

Template.form.helpers({
  toggleClassAndEditPlaceholder: function() {
    return Session.get('toggleClassEditPlaceholderSessionVar');
)};

Template.form.events({
  'focus input[type="text"]': function () {
    Session.set('toggleClassEditPlaceholderSessionVar', ' class="focusField" id="first_name" name="firstName" type="text" placeholder="First Name NOW" ');
  }
});

The Meteor way is a lot more verbose and at least in this example, includes redundant items ( id, name, and type don't change, only class and placeholder). jQuery targeted ONLY the class and placeholder and left everything else alone. Templates, however, sometimes have to encompass a lot of extraneous stuff. In this example, sure, I could have moved placeholder and class side by side in my code so that id, name, and type are untouched when defining the template, but in some other code you wouldn't be able to.

So what am I doing wrong? Is there supposed to be a much more efficient way of doing it in Meteor, one that's more efficient that just that single jQuery line?


回答1:


The statement in question was made nine months ago. It was very important at that time. Since then Meteor UI engine received a complete overhaul. One of key points of that change was to make the engine more JQuery-friendly. Before, when you changed with JQuery, chances were Meteor would revert that change on redraw. Now it makes its changes in much more clever way, so it's safe to alter the elements state with pure JQuery.

That being said, it's still a good practice to think carefully whether the change you're going to need is really better done with JQuery. Specifically, it's better to leave all data-related changes to Meteor. In your case, however, you alter the behavior of a UI component based purely on its state. So indeed, to make that change with Meteor alone you'd need to create an artificial data object, and indeed, it's better to just use JQuery in this case.

 


 

Aside from that, your Meteor code itself can be significantly improved. You don't need to pass all tag attributes in the helper, it's enough to change the thing you need:

<input id="..." type="..." name="..." class="{{class}}" placeholder="{{placeholder}} maxlength="10"/>

Template.form.helpers({
  class: function() {
    return Session.get('toggled') ? 'focusField' : 'idleField';
  },
  placeholder: function() {
    return Session.get('toggled') ? 'focusPlaceholder' : 'idlePlaceholder';
  },
)};

Template.form.events({
  'focus input[type="text"]': function () {
    Session.set('toggled', true);
  },
});



回答2:


First, the original SO post you cite was referencing using jQuery for "reactive" data changes (on model data) and the answer was pointing the author toward using the Collection API to avoid having to manually update the DOM. When you pull data from a Meteor.Collection and display it on the page, you are using a "reactive" data source...updates will happen automagically.

Your example doesn't really follow the same reasoning. Therefore, you would most definitely make use of jQuery to simplify your approach. It would look something like:

Template.form.events({
  'focus input[type="text"]': function (e) {
      $(e.currentTarget).removeClass("idleField").addClass("focusField").attr("placeholder", "First Name NOW");
  }
});

There's no reason to litter the global Session object with a bunch of key/value pairs for element attributes. Even if you did, there's no reason to store the attributes that remain the same (id, name, type).



来源:https://stackoverflow.com/questions/23934060/with-meteor-why-should-dom-manipulation-never-be-done-with-jquery

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!