2008年7月11日 星期五

用 jQuery 動態載入 json-in-script 的作法

在準備改版『依相關度排序的相關文章』的過程之中, 幾乎可以確定要用 jQuery 來寫, 不過其中有一個問題, 就是如何 動態載入 不同類別標籤 的 JSON, ....

好啦, 沒有打算要用 jQuery 來寫 json-in-script 的人, 請再忍耐一下, 看完下面這一句再轉台,

json-in-script 要當作 JavaScript 來載入, 所以用 jQuery 動態載入 json-in-script, 也就是要用 jQuery 動態載入 JavaScript 的意思。

今天終於讓我試出來了, 簡單的說, 要使用 jQuery 的 $.getScript() 或 $.ajax();

.

2008-07-17 : 請見意見的最新訊息, 或看底下是否有新的『相關文章』

原本, 靜態呼叫 json-in-script 的方式, 像底下這樣, 其中 VB 是類別標籤的名字, 問號 ( ? ) 後面的 alt=json-in-script&callback= ... , 則是設定回傳格式為 json-in-script, 以及指定 callback function

<script src="http://eucaly61.blogspot.com/feeds/posts/default/-/VB?alt=json-in-script&callback=RelatedLabels" type="text/javascript"/>

再來, 要注意的是 json-in-script 和 JSON 的差別,

  • JSON 指的是『資料格式』, 詳見 JSON Feeds (Beautiful Beta),
    也就是底下紅色的部分,
  • json-in-script 則是將 JSON 資料 回傳給 callback function,
    將 JSON 塞在括號內, 再呼叫 RelatedLabels()

不信的話, 點選上面 script src= 的 http:// 連結, 就會看到如下的內容,

RelatedLabels({"version":"1.0","encoding":"UTF-8","feed":{"xmlns":"http://www.w3.org/2005/Atom","xmlns$openSearch":"http://a9.com/-/spec/opensearchrss/1.0/","id":{"$t":"tag:blogger.com,1999:blog-8685080495061991394"},"updated":{"$t":"2008-07-10T22:12:07.563+08:00"},"title":{"type":"text","$t":"Beyond Alternative"},"link":[{"rel":"alternate","type":"text/html","href":http://eucaly61.blogspot.com/search/label/VB},
...
openSearch$totalResults":{"$t":"3"},"openSearch$startIndex":{"$t":"1"},"openSearch$itemsPerPage":{"$t":"25"},"entry":[{"id":{"$t":"tag:blogger.com,1999:blog-8685080495061991394.post-6282815987510613229"},"published":{"$t":"2008-06-27T23:23:00.001+08:00"},"updated":{"$t":"2008-06-28T00:29:03.151+08:00"},"category":[{"scheme":"http://www.blogger.com/atom/ns#","term":"程式設計"},{"scheme":"http://www.blogger.com/atom/ns#","term":"VB"},{"scheme":"http://www.blogger.com/atom/ns#","term":"Excel"}],"title":{"type":"text","$t":"[Excel 巨集] Address 函數 -- 傳回『範圍參照』"},"content":{"type":"html","$t":"\u003cp\u003e自從 2008-02 提出
... });

.

下面列出 jQuery 載入 JavaScript 的語法,
要記得, json-in-script 要當作 JavaScript 來載入

http://docs.jquery.com/Ajax

.

jQuery.getJSON( url, data, callback ) Returns: XMLHttpRequest

Load JSON data using an HTTP GET request.

jQuery.getScript( url, callback ) Returns: XMLHttpRequest

Loads, and executes, a local JavaScript file using an HTTP GET request.

.

下面是測試成功的程式,

function jsOK(a){
$('#msg').append('<p> END callback : ' + a + ' / ' + relatedPostsNum + '</p>');
for (var j=0; j < relatedPostsNum; j++) {
$('#msg').append('<p>' + relatedDates[j] + ' / ' + relatedTitles[j] + ' [' + relatedUrls[j] + '] </p>');
}
}

$(document).ready(function(){
$('body').prepend('<div id="msg"></div>');
$('#msg').append('<p> ready BEGIN </p>');
var feedUrl = "http://eucaly61.blogspot.com/feeds/posts/default/-/VB?alt=json-in-script&callback=RelatedLabels";

$.getScript(feedUrl, jsOK);
$('#msg').append('<p> ready END </p>');
});

其中

  • RelatedLabels 將 JSON 讀到陣列 (請參考上一篇),
    -- 根據實驗結果, 在這個函式中就算使用 jQuery, 也無法改變頁面內容

  • jsOK 則是在 json-in-script 執行成功之後 由 jQuery 呼叫,
    -- 根據實驗結果, 在這個函式中可以成功使用 jQuery 改變頁面內容

由此, 建議 callback 的 RelatedLabels 只要專心處理 json-in-script 的資料即可。至於頁面的資料顯示或其他需要 jQuery 的處理程序, 則留待 jsOK 再來處理

由執行結果得知, json-in-script (含 callback) 和 jsOK 會在背景執行 (非同步)。因為有遠端處理和回傳的延遲, 通常會到最後才出現結果, 而不會 夾在 "ready BEGIN" 和 "ready END" 之間。

ready BEGIN

ready END

END callback : undefined / 3

2008-06-27 / [Excel 巨集] Address 函數 -- 傳回『範圍參照』 [http://eucaly61.blogspot.com/2008/06/excel-vba-address-function.html]

2008-06-04 / 我的 Excel 日記 [http://eucaly61.blogspot.com/2008/06/my-excel-diary.html]

2008-02-20 / [程式設計構想] 使用 EXCEL 巨集合併/比對/更新多種格式的通訊錄 [http://eucaly61.blogspot.com/2008/02/excel-vb-to-managecombine-contact.html]

.

也可以使用比較低階的 $.ajax(), 它有 更多設定, 包括同步 (async: false), 非同步 (async: true) 等 ..., 不過目前試過 同步 (async: false) 並沒有看到預期的結果就是了。

$.ajax({
async: false,
type: "GET",
url: feedUrl,
dataType: "script",
success: jsOK
});

.

再來, 很奇怪的一件事, 如果使用下面這一行, 雖然成功傳值 'A' 給 jsOK, 但 json-in-script 卻沒有正確執行 (項目數為 0)

$.getScript(feedUrl, jsOK('A'));

ready BEGIN

END callback : A / 0

ready END

.

最後, 如果不想使用 jQuery, 那就用老方法, 例如 :

document.write, 但必需在 『網頁載入完畢之前』執行

document.write('<script src="..." type="text/javascript"/>');

或者

var s = document.createElement('script');
s.type = "text/javascript";
s.src = path;
var headobj = document.getElementsByTagName('head')[0];
headobj.appendChild(s);

.

2 意見:

發表您的回應
  1. LVCHEN 提到...

    我用的是最後面的那個方法,可以在回傳json-in-script的時候使用 jQuery。
    $.getScript 的方法我沒好像有試過,不過我記得這個方法在local 可以 work,遠端好像不行耶!
    有試過把檔案放到網路遠端的伺服器上執行看看嗎?

  2. 水瓶尤加利 / Eucaly61 提到...

    @ LVCHEN, 目前實驗結果如下,

    $.getScript 似乎有 proxy 或 firewall 的問題, 以致從本機執行 Firefox 有時候不行, 但 IE7 可以 ..., 就沒再試『把檔案放到網路遠端的伺服器上執行』

    改用你所說的最後一個方法, document.createElement('script'), 這個就可以在遠端執行

    目前的程式在 http://eucaly61-java.googlecode.com/svn/trunk/rps-10-debug.js

    另外還找到 4 種動態載入外部 JS 的方式createElement / XMLHttpRequest 的說明

張貼留言