【问题标题】:Override JQuery Selector to support Dollar Sign ($) in element id覆盖 JQuery 选择器以支持元素 id 中的美元符号 ($)
【发布时间】:2015-06-10 07:23:26
【问题描述】:

我正在尝试编写一个 JQuery 插件来支持元素 ID 中的 $,我的代码是:

DollarSignPlugin.js:

function escapeJQueryElementName(elementName) {
    elementName = elementName.replace(/\\\$/g, "$");

    return elementName.replace(/\$/g, "\\$");
}

var jQueryInit = $.fn.init;

$.fn.init = function(arg1, arg2, rootjQuery){
    arg2 = arg2 || window.document;
    if (arg1 && arg1.replace) {
        var newArg1 = escapeJQueryElementName(arg1);
        return new jQueryInit(newArg1, arg2, rootjQuery);
    }

    return new jQueryInit(arg1, arg2, rootjQuery);
};

效果很好,但我在当前行遇到了一个问题:

var $anyselector = $("#");

JQuery 抛出错误“语法错误,无法识别的表达式:#”。

当单击任何带有 href="#" 的选项卡时,此行来自引导程序。

删除我的插件时不会出现此错误,如果我将替换功能直接复制粘贴到 jquery 文件中,它也可以正常工作。

那么有没有更好的方法来覆盖选择器或者我的代码有问题,请帮忙?

【问题讨论】:

    标签: javascript jquery html jquery-plugins


    【解决方案1】:

    我强烈建议你不要这样做(但如果你愿意,请继续阅读,我在下面有一个修复),因为:

    1. 这意味着您在代码中使用了无效的选择器,这是一个维护问题 - 在某些时候,进行维护的人不了解发生了什么,或者您会遇到边缘条件等。

    2. 你当前的实现会搞砸

      $("<div>$12</div>").appendTo(document.body);
      

      (通过在美元符号前放置反斜杠)。谁知道还有什么问题?

    相反,我只需要一个简单的:

    function $gid(id) {
        var e = document.getElementById(id);
        if (!e) {
            return $();
        }
        if (e.id === id) {
            return $(e);
        }
        // Fallback processing for old IE that matches name attributes
        return $('[id="' + id.replace(/"/g, '\\"') + '"]').filter(function() {
            return this.id === id;
        }).first();
    }
    

    例子:

    // Plugin
    function $gid(id) {
        var e = document.getElementById(id);
        if (!e) {
            return $();
        }
        if (e.id === id) {
            return $(e);
        }
        // Fallback processing for old IE that matches name attributes
        return $('[id="' + id.replace(/"/g, '\\"') + '"]').filter(function() {
            return this.id === id;
        }).first();
    }
    
    // Use
    $gid("a$b").css("color", "blue");
    $gid("$c").css("color", "green");
    <div id="a$b">a$b</div>
    <div id="$c">$c</div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

    但是:如果您要这样做,则必须小心地尽可能轻柔地踩踏。这意味着使用完全相同数量的参数、相同的thisvalue 等调用原始文件;并确保 $.fn.init.prototype 在替换 $.fn.init 后具有相同的值。

    做这两件事似乎可以解决问题:

    // Plugin
    (function () {
        function escapeJQueryElementName(elementName) {
            elementName = elementName.replace(/\\\$/g, "$");
            return elementName.replace(/\$/g, "\\$");
        }
    
        var slice = Array.prototype.slice;
        var jQueryInit = $.fn.init;
    
        $.fn.init = function (arg1) {
            var args = slice.call(arguments, 0);
            if (arg1 && arg1.replace) {
                args[0] = escapeJQueryElementName(arg1);
            }
            return jQueryInit.apply(this, args);
        };
        $.fn.init.prototype = $.fn;
    })();
    
    // Use
    $("#a$b").css("color", "blue"); // Using special version that handles $ without \\
    $("#$c").css("color", "green"); // Using special version that handles $ without \\
    $("<div>Checking '#' selector, should get 0: " + $("#").length + "</div>").appendTo(document.body);
    <div id="a$b">a$b</div>
    <div id="$c">$c</div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

    【讨论】:

    • 感谢您提请我注意此技术可能出现的问题,我已更新您代码中的条件以将其严格限制为 id 和 classes 选择器,这样我们将避免在不需要时替换 $ : if (typeof(arg1) === "string" && arg1.indexOf("$") !== -1 && (arg1.startsWith(".") || arg1.startsWith("#"))) { args[0] = escapeJQueryElementName(arg1); }
    【解决方案2】:

    与其试图通过覆盖实际上只应该在内部使用的东西来解决这个问题,更好的解决方案是创建一个新的 jQuery 别名并支持转义选择器的函数。

    顺便说一句,请记住,不应对 HTML 内容进行转义,例如$('&lt;span&gt;give me $$$&lt;/span&gt;'),所以我对此进行了粗略的检查。

    (function(jQuery) {
      jQuery.withSelectorEscaping = function() {
        function escapeJQueryElementName(elementName) {
          elementName = elementName.replace(/\\\$/g, "$");
          return elementName.replace(/\$/g, "\\$");
        }
    
        return function(selector, context) {
          // avoid doing this for HTML
          if (selector && selector.replace && selector[0] !== '<') {
            selector = escapeJQueryElementName(selector);
          }
          return jQuery(selector, context);
        };
      }
    }(jQuery));
    
    // create new alias here
    $ = jQuery.withSelectorEscaping();
    
    // use new alias
    console.log($('#'));
    &lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

    这段代码sn-p 给jQuery 本身增加了一个新的函数jQuery.withEscaping;它返回一个函数,然后您可以将其分配给您选择的别名,我在这里选择了$,但您也可以这样做:

    $foo = jQuery.withSelectorEscaping();
    

    它让jQuery 本身的行为保持不变,只为需要它的东西公开你的转义功能。

    【讨论】:

    • 感谢@Jack 的快速响应,它可以工作,但它会导致其他插件停止工作,例如 jQuery-migrate。
    • @Anas 如果这些插件正确扩展 jQuery 而不是 $ 它们应该可以正常工作。你能举一个停止工作的例子吗?
    • $.browser.msie,我使用的是 JQuery 1.11.3,并使用 JQuery-migrate 来支持这个旧方法。
    猜你喜欢
    • 1970-01-01
    • 2010-12-14
    • 2013-04-03
    • 1970-01-01
    • 2016-11-17
    • 2020-02-05
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    相关资源
    最近更新 更多