iT邦幫忙

2022 iThome 鐵人賽

DAY 4
0
自我挑戰組

向網頁施點魔法粉 framer-motion 系列 第 4

#04 Put your Gestures up II - Pan, whileDrag, whileInView

  • 分享至 

  • xImage
  •  

上篇只介紹到最基本的使用者互動操作,本篇的 PanwhileDrag 具有持續的互動性,在過程中能依照更細節的偏移量 (offset)、速度 (velocity)、座標位置 (point) 來變換動畫。最後還有 whileInView 是我覺得最好用的,scroll trigger 幾乎是每個網頁都會添加的動畫,再調整一些動畫參數,就能獲得不一樣的感受。

目錄

  1. 摩擦摩擦 似魔鬼的步伐 : Pan 事件
  2. 拖出去斬了 : whileDrag
  3. 映入眼簾 : whileInView

本節資源 :

  1. Day04
    2.網頁展示

摩擦摩擦 似魔鬼的步伐 : Pan 事件

在介紹 Drag 之前,要來討論 Pan。在攝影技巧裡是稱作固定鏡頭的平移,在網頁上是 使用者在固定區塊進行偏移

跟前一篇提到的 Tap 差別在,只要 點擊之後移動超過 3 像素,就啟動 Pan,從點擊滑動超過 3 像素到放開點擊,這是一個完整的 Pan。

Pan 跟 Tap 通常會是一組,並且要符合 CSS touch-action 的規則 (應用於觸控式螢幕), 必須禁用 x/y 軸的移動。

Pan 也提供在不同時間點的事件監聽 onPanStartonPanEnd

<motion.div
  onPan={(e, info) => {{ ... }}
  onPanStart={(e, info) => { ... }}
  onPanEnd={(e, info) => { ... }}
/>

效果 : (待補)

拖出去斬了 : whileDrag

拖曳 (drag) 可以為網頁添加不少趣味性,whileDrag 就是 正在拖曳的動畫狀態,motion 元件還有提供其他 drag 的 props 快速設定 drag 更細節上的操作 :

  1. drag : 給予拖曳權限與拖曳的方向,共有三個值
  • boolean : 如果是 true 兩個方向都可以拖曳,反之 false 就是不能拖曳。
  • x : 只能平移。
  • y : 只能垂直。
  1. dragConstraints: 拖曳的範圍限制,可以侷限在指定的上下左右 (top, bottom, left & right) 或是搭配 useRefref 限制在父元素容器內。

跟其他互動一樣,也有提供更細微操作的監聽事件 onDragonDragStartonDragEnd

<motion.div
  drag="x"
  dragConstraints={ref}
  whileDrag={{
      scale: 1.5,
      cursor: "grabbing",
  }}
  onDrag={(e, info) => {{ ... }}
  onDragEnd={(e, info) => { ... }}
/>

拖曳在專案中很常用來做物件排序,在 motion 裡有專屬的 Component 處理這件事,之後會再提到,暫時以單個元素的拖曳為範例。

自定義 range slider

input 的 range slider 是最常看見的拖曳操作

  • CSS
.slider{
    position: relative;
    width: 300px;
    height: 10px;
    border-radius: 10px;
    background: #aaa;
    display: flex;
    align-items: center;
    border: 1px solid #666;
}
.slider::after{
    position: absolute;
    top:0;
    bottom:0;
    left:0;
    right: 0;
    background-color: #aaa;
}
.slider-thumb{
    display: block;
    width: 30px;
    height: 30px;
    cursor: grab;
    line-height: 30px;
    text-align: center;
    font-size: 30px;
    margin-left: -6px;
    text-shadow: 0 3px rgba(0,0,0,.3);
}
  • 定義好表情跟顏色 (這裡看不到 emoji 我用文字代替)
const faces = ["(疑惑)", "(生氣)", "(尷尬)", "(無言)", "(開心)", "(興奮)", "(大愛)"];
const colors = ["#aaa", "#f00", "#0ea", "#0aa", "#fa2", "#fe2", "#fae"];
  • 按照傳入的 drag 位置設定不同的 range
// 轉換成對應的 index,由於我設定的 slider width 是 300 分成多個層級
function pointer2Range(pointerX) {
    const number = Math.round(pointerX / 60);
    if (number <= 1) return 1;
    if (number >= 6) return 6;
    return number;
}
  • state 跟 ref
  const sliderRef = useRef(null);
  const [range, setRange] = useState(0);
  • 結構
 <motion.div
  className="slider"
  {/* 拿到元素的資料˙ */}
  ref={sliderRef}
  {/* 改變背景顏色 */}
  animate={{
      background: colors[range],
  }}
>
  <motion.span
      className="slider-thumb"
      drag="x"
      {/* 限制拖曳的最大範圍*/}
      dragConstraints={sliderRef}
      {/* 按住拖曳 */}
      whileDrag={{
          scale: 1.5,
          cursor: "grabbing",
      }}
      {/* 滑動中 */}
      onDrag={(e, info) => {
          setRange(pointer2Range(info.point.x));
      }}
      {/* 結束滑動,放開點擊或滑鼠 */}
      onDragEnd={(e, info) => {
          setRange(pointer2Range(info.point.x));
      }}
      
      {/* 在滑動時就會替換臉 */}
      {faces[range]}
  </motion.span>
</motion.div>
  • 一開始是想說做五等分量表 :O,後來想說有趣一點改成 emoji

映入眼簾 : whileInView

這是我覺得超好用的屬性,如果你曾用過 AOS 套件,這個就不會很陌生。

inView 顧名思義就是 當元素進入 viewport 觸發的動畫。以往要透過 Intersection Observer API 設定,現在搭配 motion props 就能簡單地讓網頁看見後滑動飛入的效果。

通常搭配 initial ,起始位置先設定好後,等進入 viewport 在啟動動畫

  • 元素會從左邊位移到原本位置
<motion.div
  initial={{
    x: -100
  }}
  whileInView={{
    x : 0
  }}
/>

今天只會講到最基本的 scroll 屬性,之後會再實作比較 fancy 的動畫,如果迫不及待,可以看
官方的 scroll 範例,裡面都很實用,舉凡 : 跑馬燈、頁面進度條等等的。

預設是不再 view 裡回歸到 initial 動畫,進入就執行 whileInView,要是 想要只出現 1 次,只要加上 viewport 的 once :

viewport={{ once: true }}

效果 : (待補)

補充 : 胎死腹中的 @scroll-timeline

原生 CSS 也有個神祕的 scroll trigger 叫 @scroll-timeline ,目前是棄用狀態 QQ ,或許某朝一日會再復活也說不定,實際的例子可以看 CSS-tricks 的文章

總結

  • onPan : 固定元素的位移事件,其他還有 onPanStartonPanEnd
  • whileDrag : 拖曳當下觸發的動畫,事件相關有 onDragonDragStartonDragEnd
  • whileInView : 當元素進入 viewport 啟動動畫

大致上基本動畫的 props 都走過一輪了,使用上就是考驗大家的創意。明天會討論 motion 中強大的變體 Variants ,是一個把動畫個別提出 props,除了提高元件的重複性之外,也可以在細微調整 initialanimate 個別的 transition 屬性 。

參考資料

  1. 官方文件 : Gestures | Framer for Developers

雜談

我發現 IT 邦的文章編輯器不能辨識 emoji ... ,導致使用到的部分都變問號 QQ ,因此突然看到問號不是我在自我懷疑,我會再修正。


上一篇
#03 Put your Gestures up - Hover, Focus & Tap
下一篇
#05 Kage Bunshin no Jutsu - Variants
系列文
向網頁施點魔法粉 framer-motion 15
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言