jQuery 屬性操作

jQuery 提供了多種方法來操作 HTML 元素的屬性,包括 HTML 屬性、DOM 屬性、表單值以及自訂資料。

HTML 屬性 vs DOM 屬性

在深入之前,需要先了解 HTML 屬性(attribute)和 DOM 屬性(property)的差異:

  • HTML 屬性:定義在 HTML 標籤上的屬性,如 <input type="text" value="hello">
  • DOM 屬性:JavaScript DOM 物件的屬性,反映元素的當前狀態

對於大多數屬性,兩者的值是相同的。但對於某些屬性(如 checkedselecteddisabled),兩者可能不同:

<input type="checkbox" checked />
// HTML 屬性 - 返回屬性的原始值
$('input').attr('checked'); // "checked"

// DOM 屬性 - 返回當前狀態
$('input').prop('checked'); // true 或 false

attr() - HTML 屬性

取得屬性值

// 取得 href 屬性
var url = $('a').attr('href');

// 取得 src 屬性
var src = $('img').attr('src');

// 取得自訂屬性
var id = $('#item').attr('data-id');

設定屬性值

// 設定單一屬性
$('a').attr('href', 'https://example.com');
$('img').attr('alt', '圖片說明');

// 設定多個屬性
$('a').attr({
  href: 'https://example.com',
  title: '前往範例網站',
  target: '_blank',
});

// 使用函式設定
$('a').attr('href', function (index, oldValue) {
  return oldValue + '?ref=site';
});

使用場景

attr() 適合用於:

  • 取得/設定 href、src、title、alt 等屬性
  • 取得/設定 data-* 自訂屬性
  • 取得/設定 ARIA 屬性

removeAttr() - 移除屬性

// 移除單一屬性
$('a').removeAttr('target');

// 移除多個屬性(空格分隔)
$('input').removeAttr('disabled readonly');

prop() - DOM 屬性

取得屬性值

// 取得 checkbox 是否被勾選
var isChecked = $('input[type="checkbox"]').prop('checked');

// 取得 input 是否被停用
var isDisabled = $('input').prop('disabled');

// 取得 select option 是否被選取
var isSelected = $('option').prop('selected');

設定屬性值

// 勾選 checkbox
$('input[type="checkbox"]').prop('checked', true);

// 停用 input
$('input').prop('disabled', true);

// 設定多個屬性
$('input').prop({
  disabled: true,
  readonly: true,
});

// 使用函式設定
$('input[type="checkbox"]').prop('checked', function (index, oldValue) {
  return !oldValue; // 切換勾選狀態
});

使用場景

prop() 適合用於:

  • checked(checkbox、radio 的勾選狀態)
  • selected(option 的選取狀態)
  • disabled(表單元素的停用狀態)
  • readonly(表單元素的唯讀狀態)
  • selectedIndex(select 的選取索引)
  • tagName、nodeName(元素標籤名)

attr() vs prop() 比較

情境使用方法說明
href、src、titleattr()HTML 屬性
checked、disabled、selectedprop()反映當前狀態
data-* 屬性attr()data()自訂資料
classattr()addClass()建議用專門方法
styleattr()css()建議用 css()
value(取得當前值)val()表單值

實際差異示範

<input type="checkbox" checked />
// 初始狀態
$('input').attr('checked'); // "checked"
$('input').prop('checked'); // true

// 使用者取消勾選後
$('input').attr('checked'); // "checked"(HTML 屬性不變)
$('input').prop('checked'); // false(反映當前狀態)
最佳實踐:操作布林屬性(checked、disabled、selected 等)時,應使用 prop(),因為它能正確反映元素的當前狀態。

removeProp() - 移除 DOM 屬性

移除使用 prop() 設定的屬性:

$('input').removeProp('disabled');
注意removeProp() 不應用於移除原生的 DOM 屬性(如 checked、disabled),這樣做可能導致無法再次設定這些屬性。應改用 prop('disabled', false) 來停用屬性效果。

val() - 表單值

val() 方法用於取得或設定表單元素的值。

取得值

// 取得 input 值
var username = $('#username').val();

// 取得 textarea 值
var message = $('#message').val();

// 取得 select 的選取值
var country = $('#country').val();

// 取得多選 select 的所有選取值(返回陣列)
var languages = $('#languages').val();
// ['javascript', 'python', 'php']

// 取得 radio 的選取值
var gender = $('input[name="gender"]:checked').val();

// 取得 checkbox 的值(需先確認是否勾選)
var agree = $('#agree').prop('checked') ? $('#agree').val() : '';

// 取得所有已勾選 checkbox 的值
var hobbies = $('input[name="hobby"]:checked')
  .map(function () {
    return $(this).val();
  })
  .get();

設定值

// 設定 input 值
$('#username').val('John');

// 設定 textarea 值
$('#message').val('Hello World');

// 設定 select 的選取值
$('#country').val('tw');

// 設定多選 select 的選取值
$('#languages').val(['javascript', 'python']);

// 設定 radio 的選取值
$('input[name="gender"]').val(['male']);

// 設定多個 checkbox 的勾選(使用陣列)
$('input[name="hobby"]').val(['reading', 'sports']);

// 使用函式設定
$('input').val(function (index, oldValue) {
  return oldValue.toUpperCase();
});

data() - 自訂資料

jQuery 提供 data() 方法來儲存與元素相關的任意資料。

HTML5 data-* 屬性

<div id="user" data-id="123" data-user-name="John" data-active="true"></div>
// 讀取 data-* 屬性
$('#user').data('id'); // 123(自動轉為數字)
$('#user').data('userName'); // "John"(camelCase 轉換)
$('#user').data('active'); // true(自動轉為布林值)

// 讀取所有 data-* 屬性
$('#user').data();
// {id: 123, userName: "John", active: true}
data() 會自動將屬性名稱從 kebab-case(data-user-name)轉換為 camelCase(userName)。

儲存資料

// 儲存簡單值
$('#item').data('price', 99);
$('#item').data('inStock', true);

// 儲存物件
$('#item').data('info', {
  name: 'Product',
  category: 'Electronics',
});

// 儲存陣列
$('#item').data('tags', ['sale', 'popular']);

// 讀取儲存的資料
var price = $('#item').data('price'); // 99
var info = $('#item').data('info'); // {name: 'Product', ...}
var name = $('#item').data('info').name; // 'Product'

data() vs attr('data-*')

// 使用 data() 設定的資料不會反映到 HTML 屬性
$('#item').data('key', 'value');
$('#item').attr('data-key'); // undefined(除非原本就有)

// 使用 attr() 設定會更新 HTML 屬性
$('#item').attr('data-key', 'value');
$('#item').data('key'); // 'value'
方法讀取來源寫入位置資料類型轉換
data()HTML data-* 屬性 + jQuery 內部快取jQuery 內部快取自動
attr('data-*')HTML data-* 屬性HTML data-* 屬性無(總是字串)

removeData() - 移除資料

// 移除特定資料
$('#item').removeData('price');

// 移除所有透過 data() 儲存的資料
$('#item').removeData();
removeData() 只會移除透過 data() 方法儲存的資料,不會移除 HTML 的 data-_ 屬性。若要移除 HTML 屬性,請使用 removeAttr('data-_')

實用範例

切換按鈕狀態

$('#submit').on('click', function () {
  var $btn = $(this);

  // 停用按鈕並顯示載入中
  $btn.prop('disabled', true).text('處理中...');

  // 模擬 Ajax 完成後恢復
  setTimeout(function () {
    $btn.prop('disabled', false).text('送出');
  }, 2000);
});

全選/取消全選

$('#selectAll').on('change', function () {
  var isChecked = $(this).prop('checked');
  $('input[name="item"]').prop('checked', isChecked);
});

// 更新全選狀態
$('input[name="item"]').on('change', function () {
  var total = $('input[name="item"]').length;
  var checked = $('input[name="item"]:checked').length;
  $('#selectAll').prop('checked', total === checked);
});

動態設定連結

$('.download-btn').each(function () {
  var $btn = $(this);
  var fileId = $btn.data('fileId');
  var fileName = $btn.data('fileName');

  $btn.attr({
    href: '/download/' + fileId,
    download: fileName,
  });
});

表單資料收集

$('form').on('submit', function (e) {
  e.preventDefault();

  var formData = {
    username: $('#username').val(),
    email: $('#email').val(),
    gender: $('input[name="gender"]:checked').val(),
    country: $('#country').val(),
    interests: $('input[name="interest"]:checked')
      .map(function () {
        return $(this).val();
      })
      .get(),
    agree: $('#agree').prop('checked'),
  };

  console.log(formData);
});