JQuery Lint says: “You've used the same select

2019-04-13 04:43发布

问题:

Here's my problem child:

jQuery(document).ready(function() {
    var a = jQuery('img[title*="after"]');  
    a.parents('dl.gallery-item').addClass('after');
    a.addClass('after');
    var b = jQuery('img[title*="before"]');
    b.parents('dl.gallery-item').addClass('before');
    b.addClass('before');
//the following gives each image a 'name' attribute based on the caption, collapsed.
jQuery('img').each(function() {
    var f = jQuery(this).parents('dl.gallery-item').find('dd').text();
    var f = f.replace(/\s/g,'');
    jQuery(this).attr('name', f);
});
//the following takes each 'name' attribute, finds the before, and sticks it behind the after   
    jQuery('img.after').hover(function() {
        var imgName = jQuery(this).attr('name');
    //  alert(imgName);

        var afterPosition_L = jQuery(this).offset().left;
        var afterPosition_T = jQuery(this).offset().top;
        var css_string = '{ top: '+ afterPosition_T +'; left: '+ afterPosition_L +'; position: absolute; z-index: 999;}';
        var imgBefore = jQuery('img.before[name="'+ imgName +'"]');
    //  alert(imgBefore);
        jQuery(imgBefore).css(css_string);
    });

Explanation: I'm working with WordPress (so I spell out jQuery). WordPress loads a bunch of images in a gallery (with PHP). Based on some fields for 'title' and the content of the caption, I determine if it's a 'before' or 'after' and assign that class both to a tag that wraps the image, et al and the img itself. I also assign a 'name' attribute to the image, based on the caption text. All this is working well.

The 'hover' is where things go bad.

When hovering nothing happens, but the Lint error (in the title of this post) is thrown on mouseout.

What's supposed to happen: First, I get the name of the hovered image and stick it in imgName (this is working). Next, I get the position of the hovered img

Here's the ugly stuff: I try to identify the image with $('img.before[name=""]') using the variable of the name from 'this', i.e. the one we're hovering, and stick it in a variable "imgBefore", then I try to apply CSS to it to move it to the same left/top position as the 'after' but with a different z-index.

The 'img.before[name=""] seems to be the selector that Lint is complaining about... it says:

Selector: "img.before[name="CarterLivingRoom"]"
You've used the same selector more than once.

So it is using the variable correctly. It does seem to throw the error twice on mouseout. Perhaps the 'hover()' is using it twice, but how can that be avoided?

回答1:

There are a number of things going wrong here.

  • The jQuery document.ready functions pass the jQuery object as a parameter, so you can use $ inside the function without fear of collision.
  • In img.each, you redefine var f multiple times.
  • You're recreating new jQuery objects off of the same selector multiple times in your functions.
  • It's generally considered good form to use var once per function, at the top of the function; this helps you avoid mistaken redeclarations, as well.
  • You are creating multiple offset objects; just call it once, then use the members of the resulting object.
  • jQuery objects return self, so you can chain calls! This lets you clean up your code a lot.
  • You're creating a new jQuery object out of an existing jQuery object (imgBefore); no need to do that. Additionally, .css() can take an object rather than a string, which makes updates a fair bit easier/cleaner.

Refactored:

jQuery(document).ready(function($) {
  $('img[title*="after"]').addClass('after').
    parents('dl.gallery-item').addClass('after');

  $('img[title*="before"]').addClass('before').
    parents('dl.gallery-item').addClass('before');

  //the following gives each image a 'name' attribute based on the caption, collapsed.
  $('img').each(function() {
    var $this = $(this), f;
    f = $this.parents('dl.gallery-item').find('dd').text().replace(/\s/g, '');
    $this.attr('name', f);
  });

  //the following takes each 'name' attribute, finds the before, and sticks it behind the after
  $('img.after').hover(function() {
    var $this = $(this), offset = $this.offset();
    $('img.before[name="' + $this.attr('name') + '"]').css({
      top: offset.top,
      left: offset.left,
      position: 'absolute',
      'z-index': 999
    });
  });
});


回答2:

The error message may be misleading:. The issue I see is that:

jQuery(imgBefore)

is redundant. imgBefore is already a jQuery node set. You can just use:

imgBefore.css(css_string);


回答3:

First thing I see here is that your last line is wrong:

jQuery(imgBefore).css(css_string);

It should be:

imgBefore.css(css_string);


回答4:

We found a solution late last night. One problem, as ifaour and Flaschen (thanks!) noted, was the imgBefore... we had a couple other steps to make it right.

We ended up with this:

// the following gives each image a class before or after based on the 'title' field
jQuery(document).ready(function() {
    var a = jQuery('img[title*="after"]');  
    a.parents('dl.gallery-item').addClass('after');
    a.addClass('after');
    var b = jQuery('img[title*="before"]');
    b.parents('dl.gallery-item').addClass('before');
    b.addClass('before');
//the following gives each image a 'name' attribute based on the caption, collapsed.
jQuery('img').each(function() {
    var f = jQuery(this).parents('dl.gallery-item').find('dd').text();
    var f = f.replace(/\s/g,'');
    jQuery(this).attr('name', f);
});
//the following takes each 'name' attribute, finds the before, and sticks it behind the after
    jQuery('img.before').each(function(){
        var imgName = jQuery(this).attr('name');
        var imgAfter = jQuery('img.after[name="' + imgName + '"]');

        var position = imgAfter.position();
//alert(position.top);
        imgAfter.after(this);
      //there was some CSS in the stylesheet, too, providing relative/absolute, etc.
        var css_array = {
            'top' : position.top,
            'left' : position.left,
            'display' : 'block',
        }

        jQuery(this).css(css_array);
    });
// then this fades the front image to the back image.
    jQuery('dl.after').hover(function(){
        jQuery(this).find('img.after').fadeOut(1500);
    }, function(){
        jQuery(this).find('img.after').fadeIn(1000);

Thank you all!