Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

While working on a script recently, I came across a peculiar nuance of how Sizzle works with the href attribute. Specifically, using an attribute selector on an href, Sizzle will use the actual attribute value:

// Will not find <a href="index.html">...
$('a[href="http://www.example.com/index.html"]')

Sizzle uses .getAttribute() instead of elem.href (or more precisely, elem['href'], as Sizzle does in most cases); elem.href would provide the fully-qualified URL.

To understand this a bit more, I created a fiddle to try different forms of URLs. In the process of testing, I discovered the (obvious) "solution" of setting the href equal to itself:

$('a').each(function(){
    this.href = this.href;
});

Which, unsurprisingly, updates the element to reflect the fully-qualified URL that this.href provides. There are other ways I've found that work (any that update the href attribute of an element), but they just port the above approach to other forms, or involve something like .filter() (demo):

var matches = $('a').filter(function(){
    var window_location = 'http://example.com/services.html';
    return window_location == this.href;
});

The reason I say this is that doing el.href = el.href before selecting is a workaround in a sense (and one I don't think is a great alternative). For instance, running a check on a set of elements to find if any contain a matching link to the current URL (or another URL) is simpler to do if you can:

$links.not('[href="' + window.location.href + '"]')

Is there a way to do this without having to resort to "updating" the attributes, or writing additional code to manage the check? Is there a way I've overlooked that doesn't involve modifying how Sizzle works ^?

^ Note: Modifying the actual source code would be a (bad) idea compared to just adding an expression:

$.extend($.expr[':'], {
    url: function(elem, i, match){
        return elem.href === match[3];
    }
});

var $matched = $('a:url(http://test.com/index.html)');

http://jsfiddle.net/yt2RU/

(And as an aside, are there other attributes with similar untypical behavior in Sizzle?)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
405 views
Welcome To Ask or Share your Answers For Others

1 Answer

I believe I've got the answer to this question...

Use either an expression:

jQuery.extend(jQuery.expr[':'], {
    url: function(elem, i, match){
        return elem.href === match[3];
    }
});

var $matched = jQuery('a:url(http://test.com/index.html)');

http://jsfiddle.net/yt2RU/

Or, as it was noted in the comments, $.filter() could be used:

var $matched = $('a').filter(function(){
    if (this.href == 'http://test.com/index.html') {
        return true;
    }
    return false;
});

http://jsfiddle.net/dMuyj/

And that jQuery only falls back to Sizzle if querySelector() and querySelectorAll() are not available natively, and that both of these work the same as jQuery's selector engine (not surprising).

The sum total is, you either need an expression or a filter if you desire this type of selector, and use elem.href for the comparison, not getAttribute().


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...