邊做邊學jQuery系列06 - jQuery網頁元素操控

課程錄製時間: 2009年
jQuery網頁元素操控

【網頁元素操作】

在網頁上動態地增減元素是撰寫AJAX網頁時重要的課題,傳統Javascript常用的做法是透過document.createElement("tagName")的方式建立元素,再一一設定屬性,最後透過appendChild()方法將元素新增在某個父元素之下。如以下的例子:

<body onload="createElem()">
<div id="dvDisp">Welcome to </div>
<script type="text/javascript">
function createElem() {
var a = document.createElement("a");
a.href = "http://msdn.microsoft.com/zh-tw/default.aspx";
a.target = "_blank";
var img = document.createElement("img");
img.src = "http://i3.msdn.microsoft.com/Platform/Controls/Masthead/resources/msdn.logo.jpg";
img.alt = "MSDN Logo";
a.appendChild(img);
document.getElementById("dvDisp").appendChild(a);
}
</script>
</body> 

每個屬性都要分開來指定十分瑣碎煩人,不少過去專攻IE的網頁開發者或許會想到,為何不用outerHTML直接指定HTML標籤? 不是乾淨俐落多了。只可惜並不是每種瀏覽器都支援outerHTML,但好消息是IE領先提出的innerHTML已被主流瀏覽器採納為DOM的標準規格。因此上述例子可以再簡化:

function createElem() {
    var a = document.createElement("a");
    a.href = "http://msdn.microsoft.com/zh-tw/default.aspx";
    a.target = "_blank";
    a.innerHTML = "<img src='http://i3.msdn.microsoft.com/Platform/Controls/Masthead/resources/msdn.logo.jpg' alt='MSDN Logo' />";
    document.getElementById("dvDisp").appendChild(a);
}

當然,使用document.getElementById("dvDisp").innerHTML += "<a href='.... 略 .... </a>"的寫法也是可行,但是若dvDisp的內容複雜時,重設innerHTML會致使dvDisp的所有內容重新產生,效率較差。

補充: http://www.quirksmode.org/dom/w3c_html.html 可以查到各瀏覽器對innerHTML, outerHTML, innerText等屬性的支援現況。

jQuery裡巧妙地利用暫建物件的做法,讓我們可以跨瀏覽器用類似指定outerHTML的方式建立元素,以上的例子可直接寫成:

    $(function() {
        $("#dvDisp").append($("<a href='http://msdn.microsoft.com/zh-tw/default.aspx' target='_blank'>" +
        "<img src='http://i3.msdn.microsoft.com/Platform/Controls/Masthead/resources/msdn.logo.jpg' alt='MSDN Logo' />" +
        "</a>"));
    }); 

除了可以直接指定HTML標籤建立元素,jQuery還提供了許多操弄元素的方便函數:

在以下的說明中,X, Y可為HTML標籤、元素物件或Selector

  • html(), html(val) 讀取或設定innerHTML
  • text(), text(val) 讀取或設定innerText
  • $(X).append( Y ) 在X內新增Y當成最後的子元素
  • $(X).appendTo( Y ) 將X附加到Y內作為最後的子元素
  • $(X).prepend( Y ) 將Y插入X內當作第一個子元素
  • $(X).prependTo( Y ) 將X插入Y內當作第一個子元素
  • $(X).after( Y ) 將Y接在X後方
  • $(X).before( Y ) 在Y插入到X前方
  • $(X).insertAfter( Y ) 將X接在Y的後方
  • $(X).insertBefore( Y ) 將X插入到Y的前方
  • $(X).wrap( Y ) 用Y將X包起來(與wrapAll最大的差別在於wrap時每個X都會被一個Y包住)
  • $(X).wrapAll( Y ) 將所有X元素集中在一起並用一個Y包起來
  • $(X).wrapInner( Y ) 將X的子元素用Y包起來
  • $(X).replaceWith( Y ) 將X置換成Y
  • $(X).replaceAll( Y ) 以X去置換Y
  • $(X).clone() 複製一份X

這裡用一個簡單的範例,展示動態新增元素用jQuery做起來不過是幾行程式的功夫。

我們做一個積木接接樂,上方的<div id="dvPool">裡放入四色方塊(<div class="Square">),下方則是<div id="dvWorkBench">,選取dvPool中的方塊後,我們利用clone()複製<div class="Square">,放入dvWorkBench中。dvWorkBench中的方塊在點選後會取得焦點(addClass("Focus");),若有設定焦點,之後再插入方塊時,會安插在焦點方塊的後方。

Add Element Demo

配合CSS設定,以上的互動操作,扣除註解不到20行程式碼就可以完成。(見程式範例檔: AddElementDone.htm)

    $(function() {
        //Pool中產生四色方塊
        var colors = ["red", "green", "blue", "yellow"];
        //利用$.each跑迴圈, callback中, this就是陣列中的元素
        $.each(colors, function() {
            $("#dvPool")
		.append("<div class='Square' style='background-color:" + this + "'></div>");
        });
        //點選後觸發新增到下方動作
        $("#dvPool .Square").click(function() {
        var newSquare = 
            $(this).clone()
            .click(function() {
                //取消目前的焦點方塊
                $(".Focus").removeClass("Focus");
                //點選者設成焦點方塊
                $(this).addClass("Focus");
            });
            //有焦點物件時,加在其後方
            if ($(".Focus").length > 0)
                $(".Focus").after(newSquare);
            //否則就直接加在最後一個
            else
                $("#dvWorkBench").append(newSquare);
        });
    });

【共用函數補充】

在以上的範例中,我們提到了$.each()這個函數,事實上,jQuery還有不少好用的共用函數,在此一道做個補充:

  • jQuery.browser 用以偵測瀏覽器版本,它是一個物件,會有safari、opera、msie、mozila及version五個屬性,前四個屬性依瀏覽器不同,只有一個屬性會傳回true,其餘都傳回false,而version則會傳回版號。
  • jQuery.support,由於使用jQuery.browser的做法意味著我們要寫死何種瀏覽器支援哪些功能,一旦瀏覽器改版或特性改變時就要修校,因此從jQuery 1.3起,jQuery核心不再用jQuery.browser判斷決定不同的做法,而是一律由jQuery.support.*傳回true/flase判斷瀏覽器的支援度,目前可測試的瀏覽器特性包含了: boxModel、cssFloat、hrefNormalized、htmlSerialize、leadingWhitespace、noCloneEvent、objectAll、opacity、scriptEval、style、tbody。但基於向前相容,jQuery.browser仍會持續存在。
  • jQuery.each(array, function() { ... }) ,將array的各元素逐一送給callback函數處理,函數中以this取得陣列元素內容。
  • jQuery.each(object, function(i, val) { ... }),逐一傳入物件各屬性的名稱(i)以及值(val)給callback函數處理。
    (註: each中return false時,後續尚未處理到的其他陣列元素/物件屬性則略過不處理。)
  • jQuery.extend(obj1, obj2, obj3),將obj2/3的屬性合併到obj1中(若同名屬性存在則覆寫之),很常用於指定參數的預設值,例如:
    var finalSetting = { };
    var defaultSetting = { limit: 256, maxRows: 16, maxCols: 16 };
    var userOption = { maxRows: 10 };
    //第一個參數物件會被修改,為了保持defaultSetting不被更動,放在第二個參數
    $.extend(finalSetting, defaultSetting, userOption);
    $.each(finalSetting, function(i, val) { 
    	alert(i + "->" + val);
    });
    
  • jQuery.grep(array, function(v, i) { ... }); 將陣列元素(v)與其排序(i)傳給callback,return true/false決定該陣列元素留下或捨棄,可以用來過濾陣列。
  • jQuery.map(array, function(v, i) { ... }); 將陣列元素(v)處理過傳回,傳回值若為null則移除該元素,傳回值若為陣列則陣列中的元素都會被新增,最後得到一個處理過的新陣列。
  • jQuery.inArray(val, array); 檢查val有無存在於array中。
  • jQuery.merge(array1, array2); 合併兩個陣列,若要排除重覆元素則可用jQuery.unique(array)事後處理。
  • jQuery.isArray(obj)/jQuery.isFunction(obj) 判別是否為陣列/函數。
  • jQuery.trim(s); 去掉字串頭尾的空白
  • jQuery.param(array/object/jQuery) 將陣列/物件/jQuery物件序列化成一個字串,格式如: width=1680&height=1050。

【範例檔案下載】

歡迎推文分享:



 
RSS
【工商服務】
OrcsWeb: Windows Server Hosting
twMVC

關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。