web-dev-qa-db-ja.com

jQueryセレクター+ SVG互換性がない?

私はインラインSVGとJavaScriptアニメーションを含むHTML5ドキュメントで作業してきました。

ユーザーがどこかをクリックするとボックスがポップアップし、ユーザーがボックス以外の場所をクリックするとボックスが消えるようにしたいのですが。つまり、機能する$(window).click()を使用できません。

SVGにクラス名を付けて$(".svgclassname").click()を使用することでSVGを選択しようとしましたが、これは機能しないようです。 $("#svgname").click()を使用して個別に選択することもできません。

何が問題ですか?

$(".eyesvg")$(window)に置き換えると、ユーザーがウィンドウのどこかをクリックすると、カーソルの近くに青いボックスが表示されます。

38
Will

これは、SVG DOM仕様がHTML DOMと大きく異なるためです。

SVG DOMは異なる方言であり、一部のプロパティは同じ名前を持っていますが、意味が異なります。たとえば、svg要素のclassNameを取得するには、次を使用します。

svg.className.baseVal

これによって影響を受けるプロパティは

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

これらのアニメーションプロパティは構造体であり、baseValにはHTML DOMで見つかるのと同じ値が保持され、animatedValには何が保持されているかわかりません。

SVG DOMには、innerHTMLなど、ライブラリが依存する一部のプロパティもありません。

これは、jQueryをさまざまな方法で壊し、上記のプロパティに依存するものはすべて失敗します。

一般に、SVG DOMとHTML DOMはあまりうまく混合しません。彼らはあなたを誘惑するのにちょうど十分に協力し、それから物事は静かに壊れ、そして別の天使は翼を失います。

SVG要素をラップしてHTML DOMのように見えるようにする小さなjQuery拡張機能を書きました

(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オブジェクトのラッパーを作成し、それらをjQueryに対してHTML DOMのように見せます。私はそれをjQuery-UIで使用して、SVG要素をドロップ可能にしました。

HTMLとSVG間のDOM相互運用性の欠如は、完全に悲惨です。 HTML用に作成されたすべてのスイートユーティリティライブラリは、SVG用に再発明する必要があります。

68

時々私はそれを得られない...しかし実際にはそれはクラスセレクターで動作しません。 ID $( "#mysvg")または要素$( "svg")を使用すると、機能します!奇妙な..。

そして、ヘッダーから本文にsvg要素の後のonClickスクリプトを移動したときにのみ機能します。 jqueryは、バインディングの前に要素が宣言されている場合にのみ、onclickをバインドできます。

4
räph

あなたはチャームのように 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>