开发者

Multiple selectors or multiple functions - any efficiency gains?

I'm wondering if its possible to make the following code more concise:

 $('#americasTrigger').hover(
  function () {
          $('#americasImg').fadeIn()
      },
  function(){
          $('#americasImg').fadeOut()
  }
  );

$('#europeTrigger').hover(
  function () {
      $('#europeImg').fadeIn();
  },
  function(){
      $('#europeImg').fadeOut();
  }
  );    

$('#middleEastTrigger').hover(
  function () {
      $('#middleEastImg').fadeIn();
  },
  function(){
      $('#middleEastImg').fadeOut();
  }
  );    

//More etc

The country name stays the same for each, with 'Trigger' or 'Img' added to the end. There's a lot of repetition here which indicates to me I'm not going about the this best way.

I had thoughts around:

  • Crearting a case scenario, or
  • Somehow getting the selector being used for a selection, making it a string, splitting it's name to capture the country in use and applying that to the nested fadeIn/Out function with 'Img' on the end.

Is this possible or am I being too fancy?

Edit 1: Thanks verymuch for all the responses, apologies for not posting the html, i've put this bellow. In short I'm using image maps over a bg image (of earth) as the hover triggers for fading in/out my absolutely positioned on-hover images.

<div class="mapTub"> 

  <img src="images/transparentPixel.png" class="mapCover" usemap="#worldMap" width="524px" height="273px"/>

  <map name="worldMap" id="worldMap">
    <area id="americasTrigger" shape="poly" coords="1,2,3" href="#americas" />
    <area id="europeTrigger" shape="poly" coords="4,5,6" href="#europe" />
    <area id="middleEastTrigger" shape="poly" coords="7,8,9" href="#middleEast" />
  </map>

<img src="images/International_americas_dark.png" class="americas" id="americasImg" />
<img src="images/International_europe_dark.png" class="europe" id="europeImg" />
<img开发者_如何学运维 src="images/International_middleEast_dark.png" class="middleEast" id="middleEastImg"  />

</div>

Reigel's answer seems like the way to go here, ill try it out report back, further comments welcome! :)


Me, without knowledge of the html, suggest this...

$('#americasTrigger, #europeTrigger, #middleEastTrigger').hover(
    function () {
        var id = this.id;
        $('#'+id.replace('Trigger', 'Img')).fadeIn();
        //$('#'+id.slice('0',id.indexOf('Trigger'))+'Img').fadeIn();
    },
    function(){
        var id = this.id;
        $('#'+id.replace('Trigger', 'Img')).fadeOut();
        //$('#'+id.slice('0',id.indexOf('Trigger'))+'Img').fadeOut();
    }
);

You can also use .replace() as suggested by Anurag in the comment below...


id ='europeTrigger';
alert(id.slice('0',id.indexOf('Trigger'))); // alerts 'europe'
// '#'+id.slice('0',id.indexOf('Trigger'))+'Img' is '#europeImg'

demo


Since it looks like you are accessing only unique ids, your best choice is to use a lookup table IMO.

var lookmeup = [  [$('#americasTrigger'), $('#americasImg')],
                  [$('#europeTrigger'), $('#europeImg')],
                  [$('#middleEastTrigger'), $('#middleEastImg')]
               ];

$.each(lookmeup, function(index, element){
    element[0].hover(function(){
      element[1].fadeIn();
    }, function(){ 
      element[1].fadeOut();
    });
});

DRY! all done!

Another way to do it in a more efficient manner would be to use event delegation.

If all of your hover elements have the same TAG, this approach could be useful:

$(document.body).delegate('div', 'mouseenter', function(e){
     $('#' + e.target.id.replace(/Trigger/, 'Img')).fadeIn();
});

$(document.body).delegate('div', 'mouseleave', function(e){
     $('#' + e.target.id.replace(/Trigger/, 'Img')).fadeOut();
});

Assuming that all your "hoverable" elements were DIVs. You still should give those elements a classname so that only those specific elements are targeted.

It makes a lot of sense to confine the root element for delegate(). Here I use document.body which would .live() do. The great thing about .delegate() is, that if your hover elements share one parent node, you can apply delegate() on that node. In that manner you reduce the number of event handlers bound

(2 instead of 6).


lol, looks like this may be about the same size or longer than your code, but definitely dryer.

Thanks to @Andy for pointing out the performance penalty with the previous version using $(..).each.

var regions = ['americas', 'europe', 'middleEast'];

$.each(regions, function(region) {
    var trigger = id(region, 'Trigger');
    var image = id(region, 'Image');

    $(trigger).hover(
        effect(image, 'fadeIn'),
        effect(image, 'fadeOut'),
    );
});

function effect(selector, method) {
    return function() {
        $(selector)[method]();
    };
}

function id(prefix, suffix) {
    return '#' + prefix + suffix;
}

If you can change the HTML, I would encode all knowledge into the page itself, and just use jQuery to setup hover events.

<div class='trigger' data-image='#americasImg'>
   ..
</div>
<div class='trigger' data-image='#europeImg'>
  ..
</div>

Javascript

function imageId(elem) {
    return $(elem).attr('data-image');
}

// Using the fade function from before
$('.trigger').hover(
    effect(imageId(this), 'fadeIn'),
    effect(imageId(this), 'fadeOut')
);


Or, to make things much simpler, add a marker class, called 'fadingImage' for example, to each of the images and then use this code...

$('.fadingImage').hover( 
    function () { 
        $(this).fadeIn() 
    }, 
    function(){ 
        $(this).fadeOut() 
    } 
); 

This works because all of the images, regardless of their id, are handled in the same way, al that you really need to do is identify which images on your page need to have the hover handlers attached, and this is done with the marker class. You might even be able to dispense with the ids altogether, if they aren't used for anything else.

Update: No that I've woken up (Thanks jAndy & Reigel!), I'll amend my post to deal with the fact that the element being hovered is not the one that is being faded.

Without having any sample markup, I'm going to have to make some assumptions, but the original poster may want to provide the real markup, in order to put things in context.

<div>
    <span class="fadingTrigger">first text to hover over<span>
    <img class="fadingImage" src="..." alt="first image to be faded"/>
<div>
<div>
    <span class="fadingTrigger">second text to hover over<span>
    <img class="fadingImage" src="..." alt="second image to be faded"/>
<div>

$('.fadingTrigger').hover( 
    function () { 
        $(this).parent().find(".fadingImage").fadeIn() 
    }, 
    function(){ 
        $(this).parent().find(".fadingImage").fadeOut() 
    } 
); 

Depending on the markup structure, the method of finding the fadingImage that is associated with the fadingTrigger may have to vary, but by having some well defined structure, it should be reliable.

The reason why I'd prefer this method over using an array of ids to lookup the elements is that any additions to the markup would require changes to the javascript - this would be especially problematic if the markup is dynamically generated. The javascript could be dynamically generated too, to include the appropriate array of values, but the would violate the DRY principal.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜