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

时间:2011-04-13 16:27:40

标签: javascript jquery jquery-selectors

我正在尝试将自定义jquery选择器组合在一起,以便在Asp.net中匹配asp客户端ID。我正在处理来自这两个博客条目herehere

的信息

问题是我现在正在页面上的每个元素上返回一个匹配项。我知道为什么(这是我每次想的时候都在查询所有节点)但是我的大脑绝对是疲惫的,我已经把自己写成了提交。

如果有人能弄清楚出了什么问题,并给我一些指示,我会非常感激。

选择器的用法如下:

$("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));

3 个答案:

答案 0 :(得分:2)

我认为你误解了jQuery选择器应该如何工作。这是他们的工作方式。假设您使用以下内容进行查询:

$("input:clientID(TextBox1)");

jQuery首先找到所有输入元素,然后,每个输入元素询问您的函数是否应该包含它。因此,如果您的页面有10个input元素,那么您的函数将被调用10次。

您不必自己查询DOM

通过这种理解,您可以更轻松地确定节点的ID是否包含_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 clientID。但是,根据我的理解,您还可以简单地使用内置的jQuery选择器实现相同的功能(正如其他人提到的那样)。

编辑 - 查找ASP.net格式的id

要选择可能是“xxx_xxx_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));

我们的clientID函数(而且没有其他人)可以通过闭包访问alreadyFound变量。

答案 1 :(得分:0)

开箱即用,但如何将ClientIDMode更改为静态而不用担心呢?

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

http://weblogs.asp.net/asptest/archive/2009/01/06/asp-net-4-0-clientid-overview.aspx

答案 2 :(得分:0)

我只是添加一个答案,以便显示最终代码。如果没有Skabbes,我就无法做到这一点,所以他会得到积分。

选择器返回具有给定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));