2009年9月17日星期四

[bug-fixed]jQuery-SVG插件在IE上使用的注意点!

1. 由于IE本身不支持SVG所以需要安装插件来实现,一般使用adobe-svg-viewer。jQuery-SVG插件在附加SVG图片的时候,由于IE使用的是插件,所以它先附加一个默认的空的SVG图片(blank.svg),这与firefox等其他原生支持svg不同的是firefox只需要加一个<svg ...></svg>标签就可以。这就导致了一个不同点:必需设置initPath属性,否则插件找不到blank.svg图片。如下形式附加空标签:

$('div#svg').svg({initPath:'js/'}); //blank.svg在js文件目录下

(这个问题一直困扰了我1个多小时...看了源码后才明白 )

2. 第二个注意点在于附加svg标签这一步中,代码如下:

$('div#svg').svg({initPath:'js/'});//jquery object
var svgPic = $("div#svg").svg('get');//SVG wrapper object
svgPic.load(mapUrl, {
        changeSize: false,
        onLoad: function (svgg, error) {
            //TODO :载入完成之后需要做的事!
        }}
    );

看起来没什么问题,但是放到IE下就会出现svgPic为“undefined”的情况。
仔细看svg('get');方法源码如下:

var PROP_NAME = 'svgwrapper';   
 
_getSVG: function(container) {
        container = (typeof container == 'string' ? $(container)[0] :
            (container.jquery ? container[0] : container));
        return $.data(container, PROP_NAME);
    },
 
排除一些可能之后,问题在于return $.data(container, PROP_NAME);
这是jQuery的内部函数,功能如下;

jQuery.data( elem, name )

Returns value at named data store for the element.

jQuery.data( elem, name, value )

Stores the value in the named spot and also returns the value.
This function can be useful for attaching data to elements without having to create a new expando. It also isn't limited to a string. The value can be any format.

To avoid conflicts in plugins, it is usually effective to store one object using the plugin name and put all the necessary information in that object.

可见它是用于存储的,而存入这个值的函数在attachSVG方法中,代码如下:
_attachSVG: function(container, settings) {
        .......
        try {
            // firefox等其他浏览器使用   
            var svg = document.createElementNS(this.svgNS, 'svg');
            svg.setAttribute('version', '1.1');
            svg.setAttribute('width', container.clientWidth);
            svg.setAttribute('height', container.clientHeight);
            container.appendChild(svg);
            this._afterLoad(container, svg, settings);
        }
        catch (e) {
            if ($.browser.msie) {
                //IE使用
                if (!container.id) {
                    container.id = 'svg' + (this._uuid++);
                }
                this._settings[container.id] = settings;
                container.innerHTML = '<embed type="image/svg+xml" width="100%" ' +
                    'height="100%" src="' + (settings.initPath || '') + 'blank.svg"/>';
            }
            else {
                //浏览器不支持情况
                container.innerHTML = '<p class="svg_error">' +
                    this.local.notSupportedText + '</p>';
            }
        }
    },
 
    _afterLoad: function(container, svg, settings) {
        var settings = settings || this._settings[container.id];
        this._settings[container.id] = null;
        var wrapper = new this._wrapperClass(svg, container);
        $.data(container, PROP_NAME, wrapper);
         ......
    },
 
可见在IE情况下并不会设置这个值,那么什么时候设置呢?registSVG方法如下:

    _registerSVG: function() {
        for (var i = 0; i < document.embeds.length; i++) { // Check all
            var container = document.embeds[i].parentNode;
            if (!$(container).hasClass($.svg.markerClassName) || // Not SVG
                $.data(container, PROP_NAME)) { // Already done
                continue;
            }
            var svg = null;
            try {
                svg = document.embeds[i].getSVGDocument();
            }
            catch(e) {
                setTimeout($.svg._registerSVG, 250); // Renesis takes longer to load
                return;
            }
            ......
        }
    },
 
奇怪的是并没有函数调用registerSVG(还没搞懂),不过也可以看出对IE来说设置值需要一定的时间,所以之前的代码马上执行svg('get')操作得不到正确值!
所以需要将svg();和svg('get');方法分开执行,或设置一段等待时间!

没有评论: