邊做邊學 jQuery 系列 5 - jQuery 的樣式、屬性、欄位內容存取語法
邊做邊學 jQuery 系列 5 - jQuery 的樣式、屬性、欄位內容存取語法教學影片 > [!VIDEO https://www.microsoft.com/zh-tw/videoplayer/embed/13e3ca44-c89d-4b61-b465-e60ab67b8ebf] |
【選取功能延伸】
除了用 Selector 語法取得符合特定條件的網頁元素外,我們還可以對結果群組做一些後續處理
- eq( N ) 傳回群組中第 N 個 jQuery 物件 (get(N) 傳回的是元素本身)
- hasClass( className ) 檢查是否設定了特定的 CSS 類別,結果傳回 true/false
- filter( expr ) 使用 Selector 語法對群組進行篩選
- filter( fn ) 使用自訂函數對群組進行篩選,自訂函數可以接收 index 參數或由 this 存取元素本身,傳回 true 或 false 決定保留或剔除
- is( expr ) 使用 Selector 語法對群組進行篩選,如果篩選後個數大於零時傳回 true
- map( callback ) 透過自訂函數,對群組中的每個元素進行轉換
- not( expr ) 利用 Selector 語法剔除指定條件的元素
- slice( start, end ) 取出群組中第 start 到第 end 個元素
- add( expr ) 跟另一個 Selector 語法查詢得到的結果群組合併在一起
- children( expr ) 用 Selector 對群組裡各元素的子元素進行篩選
- contents( ) 傳回元素的所有子元素集合 (childNodes),若為 IFrame 則傳回內容網頁 (contentDocument)
- find( expr ) 以 Selector 語法篩選其下的所有元素(不限直接隸屬,子元素下的子元素也包含在內)
- next( expr ) 找出緊臨的下一個同層元素,支援 Selector 語法篩選
- nextAll( expr ) 找出排在該元素後方的所有同層元素,支援 Selector 語法篩選
- offsetParent( ) 元素在座標定位上所屬的容器元素,例如: 元素為 <td> 時傳回 <table>
- parent( expr ) 元素所屬的父元素,可利用 Selector 進行篩選
- parents( expr ) 傳回元素的所有上層元素(包含父元素的父元素,會一層一層往上找),可透過 Selector 語法進行篩選。例如: $("#theInput").parents("tr:first")可找出輸入欄位所在的 <tr>,在寫編輯UI互動時很有用。
- closest( expr ) 1.3 版新增,用 Selector 在父系元素中找出最內層者,等同於上述所說 parents("tr:first") 在做的事。
- prev( expr ) 找出緊臨的上一個同層元素,可傳入 Selector 進行篩選
- prevAll( expr ) 找出排在該元素前方的所有同層元素,支援 Selector 語法篩選
- siblings( expr ) 找出與該元素位屬同層的所有元素(父元素是同一個的兄弟姐妹,但不含自己),支援 Selector 語法篩選
- andSelf( ) 在進行 find 等操作後,再回頭將當初的對象也合併入結果群組中。例如: $("#myDiv").nextAll("div").andSelf()可以得到 #myDiv 後方旳所有同層 <div> 再加上 #myDiv 本身
- end( ) 將操作對象切換回先前的對象。原本的 $("#myDiv").children("p").addClass("clsName1"),此時操作對象已是 #myDiv 下的所有 <p> 了,此時若要再對 #myDiv 下的所有 <span> 做動作,除了另寫一列 $("#myDiv").children("span").addClass("clsName2") 之外,還可透過 end(),再把對象切回到 #myDiv,改寫成一行 $("#myDiv").children("p").addClass("clsName1").end().children("span").addClass("clsName2")
以下來做個簡單的練習,我們先做一個 9x9 的表格,要產生出按下任何一格時,將該格所屬橫列塗成綠色,該格所屬直行塗成紅色,該格塗黑的效果。
$(function() {
$("#matrix td").click(function() {
var td = $(this);
//將所有格子全部塗白
td.parents("table:first").find("td")
.css("background-color", "white");
//用parent()取得 <td> 所屬 <tr>
var tr = td.parent();
//全列塗紅
tr.children().css("background-color", "red");
//以index()找出是第幾欄, 稍後要用於 nth-child
//以 1 起算,故先加 1
var nthChild = tr.children().index(td) + 1;
//將表格所有其他 <tr> 塗綠
tr.siblings().find("td:nth-child(" + nthChild + ")")
.css("background-color", "green");
//本格塗黑
td.css("background-color", "black");
});
});
再來一個例子,假想點選格子時來決定出一塊範圍大小。
$(function() {
$("#matrix td").click(function() {
var td = $(this);
//將所有格子全部塗白
td.parents("table:first").find("td")
.css("background-color", "white");
//用parent()取得 <td> 所屬 <tr>
var tr = td.parent();
//以index()找出是第幾欄, 稍後要用於 nth-child
//以 1 起算,故先加 1
var nthChild = tr.children().index(td) + 1;
//該列及以上只塗右半部
tr.prevAll().andSelf().find("td:nth-child(" + nthChild + ")")
.nextAll().css("background-color", "blue");
//該列以下全塗
tr.nextAll().children().css("background-color", "blue");
});
});
這兩題大家可以先用傳統 Javascript 寫法試做一次,再驗證 jQuery 的程式碼是不是簡短許多。
【樣式與屬性】
檥式 (CSS Style) 與屬性 (Attribute) 的操作很簡單,應用卻很廣泛,在先前的範例中已出現過數次。要指定元素的外觀樣式,可以透過指定或移除樣式類別方式為之,即使用 addClass( className ) 及 removeClass( className),另外 hasClass( className ) 會傳回 Boolean 指出元素是否被指定了特定的樣式類別,toggleClass( className ) 則可用在需要來回切換樣式類別的場合,例如: 第一次呼叫時加上樣式類別、第二次則移除、第三次再加上,以此類推。
另外,我們也可以單獨指定某個樣式屬性,透過 css( key, value ) 的方式進行,css("background-color", "blue") 的語法例子在先前已出現過多次,如果一次要設定多個 CSS 屬性,也可利用之前介紹過的匿名物件技巧,寫成 css({ backgroundColor:"blue", color:"white", cursor:"pointer" })。另外,我們也可以透過函數來決定設定值的寫法,例如以下的例子可以將所有 <div> 的寬度放大兩倍。
$("div").css("width", function() { return $(this).with() * 2; });
以上談的都是設定 CSS,若要取得 CSS 屬性值,只傳入屬性名稱一個參數即可,例如: alert($("#myDiv").css("color"))。
針對元素的位置、寬度、高度,有幾個專屬的函數:
- offset() 傳回一個包含 top, left 值的物件,用以表示元素相對於 document 的座標
- position() 傳回一個包含 top, left 值的物件,用以表示元素相對於其容器元素的座標
- scrollTop() 傳回元素的垂直捲動位移
- scrollTop( val ) 設定元素的垂直捲動位移
- scrollLeft() 傳回元素的水平捲動位移
- scrollLeft( val ) 設定元素的水平捲動位移
- height() 傳回元素的高度
- height( val ) 設定元素的高度
- width() 傳回元素的寬度
- width( val ) 設定元素寬度
- innerHeight() 傳回內部高度(扣除 border 及 padding)
- innerWidth() 傳回內部寬度(扣除 border 及 padding)
- outerHeight( true/false ) 傳回外部高度,預設包含 border 及 padding,傳入參數決定是否包含 margin
- outerWidth( true/false ) 傳回外部寬度,預設包含 border 及 padding,傳入參數決定是否包含 margin
關於 margin, border, padding 的定義,可參考 W3C 的 Box Model 說明,如下圖。(圖片來源: http://www.w3.org/TR/CSS2/box.html)
存取屬性的相關函數語法與 CSS 幾乎完全相同,attr( key, value )可以設定屬性值,attr( key )可以讀取屬性值,removeAttr( key ) 則是移除屬性值,利用匿名物件參數則可以一次設定多個屬性,如果要利用自訂邏輯決定屬性值,一樣可以透過 attr( key, fn ) 的方式達成。
屬性除了用來讀取或設定一些預設如 href, link, src 等元素既有屬性外,還可以自訂屬性名稱,用來保存我們想放在元素上的特殊資訊,當成 Metadata 的儲存處所,例如以下的練習範例。
建立一個 9x9 的格子陣列,以亂數方式選定十個 <td> 放入十顆地雷,利用 <td> 的 onclick 事件,在點擊到埋有地雷的格子時,以橘底顯示所有地雷、紅底顯示引爆點,並彈出 BOOM 爆炸訊息。在 <td> 上,我們自訂一個屬性 mine = "true" 來標示是否埋有地雷。
$(function() {
var tdCol = $("#matrix td");
//以亂數任選 10 個格子以設定 mine attribute 方式埋入地雷
for (var i = 0; i < 10; i++) {
var idx = 0;
//加入 do while 邏輯以避免埋在重覆的格子中
do {
idx = Math.floor(Math.random() * tdCol.length);
} while (tdCol.eq(idx).attr("mine") == "true");
//設定 mine attribute
tdCol.eq(idx).attr("mine", "true");
}
//設定點選事件
$("#matrix td").click(function() {
var td = $(this);
//比對屬性決定是否踩到地雷
if (td.attr("mine") == "true") {
td.closest("table")
//利用 td[mine=true] 選取所有地雷格子塗色
.find("td[mine=true]")
.css("background-color", "orange")
//踩中位置塗紅色
td.css("background-color", "red");
alert("BOOM!");
}
else //未踩中塗灰色
td.css("background-color", "#cccccc");
});
});
【元素內容存取】
取得元素的內容或輸入欄位的數值是開發前端程式時的重要工作之一,jQuery 提供了 html()、text() 可取得 innerHTML 及 innerText 內容,html( val )、text( val ) 則可以設定。值得一提的是,innerText 是只有 IE 提供的 DOM API,在其他瀏覽器中另有存取方法,jQuery 提供了通透性,用 text()/text( val ) 就能在不同瀏覽器實踐了讀/寫 innerText 的效果。
至於 <input> 欄位的數值存取與設定,同理推演就是 val()及val( val ) 了,而在不同的輸入欄位格式上處理方式有些許不同:
- textbox, password, textarea 可以直接使用 val() 及 val( val ) 讀取及設定欄位內容
- select 若為單選,val() 傳回的是字串,而 val( val ) 要傳入的也是字串。當為多選時 (<select multiple="multiple"> 時,則 val() 會傳回字串陣列,由所有選取的選項內容組成,同理此時要設定時也要傳入陣列。
- radio 實務上多半有多個 <input type="radio"> 指定同樣的 name,但指定不同的 value,在使用時選取同一群 radio(可透過 #name) 以 val() 取得被選取 radio 的值。要設定時,則是選取該群 radio,再傳入單一字串的陣列,例如: val([ str ]),就可選取 value 與 str 相同的 radio。
- checkbox 比較特殊一些,它常用於多選選項,所以若要一口氣找出所有被勾選的項目,通常可以善用:checked 這個虛擬類別 (Pseudo Class) 一次將被勾選的 checkbox 找出來,再逐一用 val() 取值。而要設定時則與 radio 相同,先選取所有可能選項的 checkbox,傳入字串陣列,jQuery 會逐一比對,將吻合者勾選起來。
以下是程式範例:
<input type="text" class="inp" /><br />
<textarea class="inp" ></textarea><br />
<select class="inp" id="selSingle">
<option>Opt1</option><option>Opt2</option><option>Opt3</option>
</select><br />
<select multiple="multiple" class="inp" id="selMulti">
<option>Opt1</option><option>Opt2</option><option>Opt3</option>
</select>
<div id="rdo">
<input type="radio" name="r" value="Radio1" />RDO1
<input type="radio" name="r" value="Radio2" />RDO2
</div>
<div id="cbx">
<input type="checkbox" value="Checkbox1" />CBX1
<input type="checkbox" value="Checkbox2" />CBX2
<input type="checkbox" value="Checkbox3" />CBX3
</div>
<input type="button" value="Set Value" onclick="setVal()" />
<input type="button" value="Show Value" onclick="showVal()" />
<script type="text/javascript">
function setVal() {
$("input:text").val("TextBox");
$("textarea").val("TextArea!");
$("#selSingle").val("Opt2");
$("#selMulti").val(["Opt1", "Opt3"]);
$("#rdo input").val(["Radio2"]);
$("#cbx input").val(["Checkbox1", "Checkbox3"]);
}
function showVal() {
$(".inp").each(function() {
var v = $(this).val();
alert(this.tagName + "->" + v);
});
alert("Radio: " + $("#rdo input").val());
$("#cbx input:checkbox:checked").each(function() {
alert("Checkbox: " + $(this).val());
});
}
</script>
【範例檔案下載】