I’m sure you all know that it’s possible to create plugins and extend various aspects of the jQuery JavaScript library but did you know you could also extend the capabilities of it’s selector engine?

Well, you can! For example, you might want to add a new ‘:inline’ selector which will return those elements that are displayed inline. Have a look:

$.extend($.expr[':'],{
inline: function(a) {
return $(a).css('display') === 'inline';
}
});

Using the above code, when you want to select elements that are displayed inline you can simply include it within the selector:

$(':inline'); // Selects ALL inline elements
$('a:inline'); // Selects ALL inline anchors

That was a pretty simple example but I’m sure you can see the endless possibilites that this enables! And, creating a custom jQuery selector couldn’t really be simpler!

Loaded images selector

You might want to add a ‘loaded’ selector which will work with images, and will return those images that are loaded:

// Flag images upon load:
$('img').load(function(){
$(this).data('loaded',true);
});
 
// Extend expr:
$.extend($.expr[':'],{
loaded: function(a) {
return $(a).data('loaded');
}
});
 
// Example of usage:
alert( 'Images loaded so far: ' + $('img:loaded').size() );

Querying element data

jQuery’s ‘data’ function allows us to add special data to elements without having to pollute global variables or add invalid element attributes. One of the things that jQuery lacks is the capability to easily query elements according to their data. For example, one might decide to flag all elements added dynamically (with jQuery) as ‘dom':

// New element:
$('<img/>')
.data('dom', true) // Flag
.appendTo('body'); // Append to DOM

Currently there’s no easy way to select all elements that have been flagged but what if we added a new ‘:data’ selector which could query such information?

Here’s how we would do it:

// Wrap in self-invoking anonymous function:
(function($){
 
// Extend jQuery's native ':'
$.extend($.expr[':'],{
 
// New method, "data"
data: function(a,i,m) {
 
var e = $(a).get(0), keyVal;
 
// m[3] refers to value inside parenthesis (if existing) e.g. :data(___)
if(!m[3]) {
 
// Loop through properties of element object, find any jquery references:
for (var x in e) { if((/jQueryd+/).test(x)) { return true; } }
 
} else {
 
// Split into array (name,value):
keyVal = m[3].split('=');
 
// If a value is specified:
if (keyVal[1]) {
 
// Test for regex syntax and test against it:
if((/^/.+/([mig]+)?$/).test(keyVal[1])) {
return
(new RegExp(
keyVal[1].substr(1,keyVal[1].lastIndexOf('/')-1),
keyVal[1].substr(keyVal[1].lastIndexOf('/')+1))
).test($(a).data(keyVal[0]));
} else {
// Test key against value:
return $(a).data(keyVal[0]) == keyVal[1];
}
 
} else {
 
// Test if element has data property:
if($(a).data(keyVal[0])) {
return true;
} else {
// If it doesn't remove data (this is to account for what seems
// to be a bug in jQuery):
$(a).removeData(keyVal[0]);
return false;
}
 
}
}
 
// Strict compliance:
return false;
 
}
 
});
})(jQuery);

Usage

Now, selecting elements which have that ‘dom’ flag is really easy:

$(':data(dom)'); // All elements with 'dom' flag
$('div:data(dom)'); // All DIV elements with 'dom' flag
$(':not(:data(dom))'); // All elements WITHOUT 'dom' flag

The ‘:data’ extension also allows you to query by comparison, for example:

$(':data(ABC=123)'); // All elements with a data key of 'ABC' equal to 123

It also allows you to use regular expressions:

// Let's assume we have slightly varying data across a set of elements:
$('div').each(function(i){
$(this).data('divInfo','index:' + i);
// Will result in value being 'index:0', 'index:1', 'index:2' etc. etc.
});
 
// We can select all of those DIVs like this:
$('div:data(divInfo=/index:\d+/)');
 
// Note: It's necessary to use non-literal notation when writing these
// regular expressions, so if you want to match a real backslash you'd
// have to use '\\'. Similarly if you want to test for all digit's
// you'd have to use \d instead of d.

Additionally, you can select elements on a basis of whether or not they have ANY data applied to them:

$(':data');       // All elements with data
$(':not(:data)'); // All elements without data

Some other examples:

  • :red

    // Check if color of element is red:
    $.extend($.expr[':'],{
    red: function(a) {
    return $(a).css('color') === 'red';
    }
    });
     
    // Usage:
    $('p:red'); // Select all red paragraphs
  • :childOfDiv

    // Check if element is a child of a div:
    $.extend($.expr[':'],{
    childOfDiv: function(a) {
    return $(a).parents('div').size();
    }
    });
     
    // Yes, I know this is exactly the same as $('div p')
    // This is just a demonstration! ;)
     
    // Usage:
    $('p:childOfDiv'); // Select all paragraphs that have a DIV as a parent
  • :width()

    // Check width of element:
    $.extend($.expr[':'],{
    width: function(a,i,m) {
    if(!m[3]||!(/^(<|>)d+$/).test(m[3])) {return false;}
    return m[3].substr(0,1) === '>' ?
    $(a).width() > m[3].substr(1) : $(a).width() < m[3].substr(1);
    }
    });
     
    // Usage:
    $('div:width(>200)'); // Select all DIVs that have a width greater than 200px
     
    // Alternative usage:
    $('div:width(>200):width(<300)'); // Select all DIVs that have a width greater
    // than 200px but less than 300px
  • :biggerThan()

    // Check whether element is bigger than another:
    $.extend($.expr[':'],{
    biggerThan: function(a,i,m) {
    if(!m[3]) {return false;}
    return $(a).width() * $(a).height() > $(m[3]).width() * $(m[3]).height();
    }
    });
     
    // Usage:
    $('div:biggerThan(div#banner))'); // Select all DIVs that are bigger than #banner
     
    // Alternative usage: (something a little more complex)
    // (Making use of custom width() selector)
     
    // Select all DIVs with a width less than 600px but an overall
    // size greater than that of the first paragraph which has a
    // size greater than img#header:
    $('div:width(<600):biggerThan(p:biggerThan(img#header):eq(0))');

Like I said, the possibilities are endless…

UPDATE

I’ve created a couple more examples, take a look:

  • :external

    // Check whether links are external:
    // (Only works with elements that have href):
    $.extend($.expr[':'],{
    external: function(a,i,m) {
    if(!a.href) {return false;}
    return a.hostname && a.hostname !== window.location.hostname;
    }
    });
     
    // Usage:
    $('a:external'); // Selects all anchors which link to external site/page
  • :inView

    // Check whether element is currently within the viewport:
    $.extend($.expr[':'],{
    inView: function(a) {
    var st = (document.documentElement.scrollTop || document.body.scrollTop),
    ot = $(a).offset().top,
    wh = (window.innerHeight && window.innerHeight < $(window).height()) ? window.innerHeight : $(window).height();
    return ot > st && ($(a).height() + ot) < (st + wh);
    }
    });
     
    // Usage:
    $('div:inView'); // Selects all DIV elements within the current viewport
     
    // Alternative Usage:
    if ( $('div#footer').is(':inView') ) {
    // Do stuff...
    }

UPDATE #2

I’ve created a plugin which makes it a little easier to add new ‘:’ selectors. Although, it’s not really a ‘plugin’, it’s just a function which resides under the jQuery namespace:

(function($){
$.newSelector = function() {
if(!arguments) { return; }
$.extend($.expr[':'],typeof(arguments[0])==='object' ? arguments[0]
: (function(){
var newOb = {}; newOb[arguments[0]] = arguments[1];
return newOb;
})()
);
}
})(jQuery);

Creating a new selector with the ‘newSelector’ plugin:

// Method 1:
$.newSelector('big', function(elem){
return $(elem).width() + $(elem).height() > 1000;
});
// Method 2:
$.newSelector({
red: function(elem){
return $(elem).css('color') === 'red';
},
yellow: function(elem){
return $(elem).css('color') === 'yellow';
},
green: function(elem){
return $(elem).css('color') === 'green';
},
});

Thanks for reading! Please share your thoughts with me on Twitter. Have a great day!

from http://james.padolsey.com/javascript/extending-jquerys-selector-capabilities/

扩展jquery的选择器的更多相关文章

  1. jquery选择器扩展之样式选择器

    https://github.com/wendux/style-selector-jQuery-plugin http://blog.csdn.net/duwen90/article/details/ ...

  2. jQuery 各种选择器 $.()用法

    jQuery 元素选择器jQuery 使用 CSS 选择器来选取 HTML 元素. $("p") 选取 <p> 元素. $("p.intro") 选 ...

  3. 扩展jquery easyui datagrid编辑单元格

    扩展jquery easyui datagrid编辑单元格 1.随便聊聊 这段时间由于工作上的业务需求,对jquery easyui比较感兴趣,根据比较浅薄的js知识,对jquery easyui中的 ...

  4. 扩展 -------jQuery

    本文摘要:http://www.liaoxuefeng.com/ 编写jQuery插件 为了满足需求,我们经常会调用一些插件,js插件都是别人写的,今天就来了解了解一些方法. 给jQuery对象绑定一 ...

  5. JQuery 实践--扩展JQuery

    Why扩展JQuery通过扩展可以利用JQuery所提供的现有代码基础.避免从头编写代码 有效扩展JQuery的规则扩展JQuery的两种形式: $上直接定义实用工具函数 和JQuery包装集进行操作 ...

  6. jQuery学习笔记——jQuery常规选择器

    一.简单选择器在使用 jQuery 选择器时,我们首先必须使用“$()”函数来包装我们的 CSS 规则.而CSS 规则作为参数传递到 jQuery 对象内部后,再返回包含页面中对应元素的 jQuery ...

  7. jQuery 的选择器常用的元素查找方法

    jQuery 的选择器常用的元素查找方法 基本选择器: $("#myELement")    选择id值等于myElement的元素,id值不能重复在文档中只能有一个id值是myE ...

  8. HTML 学习笔记 JQuery(选择器)

    学习前端也有一段时间了,今天终于进入到JQuery阶段了,对于新手来讲,JQuery的选择器类型之多 功能之强大实在不是一天两天能够记得完的.现在,就采用边学边记录的方式.以后要是忘了的话,也有一个地 ...

  9. 扩展 jquery miniui 组件实现自动查询数据

    主题 之前写过一篇文章分享了公司basecode查找数据后台是怎么实现的(http://www.cnblogs.com/abcwt112/p/6085335.html).今天想分享一下公司前台是怎么扩 ...

随机推荐

  1. VSFTP安装

    1. 先用rpm -qa| grep vsftpd命令检查是否已经安装,如果ftp没有安装, 使用yum? -y? install vsftpd 安装,(ubuntu 下使用apt-get insta ...

  2. Oracle 异常处理汇总

    Oracle 异常处理汇总 1.plsql无法连接 安装oracle,中间录入密码,用户是:sys,pass: 录入的密码. 连接数据库,建议创建新的用户,最好别直接用sys 安装完毕,则需要配置Ne ...

  3. nginx(tengine)的一些小优化(持续更新)

    1.nginx日志切割脚本 需求来源:nginx本身并没有日志切割的功能,由访问产生的大日志很难进行分析. 实现目的:每天对nginx日志进行切割,并备份至指定文件夹. 简要指令: mv /usr/l ...

  4. .NET微信公众号开发-6.0模板消息

    一.前言 为了保证用户不受到骚扰,在开发者出现需要主动提醒.通知用户时,才允许开发者在公众平台网站中模板消息库中选择模板,选择后获得模板ID,再根据模板 ID向用户主动推送提醒.通知消息.这个意思也就 ...

  5. chart.js插件生成折线图时数据普遍较大时Y轴数据不从0开始的解决办法[bubuko.com]

    chart.js插件生成折线图时数据普遍较大时Y轴数据不从0开始的解决办法,原文:http://bubuko.com/infodetail-328671.html 默认情况下如下图 Y轴并不是从0开始 ...

  6. navicat连接My SQL时忘记root密码处理方法

    前端时间安装完My SQL5.6以后很长时间没用过,用navicat连接时有错误提示 应该是密码错误了,但是忘记了root的密码. 在网上找了很久,终于找到修改root密码的方法并修改成功. 1. 关 ...

  7. 错误: 未能从 xmlsocket://127.0.0.1:5840 中加载策略文件

    看看你是否使用了MonsterDebugger,如果是这样的话, 因为那个 MonsterDebugger 没有启动 删掉MonsterDebugger的代码吧

  8. centos6.5 安装mysql 的过程

    Linux中使用最广泛的数据库就是MySQL,使用在线yum的方式安装的版本落后MySQL网站好几个小版本, 所以折腾了几个星期,终于在CentOS 装好了mysql5.6,装完之后,对整个linux ...

  9. 怎么打开sql server 数据库日志文件

    To Open Log File Viewer, 1. Expand Server Node > 2. Expand SQL Server Agent > 3. Expand Jobs & ...

  10. java获取配置文件里面的内容

    InputStream in = ReadProperties.class.getClassLoader() .getResourceAsStream("test.properties&qu ...