覆盖 JQuery 选择器以支持元素 id 中的美元符号 ($)

Override JQuery Selector to support Dollar Sign ($) in element id

本文关键字:美元 符号 id 选择器 JQuery 支持 元素 覆盖      更新时间:2023-09-26

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

美元符号插件.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 文件,它也可以正常工作。

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

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

  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>

但是:如果你要这样做,你必须小心地尽可能轻柔地踩踏。这意味着使用完全相同的参数数、相同的this值等调用原始参数;并确保替换$.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>

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

顺便说一句,请记住

,不应该对 HTML 的东西进行转义,例如 $('<span>give me $$$</span>'),所以我对此进行了粗略的检查。

(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($('#'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

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

$foo = jQuery.withSelectorEscaping();

它不考虑jQuery本身的行为,只为需要它的东西暴露你的转义功能。