在IE浏覽器下使用OpenFlashChart技術實作圖表展示,在重新整理圖表時會遇到“無法擷取屬性reload的值: 對象為 null 或未定義”的問題,本文給出了該問題的解決方法。
由于項目需求,需要在網頁上利用圖表展示相關資料的統計資訊,采用了OpenFlashChart技術。OpenFlashChart是一款開源的以Flash和Javascript為技術基礎的免費圖表,用它能建立一些很有效果的報表分析圖表。最重要的是它是開源和免費的,支援多種語言。首先在官網上下載下傳開發包,裡面包含了所需的flash檔案、js檔案以及多種語言的demo,這些demo寫的非常詳細,可以進行參考開發。由于項目使用.net來開發,是以我學習了一下開發包中對應的dotnet代碼,這個.net項目采用面向對象的方式對圖表進行了合理的分析,建立了一些與OpenFlashChart相對應的類,用來描述圖表資訊,還編寫了相應的使用者控件,友善開發人員直接使用。
好了,廢話不多說了,開始說問題了(想了解具體開發技術可參考官網教程和示例代碼),由于需要多角度全方位的展示圖示,那麼就必須要根據不同的要求動态重新整理圖表資訊,根據官網上的方法,可利用以下代碼:
1 function reload()
2 {
3 tmp = findSWF("chart");
4
5 //
6 // reload the data:
7 //
8 x = tmp.reload();
9
10 //
11 // to load from a specific URL:
12 // you may need to \'escape\' (URL escape, i.e. percent escape) your URL if it has & in it
13 //
14 x = tmp.reload("gallery-data-32.php?beer=1");
15
16 //
17 // do NOT show the \'loading...\' message:
18 //
19 x = tmp.reload("gallery-data-32.php?beer=1", false);
20 }
21
22 function findSWF(movieName) {
23 if (navigator.appName.indexOf("Microsoft")!= -1) {
24 return window["ie_" + movieName];
25 } else {
26 return document[movieName];
27 }
28 }
通過調用reload方法來實作圖示重新整理,按照這種方式寫完代碼後運作,在chrome中果然可以達到預想中的效果,然而,IE給我潑了一盆冷水,報出了錯誤:無法擷取屬性“reload”的值: 對象為 null 或未定義,甚至官網上點選“reload”時也會報錯(如下圖),這下我桑心了,估計不好解決了。

沒辦法,問題總要處理。經過檢視,發現錯誤的主要原因在于findSWF方法傳回的對象為null,也就是說在IE中通過 window["ie_" + movieName] 無法得到flash執行個體,這個方法是作者本人寫的,目的就是為了相容IE,因為官網上的描述是:IE中的圖表ID跟firefox不同,是以前面加上了"ie_",不知道為什麼不好使。然後我就在網上各種搜尋,希望能找到方法,這個問題也确實有很多人遇到,但都沒有給出很好的解決方法,無奈之下,我隻有進行變通處理,即:在重新整理時銷毀掉之前的flash對象,重新進行加載,并傳入相應的json資料。這種方法也可以實作所需的功能,但是由于我銷毀flash對象的手段僅僅是通過删除包含該flash對象的div元素,我總感覺這種方法可能沒有真正的将flash對象删除,因為我在網上看到有的人通過此方法删除外層div元素後,裡面的flash仍然還在執行相應的操作,一旦情況确實如此,那麼每重新整理一次就會構造出一個新的flash對象,這樣的話如果重新整理頻繁就會造成記憶體的消耗不斷增長,顯然,考慮到這個情況,這種實作方法是行不通的。這下我又陷入了麻煩中,如果這個問題解決不了的話可能就會換用其他技術來實作,那我之前話費時間研究OpenFlashChart就算是做了無用功了,再想想吧,總感覺有解決方法。突然之間,我想到了之前做檔案上傳時用到了swfupload技術,這也是利用flash對象來實作相關功能的,我打開源碼,看看該元件是怎麼處理IE的相容問題的,希望能從中發現一些端倪,經過一番檢視,終于在“SWFUpload.prototype.loadFlash”方法中發現了一段話:
// Fix IE Flash/Form bug
if (window[this.movieName] == undefined) {
window[this.movieName] = this.getMovieElement();
}
從注釋上看這段代碼是為了處理IE bug的,然後繼續檢視this.getMovieElement()方法:
// Public: get retrieves the DOM reference to the Flash element added by SWFUpload
// The element is cached after the first lookup
SWFUpload.prototype.getMovieElement = function () {
if (this.movieElement == undefined) {
this.movieElement = document.getElementById(this.movieName);
}
if (this.movieElement === null) {
throw "Could not find Flash element";
}
return this.movieElement;
};
原來擷取flash對象就是通過最常用的getElementById方法,這裡的movieName就是flash對象的id值,看到這裡,我趕緊将findSWF方法中的代碼進行了如下修改:
function findSWF(movieName) {
// Fix IE Flash/Form bug
if (window[movieName] == undefined) {
window[movieName] = document.getElementById(movieName);
}
return window[movieName];
}
修改後在chrome浏覽器、IE浏覽器(正常視圖和相容性視圖)和360浏覽器(極速模式和相容模式)上運作,果然都達到了預期的效果,至此,問題解決!