jQuery 動畫效果 (Effects)

jQuery 提供了豐富的動畫效果方法,讓你能夠輕鬆地為網頁元素添加視覺動畫效果,包括顯示/隱藏、淡入淡出、滑動效果,以及自訂動畫。

顯示與隱藏

show() 和 hide()

// 立即顯示/隱藏
$('#box').show();
$('#box').hide();

// 帶有動畫效果
$('#box').show('slow'); // 慢速
$('#box').hide('fast'); // 快速
$('#box').show(400); // 400 毫秒

// 帶回呼函式
$('#box').show(400, function () {
  console.log('顯示動畫完成');
});

// 指定 easing
$('#box').show(400, 'swing', function () {
  console.log('完成');
});

toggle()

切換顯示/隱藏狀態:

// 切換顯示狀態
$('#box').toggle();

// 帶動畫
$('#box').toggle(400);

// 根據條件顯示/隱藏
$('#box').toggle(shouldShow); // shouldShow 為 true 則顯示

速度參數

參數說明
'slow'600 毫秒
'fast'200 毫秒
數字毫秒數

淡入淡出

fadeIn() 和 fadeOut()

// 淡入
$('#box').fadeIn();
$('#box').fadeIn('slow');
$('#box').fadeIn(400);

// 淡出
$('#box').fadeOut();
$('#box').fadeOut(400, function () {
  $(this).remove(); // 淡出後移除
});

fadeToggle()

切換淡入/淡出:

$('#box').fadeToggle();
$('#box').fadeToggle(400);

fadeTo()

淡入/淡出到指定的透明度:

// 淡到 50% 透明度
$('#box').fadeTo(400, 0.5);

// 淡到完全透明
$('#box').fadeTo(400, 0);

// 淡到完全不透明
$('#box').fadeTo(400, 1);

// 帶回呼函式
$('#box').fadeTo(400, 0.5, function () {
  console.log('完成');
});
fadeOut() 在動畫完成後會設定 display: none,而 fadeTo(duration, 0) 只會將透明度設為 0,元素仍佔據空間。

滑動效果

slideDown() 和 slideUp()

// 向下滑動顯示
$('#box').slideDown();
$('#box').slideDown(400);

// 向上滑動隱藏
$('#box').slideUp();
$('#box').slideUp(400, function () {
  console.log('滑動完成');
});

slideToggle()

切換滑動顯示/隱藏:

$('#box').slideToggle();
$('#box').slideToggle(400);

手風琴選單範例

$('.accordion-header').on('click', function () {
  // 關閉其他面板
  $(this).siblings('.accordion-header').next('.accordion-content').slideUp(300);

  // 切換當前面板
  $(this).next('.accordion-content').slideToggle(300);
});

自訂動畫

animate()

animate() 讓你可以建立自訂的動畫效果:

// 基本語法
$(selector).animate(properties, duration, easing, callback);

// 移動元素
$('#box').animate(
  {
    left: '250px',
    top: '100px',
  },
  400
);

// 改變尺寸
$('#box').animate(
  {
    width: '300px',
    height: '200px',
  },
  400
);

// 改變透明度
$('#box').animate(
  {
    opacity: 0.5,
  },
  400
);

// 多個屬性同時動畫
$('#box').animate(
  {
    left: '250px',
    opacity: 0.5,
    width: '150px',
    height: '150px',
  },
  400
);

相對值

使用 +=-= 進行相對動畫:

$('#box').animate(
  {
    left: '+=50px', // 向右移動 50px
    top: '-=30px', // 向上移動 30px
    width: '+=100px', // 寬度增加 100px
  },
  400
);

預設值

使用 'show''hide''toggle' 作為屬性值:

$('#box').animate(
  {
    width: 'toggle', // 切換寬度
    opacity: 'toggle', // 切換透明度
  },
  400
);

Easing 函式

jQuery 內建兩種 easing 函式:

  • 'swing'(預設)- 開始和結束較慢,中間較快
  • 'linear' - 等速
$('#box').animate(
  {
    left: '250px',
  },
  400,
  'linear'
);
如需更多 easing 效果,可以使用 jQuery UI 或其他 easing 插件。

可動畫的 CSS 屬性

animate() 只能用於數值型的 CSS 屬性,例如:

  • 位置:left、top、right、bottom
  • 尺寸:width、height、padding、margin
  • 透明度:opacity
  • 字體:fontSize、lineHeight
  • 邊框:borderWidth

不支援的屬性:

  • 顏色(需要 jQuery Color 插件)
  • transform(需要插件)

動畫佇列

連續的動畫會依序執行:

// 動畫會依序執行
$('#box')
  .animate({ left: '100px' }, 400)
  .animate({ top: '100px' }, 400)
  .animate({ left: '0' }, 400)
  .animate({ top: '0' }, 400);

同時執行動畫

使用物件一次傳入所有屬性:

// 同時動畫
$('#box').animate(
  {
    left: '100px',
    top: '100px',
    opacity: 0.5,
  },
  400
);

或使用 queue: false

$('#box')
  .animate({ left: '100px' }, { duration: 400, queue: false })
  .animate({ top: '100px' }, { duration: 400, queue: false });

動畫控制

stop() - 停止動畫

// 停止當前動畫
$('#box').stop();

// 停止並清除佇列
$('#box').stop(true);

// 停止、清除佇列,並跳到動畫結束狀態
$('#box').stop(true, true);

stop() 參數說明:

參數說明
stop()停止當前動畫,繼續執行佇列中的下一個
stop(true)停止當前動畫並清空佇列
stop(true, true)停止並跳到當前動畫的結束狀態

finish() - 立即完成

立即完成所有排隊的動畫,並跳到最終狀態:

$('#box').finish();

delay() - 延遲

在動畫佇列中插入延遲:

$('#box')
  .fadeOut(400)
  .delay(1000) // 等待 1 秒
  .fadeIn(400);

動畫佇列操作

// 加入自訂函式到佇列
$('#box')
  .animate({ left: '100px' }, 400)
  .queue(function (next) {
    $(this).addClass('moved');
    next(); // 必須呼叫 next() 以繼續佇列
  })
  .animate({ top: '100px' }, 400);

// 清空佇列
$('#box').clearQueue();

// 取得佇列
var queue = $('#box').queue();
console.log('佇列長度:', queue.length);

回呼函式與 Promise

回呼函式

$('#box').fadeIn(400, function () {
  // 動畫完成後執行
  console.log('fadeIn 完成');
});

// 多個元素時,回呼會在每個元素完成後各執行一次
$('.items').fadeIn(400, function () {
  console.log('一個元素完成'); // 每個元素都會觸發
});

Promise 風格

使用 .promise() 取得動畫的 Promise 物件:

// 等待所有元素動畫完成
$('.items')
  .fadeIn(400)
  .promise()
  .done(function () {
    console.log('所有元素都完成了');
  });

// 使用 then()
$('#box')
  .animate({ left: '100px' }, 400)
  .promise()
  .then(function () {
    console.log('第一段動畫完成');
    return $('#box').animate({ top: '100px' }, 400).promise();
  })
  .then(function () {
    console.log('第二段動畫完成');
  });

全域設定

$.fx.off - 關閉所有動畫

// 關閉所有動畫(動畫會立即完成)
$.fx.off = true;

// 開啟動畫
$.fx.off = false;

// 根據使用者偏好設定
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
  $.fx.off = true;
}

$.fx.interval - 動畫間隔

注意$.fx.interval 在 jQuery 3.0+ 已不建議使用,因為 jQuery 已改用 requestAnimationFrame

實用範例

手風琴選單

$('.accordion-toggle').on('click', function () {
  var $panel = $(this).next('.accordion-panel');

  // 關閉其他
  $('.accordion-panel').not($panel).slideUp(300);

  // 切換當前
  $panel.slideToggle(300);

  // 切換箭頭
  $(this).toggleClass('open');
  $(this).siblings('.accordion-toggle').removeClass('open');
});

平滑捲動

$('a[href^="#"]').on('click', function (e) {
  e.preventDefault();

  var target = $(this.hash);
  if (target.length) {
    $('html, body').animate(
      {
        scrollTop: target.offset().top - 60,
      },
      500
    );
  }
});

圖片輪播

var $slides = $('.slide');
var current = 0;

function showSlide(index) {
  $slides.fadeOut(300).eq(index).fadeIn(300);
}

$('#next').on('click', function () {
  current = (current + 1) % $slides.length;
  showSlide(current);
});

$('#prev').on('click', function () {
  current = (current - 1 + $slides.length) % $slides.length;
  showSlide(current);
});

// 自動播放
setInterval(function () {
  current = (current + 1) % $slides.length;
  showSlide(current);
}, 5000);

通知訊息

function showNotification(message, type) {
  var $notification = $('<div>', {
    class: 'notification ' + type,
    text: message,
  });

  $notification
    .appendTo('body')
    .hide()
    .fadeIn(300)
    .delay(3000)
    .fadeOut(300, function () {
      $(this).remove();
    });
}

// 使用
showNotification('儲存成功!', 'success');
showNotification('發生錯誤', 'error');

數字動畫

function animateNumber($element, target) {
  $({ value: 0 }).animate(
    { value: target },
    {
      duration: 1000,
      step: function () {
        $element.text(Math.floor(this.value));
      },
      complete: function () {
        $element.text(target);
      },
    }
  );
}

// 使用
animateNumber($('#counter'), 1000);

防止動畫堆疊

// 使用 stop() 防止動畫堆疊
$('.item').hover(
  function () {
    $(this).stop().animate({ marginLeft: '20px' }, 200);
  },
  function () {
    $(this).stop().animate({ marginLeft: '0' }, 200);
  }
);