覆盖JQuery Selector以支持元素id中的Dollar Sign($)

时间:2015-06-10 07:23:26

标签: javascript jquery html jquery-plugins

我正在尝试编写一个JQuery插件来支持$ in元素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 =“#”的标签时,此行来自bootstrap。

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

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

2 个答案:

答案 0 :(得分:3)

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

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

  2. 您当前的实施会搞乱像

    这样的事情
    $("<div>$12</div>").appendTo(document.body);
    

    (在美元符号前加一个反斜杠)。谁知道还有什么搞砸?

  3. 相反,我只是有一个简单的:

    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>

答案 1 :(得分:1)

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

顺便说一下,请记住,不应该对HTML内容进行转义,例如: $('<span>give me $$$</span>'),所以我已经做了粗略的检查。

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

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

$foo = jQuery.withSelectorEscaping();

它只保留jQuery本身的行为,只为需要它的事物公开你的转义功能。