jQuery find value then replace SRC

2019-03-04 18:57发布

问题:

Can anyone see anything that is wrong with this code it just isn't working...

I am tring to:

get the value of #product-variants-option-0

search #preload for the relevant image and

then change div.image img src to that image

jQuery(document).ready(function($) {
   $('#product-variants-option-0').change(function() {

     // What is the sku of the current variant selection.
     var select_value = $(this).find(':selected').val();

            if (select_value == "Kelly Green") {
             var keyword = "kly";
            };

        var new_src = $('#preload img[src*=keyword]');

        $('div.image img').attr('src', new_src);

   });
 });

The selection:

<select class="single-option-selector-0" id="product-variants-option-0">
<option value="Kelly Green">Kelly Green</option>
<option value="Navy">Navy</option>
<option value="Olive">Olive</option>
<option value="Cocoa">Cocoa</option>
</select>

I'm trying to search an unordered list:

<ul id="preload" style="display:none;">
<li><img src="0z-kelly-green-medium.jpg"/></li>
<li><img src="0z-olive-medium.jpg"/></li>
</ul>

The image I'm trying to replace is this:

回答1:

I see a few problems:

  1. You're not converting "Kelly Green" to "kelly".
  2. The var new_src = $('#preload img[src*=keyword]'); has keyword hardcoded into it (not the value of the keyword variable).
  3. The lis in the list don't have img elements inside them (they just directly contain the URL as text). You've edited the question and fixed that.
  4. If the select value isn't "Kelly Green" you're not making it lower case, and you're not using the value at all.
  5. You're not retrieving the src attribute of the preload image.

If you change the list to:

<ul id="preload" style="display:none;">
<li><img src='0z-kelly-green-medium.jpg'></li>
<li><img src='0z-olive-medium.jpg'></li>
</ul>

(That was part of what was fixed.)

Then this should work:

jQuery(document).ready(function($) {
   $('#product-variants-option-0').change(function() {
     var select_value, keyword, new_src;

     // What is the sku of the current variant selection
     select_value = $(this).find(':selected').val();

     // Get the keyword to use (the value in lower case, or "kelly" if the
     // value is "Kelly Green")
     keyword = select_value == "Kelly Green" ? "kelly" : select_value.toLowerCase();    

     // Find the image using that `src`, note that we concatenate the value
     // from `keyword`, rather than having it in a literal.
     new_src = $('#preload img[src*=' + keyword + ']').attr('src');

     // Set the image's source.
     $('div.image img').attr('src', new_src);
   });
});

Live example


Charles, you asked for input on how it might be written differently, and I said I had a minute to do something up. Sorry for the delay, my Real Job needed me for a moment.

I'd probably approach it like this, with the assumption that you have this kind of select box elsewhere in your application and therefore generalization is worthwhile.

  1. Make things reusable wherever possible (well, almost; there's one bit of generalization I left as an exercise to the reader).
  2. Don't store the image URLs in one place and the options in another; put them together, so they can both come from the same data source easily. This reduces error. (For instance, in your question, you have four options, but you only have images for two of them in the preload structure. Now, if you don't have images for the others, that's fine, leave the attribute off or make it blank, but keeping things together / generated from the same source is a good idea.)
  3. Do #2 with the data-image attribute, which is valid as of HTML5 and perfectly harmless in earlier versions. (Details)
  4. Don't include the markup for the preloading in the HTML; generate it. This relates to #2, and also to the fact that users who don't have JavaScript don't need the precached images as they won't be used. So don't push them things they don't need.

HTML:

<select class="single-option-selector-0" id="product-variants-option-0">
<option
  value="Kelly Green"
  data-image="0z-kelly-green-medium.jpg"
  >Kelly Green</option>
<option
  value="Navy"
  data-image="0z-navy-medium.jpg"
  >Navy</option>
<option
  value="Olive"
  data-image="0z-olive-medium.jpg"
  >Olive</option>
<option
  value="Cocoa"
  data-image="0z-cocoa-medium.jpg"
  >Cocoa</option>
</select>

and

<div class='image'><img src='placeholder.jpg'></div>

JavaScript with jQuery:

(function($) {
  // A utility function from my arsenal; you can
  // just inline this if you don't want it.
  // Returns an array containing the given attribute
  // from *all* of the elements in the jQuery object.
  // Args:
  //  name        Name of the attribute to fetch
  //  blanksOkay  (Optional, default false) true if
  //              you want blanks in the array for
  //              blank entries or non-existant entries;
  //              false if you want them left out.
  $.fn.attrAll = function(name, blanksOkay) {
    var list, index;

    if (typeof blanksOkay === "undefined") {
      blanksOkay = false;
    }

    list = [];
    for (index = 0; index < this.length; ++index) {
      entry = $(this[index]).attr(name);
      if (entry || blanksOkay) {
        list.push(entry);
      }
    }
    return list;
  };

})(jQuery);

// The page's ready script
jQuery(function($) {

  // Set up the product variants select box.
  // You could generalize this with classes or other attributes
  // (so there would be *nothing* special about the select box),
  // but I didn't want to change your markup too much.
  setupSelectWithImages(
    '#product-variants-option-0',
    'div.image img:first'
  );

  // ===
  // All of the following would probably be in your
  // utility script; it's not page-specific.
  // ===

  // Set up our select box that's equipped with images
  // so it shows the image when an option is selected.
  // The options within the box should have data-image
  // attributes for their images, which are precached.
  // Args:
  //   boxSelector     The selector that finds the select box
  //   targetSelector  The selector that finds the target img
  function setupSelectWithImages(boxSelector, targetSelector) {
    var box;

    // Get the select box
    box = $(boxSelector);

    // Preload the images
    preloadImages(box.find('option'), 'data-image');

    // Ensure we show the correct image when the select box
    // changes, and force showing it right now for the default
    // value.
    setCurrentImage.call(box[0]);
    box.change(setCurrentImage);
    function setCurrentImage() {
      var entry = $(this).find('option:selected').attr('data-image');
      if (entry) {
        display("Setting src to " + entry);
        $(targetSelector).attr('src', entry);
      }
    }

    // Done with box
    box = undefined;
  }

  // Another general purpose function; preloads the images
  // defined by the given attribute on the elements in the
  // given jQuery object.
  // I've kept things bundled up (in a div rather than a ul),
  // but there's no special reason to, you could just add
  // the individual images to the body directly.
  // Using a container makes it easy to return a single
  // thing out of this function, which may be useful
  // to some calling code.
  function preloadImages(list, attrName) {
    var markup;

    // Get a list of the relevant attribute
    markup = list.attrAll('data-image');

    // Convert it into a bunch of img tags
    markup = joinEntries(markup, "<img src='", "'>");

    // Put them in an off-page div, add it to the document,
    // and return the div to the caller
    return $("<div/>").css({
      'position': 'absolute',
      'left': '-10000px',
      'top': '0px'
    }).html(markup).appendTo(document.body);
  }

  // Join the entries in the array with the given
  // prefix and suffix.
  function joinEntries(a, prefix, suffix) {
    prefix = prefix || '';
    suffix = suffix || '';
    return prefix + a.join(suffix + prefix) + suffix;
  }

  // This is just for our purposes in this demo
  function display(msg) {
    $("<p/>").html(msg).appendTo(document.body);
  }
});​

Live example (but the live example uses some gravatars, so you can actually see the images)



回答2:

$('#preload img[src*=keyword]'); will not find anything, there is no img inside #preload. You should define id for every li, and these ids will equal you keywords. After that you can do $('#preload #' + keyword).text() - this will return correct new_src value

UPDATE After your edit: do not put images inside lis! This will needlessly increase traffic! Put just sources:

 <li id="kly">pathto.jpg</li>