Javascript 为所有元素返回匹配项的自定义jQuery选择器

Javascript 为所有元素返回匹配项的自定义jQuery选择器,javascript,jquery,jquery-selectors,Javascript,Jquery,Jquery Selectors,我正在尝试组合一个自定义jquery选择器,用于在asp.net中匹配asp客户端ID。我正在研究这两篇博客的信息,并且 问题是我现在正在返回页面上每个元素的匹配项。我有点知道为什么(因为我每次思考时都会查询所有节点),但我的大脑绝对疲惫不堪,我已经把自己编码为服从 如果有人能找出哪里出了问题并给我一些建议,我将非常感激 选择器的用法如下所示: $("input:clientID(TextBox1)") 干杯 编辑:到目前为止我已经得到了这段代码,但这将返回以给定id结尾的所有节点 (fun

我正在尝试组合一个自定义jquery选择器,用于在asp.net中匹配asp客户端ID。我正在研究这两篇博客的信息,并且

问题是我现在正在返回页面上每个元素的匹配项。我有点知道为什么(因为我每次思考时都会查询所有节点),但我的大脑绝对疲惫不堪,我已经把自己编码为服从

如果有人能找出哪里出了问题并给我一些建议,我将非常感激

选择器的用法如下所示:

$("input:clientID(TextBox1)")
干杯

编辑:到目前为止我已经得到了这段代码,但这将返回以给定id结尾的所有节点

 (function ($) {
    $.expr[":"].clientID = function (objNode, intStackIndex, arrProperties, arrNodeStack) {

        var keyValue, tName, $node, len, id;

        if (arrProperties[3]) {

            // Split into array (name,value):
            keyValue = arrProperties[3];

            // Check to see whether a tag node has been supplied.
            if (objNode) {

                // Get the name.
                tName = objNode.tagName;
                $node = $(objNode);
                id = $node.attr("id");

                if ((id.lastIndexOf(keyValue) === id.length - keyValue.length) && ($node.is(":first"))) {
                    return true;
                }
                else if (id === keyValue) {
                    return true;
                }
                else {

                    return false;
                }

            } else {

                // No node supplied so will use the ends with attribute selector.
                return $("[id$=\"_" + keyValue + "\"]").first().length > 0;
            }

        } else {

            // If we have made it this far, then we found no
            // match. Return false to indicate that this node
            // did not match our selector.
            return false;
        }
    };

} (jQuery));

我认为您误解了jQuery选择器的工作原理。下面是它们的工作原理。假设您使用以下内容进行查询:

$("input:clientID(TextBox1)");
jQuery首先查找所有输入元素,然后针对每个输入元素询问函数是否应该包含它。因此,如果您的页面有10个
input
元素,那么您的函数将被调用10次

您不必自己查询DOM

有了这种理解,您就更容易决定节点的id是否包含
\u TextBox1

(function ($) {
    $.expr[":"].clientID = function(objNode, intStackIndex, arrProperties, arrNodeStack) {
        // we need to something to query
        if( ! arrProperties[3] ) return false; 
        return objNode.id.indexOf( "_" + arrProperties[3] ) !== -1;
    };
} (jQuery));
我将把ASP.net的细节留给您,因为我不熟悉ASP.net客户端ID是如何生成的。然而,据我所知,您也可以通过内置jQuery选择器实现相同的功能(正如其他人所提到的)

编辑-查找ASP.net格式的id 要选择可以是“xxx\u xxx\u clientID”或“clientID”的ID,可将代码修改为:

var testID = arrProperties[3];
if( objNode.id == testID ) return true;

// ends with code
testID = "_" + testID;
var lastIndex = objNode.id.lastIndexOf(testID);
return lastIndex !== -1 && lastIndex == (objNode.id.length - testID.length);
编辑2-仅查找第一个匹配的元素 为了只匹配第一个结果,可以在找到某个内容时设置标志变量。这应该比使用James的解决方案快得多,但不太干净

(function ($) {
    // assign the clientID filter with a self-executing anonymous function
    $.expr[":"].clientID = (function(){
        // create a "private" flag variable
        var alreadyFound = false;

        return function(objNode, intStackIndex, arrProperties, arrNodeStack) {
            if( intStackIndex === 0 ) alreadyFound = false;
            if( alreadyFound ) return false;

            var testID = arrProperties[3];
            if( objNode.id == testID){
                alreadyFound = true;
            } else {
                // ends with code
                testID = "_" + testID;
                var lastIndex = objNode.id.lastIndexOf(testID);
                alreadyFound = lastIndex !== -1 && lastIndex == (objNode.id.length - testID.length);
            }

            return alreadyFound;
        };

    })();
} (jQuery));

alreadyFound
变量可以通过闭包访问我们的clientID函数(而不是其他任何函数)。

有点现成,但是将clientID更改为Static而不必担心它怎么样

<asp:Label ID="Label1" runat="server" ClientIDMode="[Mode Type]" />

我只是添加了一个答案,以便显示最终代码。没有斯卡比斯我不可能走这么远,所以他会得到分数的

选择器返回具有给定clientid的asp控件的第一个实例。它在没有标记名的情况下工作(尽管速度要慢得多)。我已经尽我最大的能力对它进行了优化,但如果有人能加快速度,那就太好了

Usage: $("input:clientID(TextBox1)");
享受

(function ($) {
    // A cache for holding our grepped array.
    var cache = [];

    $.expr[":"].clientID = function (node, stackIndex, properties, nodeStack) {
        // <summary>
        //     Selects a single Asp.Net server control whose id has been prefixed.
        // </summary>
        //  <param name="node" type="Object">
        //      This is a reference to the current DOM element being evaluated. 
        //      This is not a jQuery version of the element but the actual DOM node.
        //  </param>
        //  <param name="stackIndex" type="Integer">
        //      This is the zero-based index of the given node within the stack of 
        //      nodes that will be evaluated with this selector call.
        //  </param>
        //  <param name="properties" type="Array">
        //      This is an array of meta data about the custom jQuery selector execution. 
        //      Of this, only the fourth argument (index 3) is of any real value - it contains 
        //      the string data that was passed to the jQuery selector.
        //  </param>
        //  <param name="nodeStack" type="Array">
        //      This is an array of the DOM elements that are being evaluated with this selector.
        //      The inStackIndex integer above is the current DOM element's index within this array.
        //  </param>
        //  <returns type="jQuery"/>
        var testID = properties[3],
        endsWithID = "_" + testID,
        nodeID,
        id = node.id,
        lastIndex,

        grep = function (elems, callback, inv) {
            /// <summary>
            /// Tweaked for speed version of the native jQuery grep.
            /// </summary>

            var ret = [], retVal, len = elems.length;
            inv = !!inv;

            // Go through the array, only saving the items
            // that pass the validator function
            while (len--) {
                retVal = !!callback(elems[len], len);

                if (inv !== retVal) {
                    ret.push(elems[len]);
                }
            }

            // reverse since we are descending.
            return ret.reverse();
        };

        // Check if there is anything in the cache and grep if not.
        if (cache.length === 0) {
            var trimmed = grep(nodeStack, function (val, key) {
                return val.id.lastIndexOf(testID) !== -1;
            });

            cache = trimmed;
        }

        // Get the first node id only.
        nodeID = cache[0].id;
        lastIndex = nodeID.lastIndexOf(endsWithID);

        // Clear the cache on the last element.
        if (stackIndex === nodeStack.length - 1) {
            cache.length = 0;
        }

        // Check the id.
        if ((nodeID === id) || (lastIndex !== -1 && nodeID.substring(lastIndex + 1) === id)) {
            return true;
        }

        // Strict.
        return false;
    };
} (jQuery));
(函数($){
//一个用来存放我们的灰色数组的缓存。
var缓存=[];
$.expr[“:”].clientID=函数(节点、堆栈索引、属性、节点堆栈){
// 
//选择id已加前缀的单个Asp.Net服务器控件。
// 
//  
//这是对正在计算的当前DOM元素的引用。
//这不是元素的jQuery版本,而是实际的DOM节点。
//  
//  
//这是堆栈中给定节点的从零开始的索引
//将使用此选择器调用计算的节点。
//  
//  
//这是一个关于自定义jQuery选择器执行的元数据数组。
//其中,只有第四个参数(索引3)具有任何实际值-它包含
//传递给jQuery选择器的字符串数据。
//  
//  
//这是使用此选择器计算的DOM元素数组。
//上面的inStackIndex整数是此数组中当前DOM元素的索引。
//  
//  
var testID=属性[3],
endsWithID=“”+testID,
诺代德,
id=node.id,
最新索引,
grep=函数(元素、回调、inv){
/// 
///调整为本地jQuery grep的速度版本。
/// 
变量ret=[],retVal,len=elems.length;
inv=!!inv;
//遍历数组,只保存项目
//通过验证器函数的
而(len--){
retVal=!!回调(elems[len],len);
如果(inv!==retVal){
再推(elems[len]);
}
}
//相反,因为我们正在下降。
返回反向返回();
};
//检查缓存中是否有任何内容,如果没有,请执行grep。
如果(cache.length==0){
var trimmed=grep(节点堆栈,函数(val,键){
返回val.id.lastIndexOf(testID)!=-1;
});
缓存=修剪;
}
//仅获取第一个节点id。
nodeID=cache[0].id;
lastIndex=nodeID.lastIndexOf(endsWithID);
//清除最后一个元素上的缓存。
if(stackIndex==nodeStack.length-1){
cache.length=0;
}
//检查一下身份证。
if((nodeID==id)| |(lastIndex!==1&&nodeID.substring(lastIndex+1)==id)){
返回true;
}
//严格的。
返回false;
};
}(jQuery));

查看代码,您是否正在尝试实现此选择器可以实现的功能:$(“[id$=”\u TextBox1']”?同意@Cybernate,代码似乎比需要的复杂得多。这个自定义选择器到底应该匹配/不匹配什么?@Cybernate,MattBall:这根本不会返回任何结果。我相信你的意思是$(“[id$='TextBox1']”)。这将返回所有匹配的id。想想嵌套的中继器。我可以使用$($(“[id$='TextBox1']”)[0]),但我发现速度非常慢。为什么它不会返回任何东西(当然,只要有一个HTMl元素的id以_TextBox1结尾,这就是ASP.Net呈现TextBox1 id的方式)?你能详细说明一下嵌套转发器部分吗?@Cybernate:因为Asp