jQuery Selector + SVG несовместим?

Я работал с документом HTML5 со встроенной анимацией SVG и javascript.

Я бы хотел, чтобы окно всплывало, когда пользователь щелкает в любом месте, и я бы хотел, чтобы окно исчезло, когда пользователь щелкнет где-нибудь, кроме окна. Это означает, что я не могу использовать $(window).click(), который работает.

Я пробовал выбирать SVG сверху, давая им имена классов и используя $(".svgclassname").click(), но это, похоже, не работает. Также нет выбора отдельных с помощью $("#svgname").click().

В чем проблема?

(Когда я заменяю $(".eyesvg") на $(window), рядом с курсором появляется синее поле, когда пользователь щелкает в любом месте окна.)


person Will    schedule 20.07.2010    source источник


Ответы (3)


Это происходит потому, что спецификация SVG DOM сильно отличается от HTML DOM.

SVG DOM - это другой диалект, и некоторые свойства имеют одинаковые имена, но означают разные вещи. Например, чтобы получить className элемента svg, вы используете:

svg.className.baseVal

Это затрагивает следующие свойства:

className is SVGAnimatedString
height,width, x, y, offsetWidth, offsetHeight are SVGAnimatedLength

Эти свойства Animated являются структурами, где baseVal содержит то же значение, что и в HTML DOM, а animatedVal - я не уверен, что именно.

В SVG DOM также отсутствуют некоторые библиотеки свойств, от которых зависят, например, innerHTML.

Это ломает jQuery разными способами, все, что зависит от вышеуказанных свойств, терпит неудачу.

В общем, SVG DOM и HTML DOM не очень хорошо сочетаются. Они работают вместе ровно настолько, чтобы заманить вас, а затем все тихо ломается, и другой ангел теряет свои крылья.

Я написал небольшое расширение jQuery, которое обертывает элементы SVG, чтобы они больше походили на HTML DOM.

(function (jQuery){
    function svgWrapper(el) {
        this._svgEl = el;
        this.__proto__ = el;
        Object.defineProperty(this, "className", {
            get:  function(){ return this._svgEl.className.baseVal; },
            set: function(value){    this._svgEl.className.baseVal = value; }
        });
        Object.defineProperty(this, "width", {
            get:  function(){ return this._svgEl.width.baseVal.value; },
            set: function(value){    this._svgEl.width.baseVal.value = value; }
        });
        Object.defineProperty(this, "height", {
            get:  function(){ return this._svgEl.height.baseVal.value; },
            set: function(value){    this._svgEl.height.baseVal.value = value; }
        });
        Object.defineProperty(this, "x", {
            get:  function(){ return this._svgEl.x.baseVal.value; },
            set: function(value){    this._svgEl.x.baseVal.value = value; }
        });
        Object.defineProperty(this, "y", {
            get:  function(){ return this._svgEl.y.baseVal.value; },
            set: function(value){    this._svgEl.y.baseVal.value = value; }
        });
        Object.defineProperty(this, "offsetWidth", {
            get:  function(){ return this._svgEl.width.baseVal.value; },
            set: function(value){    this._svgEl.width.baseVal.value = value; }
        });
        Object.defineProperty(this, "offsetHeight", {
            get:  function(){ return this._svgEl.height.baseVal.value; },
            set: function(value){    this._svgEl.height.baseVal.value = value; }
        });
    };

    jQuery.fn.wrapSvg = function() {
        return this.map(function(i, el) {
            if (el.namespaceURI == "http://www.w3.org/2000/svg" && !('_svgEl' in el))
                return new svgWrapper(el);
            else
                return el;
            });
        };
})(window.jQuery);

Он создает оболочку вокруг объектов SVG, которая делает их похожими на HTML DOM для jQuery. Я использовал его с jQuery-UI, чтобы мои элементы SVG можно было удалять.

Отсутствие совместимости DOM между HTML и SVG - полная катастрофа. Все замечательные служебные библиотеки, написанные для HTML, нужно заново изобрести для SVG.

person Aleksandar Totic    schedule 22.04.2011
comment
Привет, Александр, спасибо за предложение! Фрагмент ушел довольно далеко, но не работал в Firefox 15 из-за ошибки, возникающей при использовании прототипного наследования напрямую с элементом SVG DOM. Мы изменили его для работы в Firefox и успешно его используем. Код находится здесь: github.com/RedBrainLabs/jquery.wrap-svg - person Tim Harper; 08.09.2012
comment
Просто загрузив скрипт в Safari 8.0, я получил сообщение об ошибке: SyntaxError: Операторы функции должны иметь имя. (svg.js, строка 1). Я поместил сценарий в отдельный файл js, svg.js, и попытался загрузить его до и после файла jQuery. Одна и та же ошибка в обоих случаях. - person Andrew Swift; 28.07.2014
comment
Выглядит отлично, но как его использовать? - person kris; 05.07.2017

Вы можете использовать плагин jquery-svg, например, как шарм:

<script>
    //get svg object, like a jquery object
    var svg = $("#cars").getSVG();
    //use jquery functions to do some thing
    svg.find("g path:first-child()").attr('fill', color);
</script>
person mohammadreza berneti    schedule 18.03.2016

иногда я этого не понимаю ... но на самом деле это не работает с селектором классов. Если вы используете идентификатор $ ("# mysvg") или элемент $ ("svg"), это действительно работает! Странный....

И это работает только тогда, когда вы перемещаете скрипт onClick из заголовка в тело после элемента svg! jquery может привязать onclick только тогда, когда элемент объявлен до привязки.

person räph    schedule 21.07.2010
comment
Ага! Это потрясающе работает. Несмотря на проблему jQuery с селектором классов, я уверен, что смогу выбрать несколько идентификаторов. Спасибо! - person Will; 21.07.2010
comment
Обратите внимание, что вы можете выбирать элементы SVG по классу, используя $('*[class~="eyesvg"]') (атрибут содержит селектор слов < / а>). - person Phrogz; 04.05.2011