邊做邊學 jQuery 系列 6-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 = "https://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 = "https://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='https://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");),若有設定焦點,之後再插入方塊時,會安插在焦點方塊的後方。
配合 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、mozilla 及 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。
【範例檔案下載】
我們在乎每一位開發人員的感受 : 到 (Twitter) 公開您的想法、到 (論壇) 公開您的想法、寫悄悄話告訴我們
回到首頁