顯示具有 Javascript 標籤的文章。 顯示所有文章
顯示具有 Javascript 標籤的文章。 顯示所有文章

2012年11月13日 星期二

JavaScript - 事件指定function與圓括號(parentheses)的關係

標題其實是想說 elementA.onclick = func; 這樣一回事
之前都已經看慣&習慣這個寫法倒也沒有想太多

直到今天寫了一個要輸入參數的function
function specialSetting(obj){
....   //original code 
}

然後就直覺寫上了 elementA.onclick = specialSetting(elementA);
畢竟一開始學寫JavaScript都是 <div ... onClick="specialSetting(this);" > 這樣開始

然後執行時就發現函式一開始就馬上被呼叫一次...
仔細想想才覺得應該是圓括號的關係
猜測 JavaScript 的執行方式是 elementA.onclick = specialSetting(elementA);
先執行一次呼叫 specialSetting(obj); 之後才綁定事件
function在JavaScript中是物件
elementA.onclick = specialSetting;  表明事件綁了個函式物件,而不是要立刻執行函式

那如果要傳入參數呢? 改用匿名函式就好了
elementA.onclick = functionn(){ specialSetting(elementA); };

回想要傳入事件作參數給函式的作法是
elementA.onclick = functionn(evt){ func(); };
從這裡其實就看得出端倪了

JavaScript 常用事件整理

常見事件整理:

事件                       觸發時機

onabort                 圖片下載被中斷時

onblur                    當游標離開元件時

onchange             當使用者更改欄位內容時

onclick                 滑鼠單擊物件時

ondblclick            滑鼠雙擊物件時

onDragDrop       物件被拉入瀏灠器視窗時

onerror                 載入文件或圖片發生錯誤時

onfocus                當游標定位在元件上時

onkeydown          當鍵盤的按鍵被壓下時

onkeypress         當鍵盤的按鍵被壓下再放開時

onkeyup              當鍵盤的按鍵被放開時

onload                 當網頁或圖片載入完成時

onmousedown     滑鼠按鍵被壓下時

onmousemove     滑鼠指標移動時

onmouseout        滑鼠指標離開物件時

onmouseover      滑鼠指標移到物件上時

onmouseup         滑鼠按鍵被放開時

onreset                當reset按鍵被點擊時

onresize               當視窗或框架被改變大小時

onselect               當文字被選取時

onsubmit              當sumbit按鍵被點擊時

onunload              當使用者離開畫面時

2012年11月10日 星期六

[轉載] require.js的用法

原文


一、為什麼要用require.js?

最早的時候,所有Javascript代碼都寫在一個文件裡面,只要加載這一個文件就夠了
後來,代碼越來越多,一個文件不夠了,必須分成多個文件,依次加載
下面的網頁代碼,相信很多人都見過

      <script src="1.js"></script>
      <script src="2.js"></script>
      <script src="3.js"></script>
      <script src="4.js"></script>
      <script src="5.js"></script>
      <script src="6.js"></script>

這段代碼依次加載多個js文件

這樣的寫法有很大的缺點
首先,加載的時候,瀏覽器會停止網頁渲染
加載文件越多,網頁失去響應的時間就會越長
其次,由於js文件之間存在依賴關係,因此必須嚴格保證加載順序
比如上例的1.js要在2.js的前面
依賴性最大的模塊一定要放到最後加載
當依賴關係很複雜的時候,代碼的編寫和維護都會變得困難

require.js的誕生,就是為瞭解決這兩個問題:
(1)實現js文件的異步加載,避免網頁失去響應;
(2)管理模塊之間的依賴性,便於代碼的編寫和維護。


二、require.js的加載

使用require.js的第一步,是先去官方網站下載最新版本。

下載後,假定把它放在js子目錄下面,就可以加載了。

      <script src="js/require.js"></script>

有人可能會想到,加載這個文件,也可能造成網頁失去響應
解決辦法有兩個,一個是把它放在網頁底部加載,另一個是寫成下面這樣:

      <script src="js/require.js" defer async="true" ></script>

async屬性表明這個文件需要異步加載,避免網頁失去響應
IE不支持這個屬性,只支持defer,所以把defer也寫上

加載require.js以後,下一步就要加載我們自己的代碼了
假定我們自己的代碼文件是main.js,也放在js目錄下面
那麼,只需要寫成下面這樣就行了:

      <script src="js/require.js" data-main="js/main"></script>

data-main屬性的作用是,指定網頁程序的主模塊
在上例中,就是js目錄下面的main.js,這個文件會第一個被require.js加載
由於require.js默認的文件後綴名是js,所以可以把main.js簡寫成main


三、主模塊的寫法

上一節的main.js,我把它稱為"主模塊",意思是整個網頁的入口代碼
它有點像C語言的main()函數,所有代碼都從這兒開始運行

下面就來看,怎麼寫main.js。

如果我們的代碼不依賴任何其他模塊,那麼可以直接寫入javascript代碼。

      // main.js
      alert("加載成功!");

但這樣的話,就沒必要使用require.js了
真正常見的情況是,主模塊依賴於其他模塊
這時就要使用AMD規範定義的的require()函數

      // main.js
      require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
        // some code here
      });

require()函數接受兩個參數
第一個參數是一個數組,表示所依賴的模塊,上例就是['moduleA', 'moduleB', 'moduleC']
即主模塊依賴這三個模塊
第二個參數是一個回調函數,當前面指定的模塊都加載成功後,它將被調用
加載的模塊會以參數形式傳入該函數,從而在回調函數內部就可以使用這些模塊

require()異步加載moduleA,moduleB和moduleC,瀏覽器不會失去響應
它指定的回調函數,只有前面的模塊都加載成功後才會運行,解決了依賴性的問題

下面,我們看一個實際的例子

假定主模塊依賴jquery、underscore和backbone這三個模塊,main.js就可以這樣寫:

      require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone){
        // some code here
      });

require.js會先加載jQuery、underscore和backbone,然後再運行回調函數
主模塊的代碼就寫在回調函數中


四、模塊的加載

上一節最後的示例中,主模塊的依賴模塊是['jquery', 'underscore', 'backbone']
默認情況下,require.js假定這三個模塊與main.js在同一個目錄
文件名分別為jquery.js,underscore.js和backbone.js,然後自動加載

使用require.config()方法,我們可以對模塊的加載行為進行自定義
require.config()就寫在主模塊(main.js)的頭部
參數就是一個對象,這個對象的paths屬性指定各個模塊的加載路徑

      require.config({
        paths: {
          "jquery": "jquery.min.js",
          "underscore": "underscore.min.js",
          "backbone": "backbone.min.js"
        }
      });

上面的代碼給出了三個模塊的文件名,路徑默認與main.js在同一個目錄(js子目錄)
如果這些模塊在其他目錄,比如js/lib目錄,則有兩種寫法。一種是逐一指定路徑

      require.config({
        paths: {
          "jquery": "lib/jquery.min.js",
          "underscore": "lib/underscore.min.js",
          "backbone": "lib/backbone.min.js"
        }
      });

另一種則是直接改變基目錄(baseUrl)。

      require.config({
        baseUrl: "js/lib",
        paths: {
          "jquery": "jquery.min.js",
          "underscore": "underscore.min.js",
          "backbone": "backbone.min.js"
        }
      });

如果某個模塊在另一台主機上,也可以直接指定它的網址,比如:

      require.config({
        paths: {
          "jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"
        }
      });

require.js要求,每個模塊是一個單獨的js文件
這樣的話,如果加載多個模塊,就會發出多次HTTP請求,會影響網頁的加載速度
因此require.js提供了一個優化工具
當模塊部署完畢以後,可以用這個工具將多個模塊合併在一個文件中,減少HTTP請求數


五、AMD模塊的寫法

require.js加載的模塊,採用AMD規範
也就是說,模塊必須按照AMD的規定來寫

具體來說,就是模塊必須採用特定的define()函數來定義
如果一個模塊不依賴其他模塊,那麼可以直接定義在define()函數之中

假定現在有一個math.js文件,它定義了一個math模塊。那麼,math.js就要這樣寫:

      // math.js
      define(function (){
        var add = function (x,y){
          return x+y;
        };
        return {
          add: add
        };
      });

加載方法如下:

      // main.js
      require(['math'], function (math){
        alert(math.add(1,1));
      });

如果這個模塊還依賴其他模塊,那麼define()函數的第一個參數,必須是一個數組
指明該模塊的依賴性

      define(['myLib'], function(myLib){
        function foo(){
          myLib.doSomething();
        }
        return {
          foo : foo
        };
      });

當require()函數加載上面這個模塊的時候,就會先加載myLib.js文件


六、加載非規範的模塊

理論上,require.js加載的模塊,必須是按照AMD規範、用define()函數定義的模塊
實際上雖然已經有一部分流行的函數庫(比如jQuery)符合AMD規範,更多的庫並不符合
那麼,require.js是否能夠加載非規範的模塊呢?

回答是可以的

這樣的模塊在用require()加載之前,要先用require.config()方法,定義它們的一些特徵

舉例來說,underscore和backbone這兩個庫,都沒有採用AMD規範編寫
如果要加載它們的話,必須先定義它們的特徵

      require.config({
        shim: {
          'underscore':{
            exports: '_'
          },
          'backbone': {
            deps: ['underscore', 'jquery'],
            exports: 'Backbone'
          }
        }
      });

require.config()接受一個配置對象,這個對象除了有前面說過的paths屬性之外
還有一個shim屬性,專門用來配置不兼容的模塊
每個模塊要定義
(1)exports值(輸出的變量名)表明這個模塊外部調用時的名稱
(2)deps數組,表明該模塊的依賴性

比如,jQuery的插件可以這樣定義:

      shim: {
        'jquery.scroll': {
          deps: ['jquery'],
          exports: 'jQuery.fn.scroll'
        }
      }


七、require.js插件

require.js還提供一系列插件,實現一些特定的功能

domready插件,可以讓回調函數在頁面DOM結構加載完成後再運行

      require(['domready!'], function (doc){
        // called once the DOM is ready
      });

text和image插件,則是允許require.js加載文本和圖片文件

      define([
        'text!review.txt',
        'image!cat.jpg'
        ],
        function(review,cat){
          console.log(review);
          document.body.appendChild(cat);
        }
      );

類似的插件還有json和mdown,用於加載json文件和markdown文件

2012年10月30日 星期二

範例 - JavaScript 等比例縮小圖片

max-width、max-height以及這兩個的 min 版本是偶爾能在某些CSS中看到的屬性設定
不過因為IE不會辨識這些屬性,所以就直接寫JavaScript 調整圖片大小

var img = this.getElementsByTagName("img")[0];

img.onload = function(){
    var maxWidth = "300", maxHeight = "80";
 
    if(img.offsetHeight >= (maxHeight / maxWidth) * img.offsetWidth){
    img.style.width = img.offsetWidth / img.offsetHeight * maxHeight + "px";
    img.style.height = maxHeight + "px";
    }else{
img.style.height = img.offsetHeight / img.offsetWidth * maxHeight + "px";
img.style.width = maxWidth + "px";
    }
}

轉換AJAX取得的XML結構為DOM操作結構

這次的目的是要用AJAX取得的 responseText ,作為節點底下的結構
取得的 responseText 會是 <div>....</div><div>...</div> 這樣的結構
再以DOM方式去操作

通常查詢到的都是用framework的解決方式
例如JQuery - $("...").html( responseText );
Pototype.js也有update() method可以滿足這類需求

不過...沒看到用native JavaScript的過程
想想也是啦...畢竟這樣應該就是要自己去解析字串了
查到較相近的是XML結構的操作
雖然不符合我的需求,但還是值得記錄起來

xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET","rss.xml",false);
xmlhttp.send();
xmlText = xmlhttp.responseText;

if (window.DOMParser){
 parser = new DOMParser();
 xmlDoc = parser.parseFromString(xmlText,"text/xml");
} else{
 xmlDoc = new ActiveXObject("Microsoft.XMLDOM");  //for IE
 xmlDoc.loadXML(xmlText);
}

如果是直接取得XML的話用以下形式即可

xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET","rss.xml",false);
xmlhttp.send();
xmlDoc = xmlhttp.responseXML;

2012年10月22日 星期一

JavaScript 少用全域變數的理由

在 JavaScript: The Good Parts 書中即有討論到這個議題(心得文連結)
容易造成變數名稱紊亂這點,可以盡量用匿名函式的寫法解決
在匿名函式中使用的變數名稱就不會跟全域變數產生衝突
但除了這個問題外,還有效能的考量
JavaScript搜尋變數的方式是 區域變數 -> 更上層的區域變數 -> .... -> 全域變數
若有常用到的全域變數,把它另存成區域變數對效能有很大的幫助

function displayData(){
  //caching variables
  var _ctrl=ctrl;
  var _nui=nui;
  ....
}

2012年10月15日 星期一

動態加入CSS 與 IE 的 innerHTML 屬性討論

這幾天有遇到一個情況是動態加入CSS時發現在IE會遇到問題
查過後才發現 IE 會限制部分Element的 innerHTML 屬性值的設定
col, colgroup, frameset, html, style, table, tbody, tfoot, thead, title, tr
上述標籤的innerTML attribute 在 IE 中均為唯讀

以下有兩種處理方式可通用在所有瀏覽器中

1.
....
    var se = document.getElementById("ieStyleApplier");
    se.innerHTML = "";
    se.innerHTML = "_<style>" + o.responseText + "</style>";
...

先設定一個空的div element
再再將CSS內容將入到div的範圍內用(本例中的o.responseText 為Ajax取得CSS內容)
注意stye tag 前加入 '_' 作為前綴字元(prefix character)
這是避免IE解析div element時讀到style tag會停止解析的情形
猜測這是IE的安全性考量
加入前綴字元後就沒問題了,也可以對應到其他的browser

2.

  (function(o){
      var newStyle = document.createElement("link");
      newStyle.rel = "stylesheet";
      newStyle.href = o;
      var head = document.getElementsByTagName('head')[0];
      if(head)
          head.appendChild(newStyle);
      else
          document.body.appendChild(newStyle);
  })(url);

用一次性的函式動態加入link element後引入CSS

2012年10月8日 星期一

跨網域資料取得解決方式 - JSONP

參考文章:【原創】說說JSON和JSONP,也許你會豁然開朗,含jQuery用例
                      使用 JSONP 跨站請求

JSON為JavaScript中常用的資料交換格式
簡單、輕型的特性讓他成為Web 開發的首選,這裡就不多提了

而在Web開發的過程中,我們有時會遇到跨網域存取資料的需求
不管是基於分散流量需求,又或者是使用雲端提供業者的服務
使用第三方提供的服務、資源
甚至在同一個專案目錄底下開發的檔案也可能因啟用HTTPS而導致網域的不同

我們有這麼多會碰上跨網域的情況
但Browser 本身的安全機制會禁止我們直接從其他網域取得資料
瀏覽器唯一能從其他網域取得資源的機會就是JavaScript的匯入
也因此衍伸出一個非官方的解決方案,也就是JSONP
JSONP的全名是JSON with Padding
這項技巧本身與JSON沒有實際關係,僅僅是因為JSON是實作上最使用的格式

JSONP簡單的來說即是利用JavaScript的動態載入
將JSON格式的資料讀取進來後,直接在JavaScript做處理
這與 AJAX是不同的技術方式
AJAX的目的是獲取目標頁面的資料,而JSONP則是獲取一段JavaScript程式碼

欲取得資料的頁面寫下類似下面這段程式碼:

    var head = document.getElementsByTagName('head')[0];
    var storeList = null;

//倒入JSON資料到storeList
var JSONDataGetter = function(data){
storeList = JSON.parse(JSON.stringify(data));
};

var src = "firmList.jsp";      //JSON資料提供頁面
var js = document.createElement('script');
sJs.setAttribute('src', src);
    if(head)
        head.appendChild(js);
    else
        document.body.appendChild(js);

上面這段的 JSONDataGetter() 會將傳入的JSON資料轉成JavaScript物件
接著是資料提供者的頁面的程式碼
<%
response.setContentType("text/javascript");  //將頁面的型別設定為JavaScript

....  //JSP code

int counter = 0;
out.print("JSONDataGetter([");
    for(Map.Entry<String, HashMap<String, String>> m : totalMap.entrySet()){
    HashMap<String, String> store = m.getValue();
   
    if(counter == 0){
    out.print(String.format("{ \"storeName\" : \"%s\", \"storeType\" : \"%s\", \"storeLocation\" : \"%s\"}", m.getKey(), store.get("storeType"), store.get("storeLocation")));
    }else{
    out.print(String.format(", { \"storeName\" : \"%s\", \"storeType\" : \"%s\", \"storeLocation\" : \"%s\"}", m.getKey(), store.get("storeType"), store.get("storeLocation")));
    }
    counter++;
    }
    out.print("])");

%>


大部分都是字串拼貼的處理,顯示出來大概就是下面這樣

JSONDataGetter([ //JSON資料])

引入的JavaScript code會回頭呼叫 JSONDataGetter() 處理
實務上也會常看到在引入JavaScript的路徑上加上callback變數回傳
如:var src = "firmList.jsp?callback=XXX";
提供 JSON 資料的頁面再根據參數而輸出不同的字串,以便呼叫不同的處理函式
如此一來就能做到更多元的處理
這就是JSONP了

2012年6月26日 星期二

[轉載]強制使用javascript-檢查該頁面是否啟用javascript

原文====================

現在ajax的技術很流行,也用在很多web 2.0的網站上,但該技術是基於使用者端瀏覽器的javascript,萬一使用者把它關閉怎麼辦?還要為它們另外撰寫ajax或javascript特效的替代程式嗎?我不負責任的回答是:不要!

大部份網頁瀏覽器,預設都是啟用javascript,那誰會停用?
第一個是什麼都不懂,不小心關掉的人;第二個是很懂,非常非常在乎安全,或想亂搞的人。 我會和客戶說,這兩類的人,少之又少,又很難搞定,與其多花時間金錢來照顧它們寫替代程式,不如直接告訴它們請啟用javascript再來瀏覽此頁面。 方法很簡單:
在想強制使用javascript的頁面,<head>和</head>間,插入這段通用的tag

<noscript>
     <META HTTP-EQUIV="Refresh" CONTENT="0;URL=JS_Please.html">
</noscript>


如果有人瀏覽這頁面卻未啟用javascript,就會直接轉到JS_Please.html,接著在JS_Please.html上撰寫請啟用javascript的說明,或教不小心關掉的人要怎麼開啟它

後記:
php有個函式是get_browser,原以為是可以檢查瀏覽器所有的狀態,就很高興的拿來試試…沒想到只能得知瀏覽器是否有支援javascript,卻無法得知是否啟用;真是個讓人白高興一場的函式…
網路上還有很多檢查javascript是否啟用的方法和資訊,但大多複雜難用;用noscript來轉頁,是最簡便的方法。

2010年11月16日 星期二

[轉載] JSON傳送與接收


原文

XML可用來表現階層性資料,然而建立與處理XML DOM較為複雜
在Web應用程式中,許多時候並不需要用到XML的複雜階層性
此時通常會採用JSON作為資料交換格式
而JSON也正成為Web應用程式中交換資料的主要選擇。

JSON全名JavaScript Object Notation,為彷造JavaScript的物件實字(Object literal)格式而來
你可以在 http://www.json.org/ 找到詳細的JSON格式說明
大致而言,與物件實字格式類似,主要注意的是JSON:
作為名稱的部份,必須用"雙引號包括
作為值的部份,若為字串,必須用"雙引號包括
不支援函式表示

舉個例子來說,下面是個物件實字:
var obj = {
    name : 'Justin',
    age : 35,
    childs : [ { name : 'hamimi', age : 3} , { name : 'another', age : 5}]
};

若使用JSON表示,則是如下:
var json = '{"name":"Justin","age":35,"childs":[{"name":"hamimi","age":3}, { "name" : "another", "age" : 5}]}';

若為排版會比較容易觀察:
{
    "name":"Justin",
    "age":35,
    "childs":[
        {
            "name" : "hamimi",
            "age" : 3
        },

       {
            "name" : "another",
            "age" : 5
        }

    ]
}

你可以傳送JSON字串給伺服端,要建立JSON字串很簡單
在Firefox 3.1、Internet Explorer 8以上,支援簡單的JSON處理程式庫
如果要從JavaScript建立JSON字串,只要使用JSON.stringify(),例如:
var obj = {
    name : 'Justin',
    age : 35,
    childs : [ { name : 'hamimi', age : 3}, { "name" : "another", "age" : 5} ]
};
var json = JSON.stringify(obj);

這樣就可以得到方才所示範的JSON字串,如果要用非同步物件傳送JSON
則可以如下:
var request = xhr();     // xhr() 會建立非同步物件
request.onreadystatechange = handleStateChange;  // handleStateChange 參考至函式
request.open('POST', url);
request.setRequestHeader('Content-Type', 'application/json');
request.send(json);

請求標頭'Content-Typ'建議設為'application/json'
當然,伺服端要能夠剖析JSON字串以取出資料,但無需親自撰寫
http://www.json.org/ 網站中提供許多語言實作的JSON剖析器協助剖析JSON取得結果

伺服端可以傳回JSON字串
可以使用eval()將JSON字串計值(evaluate)為JavaScript物件
例如:
var obj = eval(json);

然而eval()也會運算傳入的JavaScript程式碼,因此並不建議直接用eval()
如果只是要計值JSON為JavaScript物件,可以使用JSON.parse()。例如:
var obj = JSON.parse(json);

如果是Firefox 3.1、Internet Explorer 8以外沒有內建JSON支援的瀏覽器
可以在 http://www.json.org/ 下載 json2.js
將之包括在網頁中,即可獲得上述的相關JSON方法:
<script type="text/javascript" src="json2.js">
如果遇到瀏覽器已內建JSON支援,json2.js什麼都不作

2010年11月12日 星期五

[轉載] javascript :onsubmit=return false阻止form表單提交

return false 阻止表單提交不起今天這個問題困擾了我很久,在網上找了很多資料,基本上關於onsubmit=return false有以下幾點要注意的地方:

1. return 的返回值問題,函數中return一旦有返回值,就不在執行下面的語句,直接跳到函數調用 的地方。如下PHP函數代碼,第一個if條件符合則函數值返回布爾型false,可以返回一個函數的值,並且跳出這個函數;只要遇到return語句,程序就在那一行代碼停止執行,執行控制將立刻返回到調用該程序的代碼處。
 function chkinput(form)
 {
   if(form.title.value=="")
    {
      alert("請輸入文章標題!");
   form.title.select();
   return false;              //注意不能寫成 return(false);
    }

   if(form.content.value=="")
    {
      alert("文章正文不能為空@!!");
   form.content.select();
   return false;
    }

    return true;
 }

2.form的onsubmit屬性的觸發問題,onsubmit 事件什麼時候觸發?onsubmit 事件會在表單中的確認按鈕被點擊時發生。不觸發的原因有一般如下:
A. onsubmit屬性的觸發時機是在form用input:submit這樣的button提交時才會觸發,否則不會觸發。如果是用一個普通input:button,則在onclick屬性中指定一個javascript函數,在這個函數裡面再執行form的submit()函數,而不是onsubmit屬性。
B. 先看一段代碼:
<form action="index.jsp" method="post" onsubmit="submitTest();">

<INPUT value="www">

<input type="submit" value="submit">

</form>
<SCRIPT LANGUAGE="JavaScript">

<!--

function submitTest() {

// 一些邏輯判斷return false;

}

//--></SCRIPT>
點擊submit按鈕該表單並未提交。因為有一處應該改為(紅色字體)
<form action="index.jsp" method="post" onsubmit="return submitTest();">
原來onsubmit屬性就像是<form>這個html對象的一個方法名,其值(一字符串)就是其方法體,默認返回true;
和Java一樣,在該方法體中你可以寫任意多個語句,包括內置函數和自定義函數。
在這裡submitTest()雖然返回false,但我們只執行了此函數,沒有對其結果進行任何處理。
onsubmit="return submitTest()利用到了它的返回值,達到了預期效果。
 
3.事件處理函數返回false的問題,在大多數情況下,為事件處理函數返回false,可以防止默認的事件行為.
例如,默認情況下點擊一個<a>元素,頁面會跳轉到該元素href屬性指定的頁.   
Return False 就相當於終止符,Return True 就相當於執行符。  
在js中return false的作用一般是用來取消默認動作的。比如你單擊一個鏈接除了觸發你的  
onclick時間(如果你指定的話)以外還要觸發一個默認事件就是執行頁面的跳轉。所以如果  
你想取消對象的默認動作就可以return false。return false應用比較多的場合有:  

<body>  
1, <a href="a.JSP" mce_href="a.JSP" onclick=test();>超級鏈接 </a>  
2, <input type="button" onclick=test() value="提交">  
3, <form name="form1" onsubmIT="return test();">  
內容  
<input type="submIT" value="提交">  
</form>  
</body>  

    
<input type="submit" onclick="submitAction(); return false;" />  
submitAction 方法裡面有提交表單的動作。如果不加 return false,
在執行完 submitAction 之後,submit 按鈕還會繼續執行它的默認事件,
就會再次提交表單。這可能就是很多錯誤的根源。   
的確,return false的含義不是阻止事件繼續向頂層元素傳播,
而是阻止瀏覽器對事件的默認處理。你可以這樣試驗:
首先將所有的js腳本註釋掉,在IE瀏覽器中嘗試拖動一下圖片,
你會發現鼠標會成為禁止操作的樣式,圖片是被禁止拖動的,
它是瀏覽器針對mousemove事件所提供的默認行為。
return false就是為了去掉這種行為,否則就會出現你描述的中斷事件連續執行。   
另外,和return false等效的語句為:
window.event.returnValue = false,
你可以把return false替換為此語句並進行驗證。   
最後說明一下,此種方式只適用於IE瀏覽器。
在js中return false的作用一般是用來取消默認動作的。比如你單擊一個鏈接除了觸發你的 
onclick時間(如果你指定的話)以外還要觸發一個默認事件就是執行頁面的跳轉。所以如果
你想取消對象的默認動作就可以return false。return false應用比較多的場合有:
<form name="form1"  onsubmit="return youfunction();">...... </form>
<a href="www.***.com" onclick="...;return false;">dddd </a>

2010年10月21日 星期四

Ajax 入門簡介

網頁程式碼常被劃分為  - HTML程式碼、儲存資料的XML、處理資料的JavaScript
動態資料儲存在XML,可以達成在不動到HTML碼的前提下修改網頁內容
這樣的快速資料更新與動態呈現的技術就是Ajax
用戶端開始Ajax請求,並等待伺服器的回應
伺服器收到請求後回傳資料,並由JavaScript居中媒介及整合資料到網頁裡

在這段過程中
使用者依然可以持續享受原本的服務,並等待在背景執行的Ajax請求執行結束
這也就是Ajax名稱的由來(Asynchronous JavaScript + XML)

JavaScript內建一個XMLHttpRequest物件
用於初始Ajax請求,並處理Ajax回應
它有比較複雜的類別成員及方法:
abort() -
取消Ajax請求

open() -
準備請求,指定請求的型態、URL與其他細節

send() -
傳送請求給伺服器

readyState -
請求的狀態碼代號;0表示未初始,1是開啟,2是已傳送,3是接收中,4是已載入

status -
HTTP的請求狀態代碼(ex:404錯誤,200表示正常)

onreadystatechange -
請求狀態改變時會被呼叫的函式參考
                              
responseText -
伺服器回傳的純文字字串資料

responseXML -
伺服器回傳的的XML資料


因為不同的瀏覽器(其實是IE問題比較大...)有不同的 XMLHttpRequest 物件建立方式
建立時必須先寫如下的程式碼:
var request = null;
if(window.XMLHttpRequest){
    try{
      request = new XMLHttpRequest();   
    }catch(e){
      request = null;
    }
}
//for IE version
else if(window.ActiveXObject){
    try{
      request = new ActiveXObject("Msxm12.XMLHTTP");   
    }catch(e){
      try{
        //for older versions of IE 
        request = new ActiveXObject("Microsoft.XMLHTTP");         
      }catch(e){
        request = null;     
      }
    }
}

部分版本的 Mozilla 瀏覽器,在伺服器送回的資料未含 XML mime-type header 時會出錯
解決方法是,用下列方法覆寫伺服器傳回的檔頭,以免傳回的不是 text/xml:
request = new XMLHttpRequest();
request.overrideMimeType('text/xml');

建立Ajax請求物件後,接著要設定伺服器傳回資料後的處理方式,之後再開啟請求
API 如下:
request.onreadystatechange = handler;       //handler是處理傳回值的 JavaScript 函式名稱
request.open(type, url, true);                          //true set for being always asynchronous

onreadystatechange 直接指向 handler() 的位置
這裡用匿名函式來處理也是可以的
request.onreadystatechange = function(){
    //code
}

open() 的第一個參數是 HTTP request 的方法
也就是從 GET、POST、HEAD 等伺服器支援的方法中擇一使用
為遵循 HTTP 標準,請記得這些方法都是大寫
否則有的瀏覽器不會處理這些請求
第二個參數是請求頁面的 URL
基於安全考量,呼叫同網域以外的網頁是被禁止的
如果網域不同,則叫用 open() 時會出現「權限不足,拒絕存取」那類的錯誤
常見的錯誤多為在 domain.tld 的網站下呼叫 www.domain.tld 中的網頁
僅是一點點差別都不行
第三個參數決定此 request 是否不同步進行
如果設定為 TRUE 則即使伺服器尚未傳回資料也會繼續執行其餘的程式

type一般選擇填入 "GET" 或 "POST"
GET 適用於不會改變伺服器任何設定的資料傳輸
有需要的話還能透過 url 傳小量資料到伺服器
範例:
request.open("GET", "Data.xml", true);
request.send(null);                                         //請求傳送時沒有資料,所以設定成null  

POST 適用於會變更伺服器設定的資料傳輸
範例:
request.open("POST", "addData.php", true);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;
                                                 charset=UTF-8"); 
request.send("date=10/10/18&demo_string=Hello World!");     //資料附在send()的參數裡傳送

send() 的參數在以 POST 發出 request 時,可以是任何想傳給伺服器的東西
不過以 POST 方式傳送資料前,必須先設定好 MIME type 才能讓伺服器理解資料的處理方式
application/x-www-form-urlencoded; charset=UTF-8 表示資料的型別是 URL-encoding
而資料則以查詢字串的方式列出


Mozilla教學的範例:
test.xml===========

<?xml version="1.0" ?>
<root>
I'm a test.
</root>

test.html===========

<script type="text/javascript" language="javascript">
function makeRequest(url) {
    var httpRequest;

    if (window.XMLHttpRequest) { // Mozilla, Safari, ...
        httpRequest = new XMLHttpRequest();
        if (httpRequest.overrideMimeType) {
            httpRequest.overrideMimeType('text/xml');
        }
    }
    else if (window.ActiveXObject) { // IE
        try {
            httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch (e) {
            try {
                httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch (e) {}
        }
    }

    if (!httpRequest) {
        alert('Giving up :( Cannot create an XMLHTTP instance');
        return false;
    }
    httpRequest.onreadystatechange = function() { alertContents(httpRequest); };
    httpRequest.open('GET', url, true);
    httpRequest.send('');

}

function alertContents(httpRequest) {

    if (httpRequest.readyState == 4) {         
        if (httpRequest.status == 200) {                //表示已傳輸完成且正常
            var xmldoc = httpRequest.responseXML;
            var root_node = xmldoc.getElementsByTagName('root').item(0);
            alert(root_node.firstChild.data);
        } else {
            alert('There was a problem with the request.');
        }
    }

}
</script>

<span
style="cursor: pointer; text-decoration: underline"
onclick="makeRequest('test.xml')">
    Make a request
</span>

2010年10月17日 星期日

JavaScript 筆記(3)

這篇筆記紀錄:
1.JavaScript的物件導向寫法與型別判斷
2.陣列的排序法
3.以for迴圈及foreach迴圈取出物件的差別
4.String物件的常用方法
5.Math 物件的常用方法
6.addEventListener 與 attachEvent 函式說明

1.JavaScript的物件導向寫法與型別判斷

   JavaScript本身就是個以物件為主體的script語言
   連函式本身也是物件,或者說JavaScript的function類似其他語言的class

   除了數值、字串、boolean、null、undefined,其他的所有值都是物件

   typeof運算子在判斷特性的型別有很大的幫助
   typeof obj.num         // 'number'
   typeof obj.arrival      // 'object'

   // 要小心有可能是涵式的值,因為原型鍊上的特性都可以產生值
   typeof obj.toString            // 'function'
   typeof obj.constructor      // 'function'

   hasOwnProperty() 在物件有指定屬性時回傳true,這個方法不會檢索原型鍊
   可以用來避免上述風險
   obj.hasOwnProperty('number')        //true
   obj.hasOwnProperty('constructor')  //false

   當需要自訂物件時,必須寫好物件的建構式,並使用new關鍵字來產生物件
   而JavaScript的類別成員不需要先宣告也不用處理型別,直接用this關鍵字來取得值
   範例:
    function ObjDemo(param1, param2){      //建構式必須首字大寫
        this.param1 = param1;
        this.param2 = param2;

        this.output = function(){
          return param1 + " " + param2;
        }
        ObjDemo.prototype.output2 = function(){
          return "This is a test ";

        }
    }

    var test = new ObjDemo("word1", "word2");
    test.output();
    test.output2();

    範例的程式碼可看出有兩種類別方法的寫法
    第一種用 this 關鍵字的方法會將方法指派給單一實例
    每建立一個物件時,物件內都會有方法的複本,處理方式像類別成員
    建立多個物件就會產生等同物件數量的方法複本
    第二種寫法使用了物件裡以特性的形式存在的prototype物件
    如此可建立類別所擁有的方法,所有建立的物件都會使用同一個方法    
    這樣可以改進資源的使用效率

    JavaScript實際上並不完全支援類別,但用prototype物件來模擬類別
    利用它也可以做到將類別成員給予物件類別共用
    ObjDemo.prototype.param3 = "This effect is like static member of other languages";


2.陣列的排序法

   範例:
    var tarray = [11, 35, 12, 9, 29];
    tarray.sort();

    sort() 方法預設依照升冪順序排列
   如果希望的排列規則不同,或是陣列裡存放的物件不是基本型別的話(也就是自訂物件)
   則依下列範例的形式修改:
    function compare(x, y){      //傳入物件x、y
      return x.value - y.value;     //回傳值<0,x排在y前;相同時則不排列;>0,y排在x前
    }
    tarray.sort(compare);

   又因為通常排序的函式只會用於sort() method
   所以寫成 tarray.sort( function(x, y){return x.value - y.value;} );  也行
   這樣也不需要為函式命名

3.以for迴圈及foreach迴圈取出物件的差別

   for ... in ... 敘述為JavaScript中for each的語法,但是為隨意排序取出資料;
   若想確保資料有一致的順序還是要乖乖用for迴圈

4.String物件的常用方法

    indexOf() 尋找字串是否包含特定子字串,找不到特定子字串則回傳 -1   
    charAt() 尋找特定字元在字串裡的位置
    toLowerCase()、toUpperCase()則是轉換字串大小寫的方法
    length 成員變數則提供字串裡的字元數量的訊息

    字串雖然看起來很像陣列物件,但沒辦法用 [index] 的形式去讀取它

5.Math 物件的常用方法

    Math 物件提供了常用的數學方法
    random() 產生介於0和1之間的亂數
    round() 將浮點數四捨五入為整數
    floor() 將浮點數無條件捨去為整數
    ceil() 將浮點數無條件進位為整數
    abs() 回傳絕對值
    PI 是Math物件提供的常數,值為3.14

6.addEventListener 與 attachEvent 函式說明

   addEventListener 是DOM的標準功能之一,能為某一事件附加其它的處理事件
   一般常見到的指定事件的處理函式的寫法如:
   window.onload = method1;       //指定處理的函式是method1()

   或是用匿名函式來處理:
   window.onload = function(){ method1(); }

   第一種方法的缺點在於一個事件只能定義一種處理,如:

   document.getElementById("btn").onclick = method1;
   document.getElementById("btn").onclick = method2;
   document.getElementById("btn").onclick = method3;    //只有最後定義的method3()會被執行

   addEventListener 是為了解決這個問題存在的
   函式為 addEventListener(event,function,capture/bubble)
   第一個參數是參數接收事件名稱(名稱不含on,如:"load" or "click")
   第二個參數是要執行的函式
   第三個參數設定 capture 或 bubble 的事件讀取方式,以bool值表示
   簡單來說 capture 從讀取完document後再執行事件
   而bubble則是先尋找指定的網頁元件位置再執行事件
   true 表示選擇 capture,false 指定用 bubble,一般指定 false 即可

   IE不支援 addEventListener,要改用 attachEvent 這個IE特有的函式
   傳入的參數大致上相同,只是第一個參數要改成完整事件名稱(如:"onclick")
   而因為IE的事件的傳遞讀取方式預設用 bubble,所以第三個參數可以省略不輸入

   完整範例:
    var bt = document.getElementById("bt");

    if(window.addEventListener){
       bt.addEventListener("click",method1,false);
       bt.addEventListener("click",method2,false);
       bt.addEventListener("click",method3,false);
    }else if(window.attachEvent){
       bt.attachEvent("onclick",method1);
       bt.attachEvent("onclick",method2);
       bt.attachEvent("onclick",method3);
   }

   執行順序為method1->method2->method3

JavaScript DOM模型操作

Document Object Model(DOM) 能將HTML視為XML處理
對於JavaScript來說,可以藉此做到動態處理
DOM將網頁視為節點構成的階層樹,如下圖所示:

階層樹的頂點是Document,並往下聯繫到各個網頁元件形成的節點
HTML元件節點也被稱為元件節點(Element node)
網頁元件的文字內容則儲存在元件下的文字節點(Text node)
Attribute是元件的屬性,可以透過Element node取得,但不會直接出現在階層樹裡

document 提供了 getElementById()、getElementsByTagName()方法來導引到其它子節點

getElementById() 可以從整份DOCUMENT中取得有指定id的元素
getElementsByName() 與 getElementsByTagName() 也是有著類似作法的函式

不過因為後兩個函式取得的元件有可能為複數,所以需要用陣列存取
如:getElementsByTagName("div")[0]  取得第一個div元素

getElementById()一般是最常用到的函式
id在每個DOCUMENT中只能是獨特的,name卻有可能是重複的
此外, getElementsByName()在非IE的瀏覽器可能行不通


在各個節點可以取得我們需要的特性:
nodeName - 回傳節點的標籤名稱,如<div>會回傳 DIV
nodeValue - 儲存於節點的值,只限文字與屬性節點使用
nodeType - 回傳節點型態
                   element node回傳1,attribute node回傳2
                   text node回傳3,包括換行符號等
childNodes - 包含節點下所有子節點的陣列,以出現在HTML碼裡的順序排列
childElementCount - 回傳 element 子代 (child) 元素的數量
parentNode - 回傳其父節點
firstChild - 節點下的第一個子節點
lastChild - 節點下的最後一個子節點
nextSibling - 下一個節點(節點範圍不限同一層)
previousSibling - 上一個節點(節點範圍不限同一層)

較特殊的:
document.baseURI - 取得目前文件的路徑(即目前網址)
style - 設定或取得某個節點的屬性,類似CSS設定,如:node.style.width='100px';
className - 設定或取得節點的class屬性


另外說明.children屬性
這個也是相當常被看到的屬性,使用的方式也很類似childNodes
差別在於
1.childNodes是W3C標準,children則不是(但基本上browser都會實作這個屬性)
2.childNodes會回傳 NodeList,children則是HTMLCollection
3.children回傳的內容不包括 text node等,僅回傳 element node
   所以如有下列的情形
   <div>
         <a></a>
   </div>

   像這樣節點間存在換行符號、空白
   用 childNodes.firstChild 便有可能取不到我們真正想要的 node(視 browser 實作情形)

可以在節點上使用的方法則有
appendChild() - 加入子節點
cloneNode() -  參數設定為 true 可複製該元素的所有子代 (child)
                        設定為 false 則通常只會複製一個文字節點
    範例:
    var demo = document.getElementById("demo");
    var demo2 = demo.cloneNode(true);
    document.body.appendChild(demo2);

hasChildNodes() - 回傳boolean值,判斷有無子節點
hasAttributes() - 回傳是否有無屬性值
insertBefore() - 使用方式:parentNode.insertBefore(newElement, referenceElement)
removeChild() - 刪除子節點,使用方式:parentNode.removeChild(node)
replaceChild() - 使用方式:node.replaceChild(newChild, oldChild);
getAttribute() - 取得節點的某項屬性,如:node.getAttribute("nowrap")
setAttribute() - 設定節點的某項屬性,如:node.getAttribute("height", "100px")
removeAttribute() - 刪除節點的某項屬性,如:node.getAttribute("nowrap")


使用範例:document.getElementsByTagName("div")[0].childNodes[1].nodeValue = 1;
當然範例要先確定childNode[1]底下只有一個節點,否則會得不要想要的效果
如果不確定所要更改的節點內容是否有多個子節點
那麼更改的時候就要先清除所有的子節點後,再新增有新內容的新子節點,如:
var node = document.getElementById("target");
//有子節點的話,firstChild回傳true
while(node.firstChild){ node.removeChild(node.firstChild); }
node.appendChild(document.createTextNode("alter OK"));

當然先寫好一個替換節點文字內容的函式,通常是個方便的選擇,如:
function replaceNodeText(id, newText){
   var node = document.getElementById(id);
   while(node.firstChild){ node.removeChild(node.firstChild); } 
   node.appendChild(document.createTextNode(newText));
}

DOM提供了透過節點調整CSS的機制
透過節點物件的className特性可以操作網頁元件的類別(class)特性
如:document.getElementById("target").className = "deco2";
節點的style特性提供對單一樣式性質的存取
如:document.getElementById("target").style.visibility = "hidden";

前面看到過的createTextNode()只能建立純粹的文字內容
接著要提的createElement() 可以用來建立任何的HTML元件
建立段落文字的範例:
var newElem = document.createElement("p");
newElem.appendChild(document.createTextNode("Hello World"));
document.getElementById("target").appendChild(newElem); 

加入的段落文字會以符合標準的形式呈現 -> <p>Hello World</p>

2010年10月16日 星期六

JavaScript 筆記(2)

這篇筆記紀錄:
1.Timer用法
2.使用JavaScript作網頁元件CSS調整修改
3.取得外部CSS資訊的方法
4.Cookie範例
5.分離JavaScript與HTML程式碼
6.快速取得物件的小技巧
7.離開頁面的確認視窗寫法

1.Timer用法

計時器只能做到延遲時間,並非是依照真實時間來觸發
單次計時器的書寫方式:setTimeout("String型別的JavaScript Code", 6000);
單次計時器示範: setTimeout("document.getElementById('a').src='b.jpg';", 5*1000);

間歇計時器則使用 setIntervel()函式,引入的參數則與單次計時器相同
間歇計時器示範:var timerID = setIntervel(...);
儲存ID的資訊的作用是要使用下一個介紹的函式 clearInterval()
clearInterval(timerID)能清除間歇計時器,停止它的作用

location物件的reload() 可以重新讀取頁面,使用範例:location.reload();
結合timer可以做到定時重讀頁面等效果

2.使用JavaScript作網頁元件CSS調整修改

JavaScript能以document物件取得用戶端的視窗寬度,並進而調整顯示物件的大小
用戶端視窗是指瀏覽器視窗裡呈現網頁的部分,並不包含瀏覽器工具列等的部分
用戶端視窗高度= document.body.clientHeight  用戶端視窗寬度=  document.body.clientWidth
其他常用的查詢需要去查API

取得圖片等元件的高度及寬度的取法如: var width = document.getElementById('a').width;
而網頁裡的所有元件都有一個style物件,能借助它達到調整CSS的顯示效果
如: document.getElementById('a').style.left = "300px";
注意一點,由 style 取得的資料有些是帶有px之類單位的字串
處理方式如:var picPos =  eval(document.getElementById('a').style.left.replace("px", ""));
這樣一來會先以replace()把 px 移除,將著用eval()函式將之轉換成數值

3.取得外部CSS資訊的方法

在IE中要取得外部CSS的資訊必須使用特有的 currentStyle
其他瀏覽器則必須使用 defaultView 物件的 getComputedStyle()
範例如下:
var item = document.getElementById('a');
var iStyle = item.currentStyle || document.defaultView.getComputedStyle(item, null);
document.write("字體大小=" + iStyle.fontSize);


4.Cookie範例

w3cschool的Cookie的示範程式碼
function getCookie(c_name)
{
if (document.cookie.length>0)
  {
  c_start = document.cookie.indexOf(c_name + "=");
  if ( c_start != -1 )
    {
    c_start = c_start + c_name.length+1;
    c_end = document.cookie.indexOf(";", c_start);
    if (c_end == -1) c_end = document.cookie.length;
    return unescape(document.cookie.substring(c_start, c_end));
    }
  }
return "";
}

function setCookie(c_name, value, expiredays)
{
var exdate = new Date();
exdate.setDate(exdate.getDate() + expiredays);
document.cookie=c_name + "=" + escape(value) +
((expiredays == null) ? "" : "; expires = " + exdate.toUTCString() );
}

function checkCookie()
{
username = getCookie('username');
if (username != null && username != "")
  {
  alert('Welcome again ' + username + '!');
  }
else
  {
  username = prompt('Please enter your name:',"");
  if (username != null && username != "")
    {
    setCookie('username', username, 365);
    }
  }
}

清除cookie的方法是將他的值改成空值,並將有效日期改成-1

5.分離JavaScript與HTML程式碼

透過HTML屬性聯繫事件處理函式(如:<button... onclick="script();" />)的寫法有缺點
HTML與JavaScript的混雜不利於維護
在JavaScript碼中指定函式的參考就可以避免動到HTML碼
如:window.onload = init;
上式效果等同於<body onload="init();">
onload是window物件的屬性,並被指派了 init() 函式的參考

如果需要將參數傳入函式中,則如下面範例改寫:
document.getElementById("test").onclick = function(evt){
     testFunc("hi");
}

外層的 function literal包裹住對 testFunc() 的呼叫,並允許將參數傳入函式中
function literal 本身則傳入了事件物件做參數,若需要事件的資料可以靠它取得
假如不需要事件物件的話,參數evt會被忽略
function literal 會以函式參考被指派到onclick事件

假使JavaScript碼會取用網頁元件,必須注意在網頁的onload事件接收完資料後才能指定元件
window.onload 能在這種情況下完成要求,事件處理器在這裡接上應用程式:
window.onload = function(){
    document.getElementById("test").onclick = function(evt){ testFunc("hi"); }
    .....  //程式碼配置
};

順便一提的是如果網頁文件載入的時間比較長
在完成之前可能會讓使用者看到未經處理的內容
要避免這種情形可以先將處理前的內容隱藏起來,處理完畢後再顯示出來

另外,因DOM的載入速度一般來說會比較慢
window.onload這樣綁定DOM物件的程式碼放在<head>裡可能不會有作用
這類型建議放在body標籤後才可能會有效

6.快速取得物件的小技巧

經常使用的 document.getElementById() method 可以寫成快捷函式來方便使用:
function $(id){
    return document.getElementById(id);
}

7.離開頁面的確認視窗寫法

//using JQuery
$(window).bind("beforeunload",function(){
     return ("您確定離開?");
});

2010年10月11日 星期一

JavaScript 筆記(1)

JavaScript 藉由事件來觸發執行的客戶端指令稿
因為JavaScript已經被瀏覽器內建接納,所以可以看到HTML元素裡有不少JavaScript事件

1.每句JavaScript碼的結束都必須添加分號 ;

2.alert 會跳出對話方塊,confirm() 函式會跳出確認視窗
   prompt() 則是跳出請求輸入的視窗,型式是 var x = prompt("提示", "預設值");

3.onload 事件用在<body>標籤上會在網頁剛被載入完時執行,ex:<body onload="alert('Hi');"

4.自訂函式寫法: function xxx(){}
    如果需要函式回傳物件,在結尾加上程式碼:   return  要回傳的物件; 

5.所有的指令稿通常是將資料儲存於記憶體中
    JavaScript的資料型別有三種:Text、Number、Boolean
    Number實際表現為64bit的浮點數,等同Java的double型別
    寫javascript要注意變數或常數的設定,常數的值永不改變
    變數剛被建立的時候是沒有值的
    當我們賦予值給變數時,值會自動將資料型別指派給變數
    const幫助建立不會改變的常數值,另外建立常數時務必要初始化

6.JavaScript的命名方式大致與Java相同

7.parseInt() 與 parseFloat() 函式將文字轉換成數字,因為資料表單總是將欄位的值儲存為字串

8.Number 有個函式 toFixed(int i) 會將數值四捨五入到 i 指定的小數點位置

9.JavaScript中出現NaN表示某個預期應該是數值的資料,其值卻不是數值
   NaN不等於任何值,包刮NaN;isNaN() 函式用來判斷是否為空白或不為數值

10.Infinity值代表大於1.7976313486231570e+308的所有值

11.注意,網頁在onload事件後才載入
      如果JavaScript碼會取用網頁內的元件,那這段程式碼沒辦法在onload事件前執行

12.在自訂函式裡面傳入form 物件是處理表單的常見手法,如:function xx(form){...}
      傳入的form物件是陣列型式,能用欄位名稱作為key去讀取欄位的值
      而 form.submit() 函式會送出整個表單

13.建立陣列的方式是讓JavaScript建立陣列物件,如: var a = new Array();
      建立並初始化陣列內容:var a = ["0","1","2"];
      JavaScript陣列於單一場所儲存多段資料,資料型別可以是不同的(但不建議)
      新增元素到初始化完畢的Array在JavaScript是被允許的
      或者也可以呼叫Array物件的push() 方法新增
      取得陣列總元素的數量則是呼叫Array物件的length成員,如:a.length
      清除陣列內容的方式很簡單,a.length = 0;  像這樣把長度設為0就可以了