邊做邊學 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");),若有設定焦點,之後再插入方塊時,會安插在焦點方塊的後方。

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、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) 公開您的想法到 (論壇) 公開您的想法寫悄悄話告訴我們

回到首頁