精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

使用 React Hooks 實現鼠標懸浮卡片發光的動畫效果

開發
在網上看到了一個很有趣的動畫效果:光會跟隨鼠標在卡片上進行移動,并且卡片會有視差的效果。那么在 React 中應該如何去實現這個效果呢?

有趣的動畫效果

前幾天在網上看到了一個很有趣的動畫效果,如下,光會跟隨鼠標在卡片上進行移動,并且卡片會有視差的效果,那么在 React 中應該如何去實現這個效果呢?

基本實現思路

其實實現思路很簡單,無非就是分幾步:

  • 首先,卡片是相對定位,光是絕對定位
  • 監聽卡片的鼠標移入事件mouseenter,當鼠標進入時顯示光
  • 監聽卡片的鼠標移動事件mouseover,鼠標移動時修改光的left、top,讓光跟隨鼠標移動
  • 監聽卡片的鼠標移出事件mouseleave,鼠標移出時,隱藏光

我們先在 Index.tsx 中準備一個卡片頁面,光的CSS效果可以使用filter: blur() 來實現:

可以看到現在的效果是這樣:

實現光源跟隨鼠標

在實現之前我們需要注意幾點:

  • 鼠標移入時需要設置卡片 overflow: hidden,否則光會溢出,而鼠標移出時記得還原
  • 獲取鼠標坐標時需要用clientX/Y而不是pageX/Y,因為前者會把頁面滾動距離也算進去,比較嚴謹

剛剛說到實現思路時我們說到了mouseenter、mousemove、mouseleave,其實mouseenter、mouseleave 這二者的邏輯比較簡單,重點是 mouseover 這個監聽函數

而在 mouseover 這個函數中,最重要的邏輯就是:光怎么跟隨鼠標移動呢?

或者也可以這么說:怎么計算光相對于卡片盒子的 left 和 top

對此我專門畫了一張圖,相信大家一看就懂怎么算了:

  • left = clientX - x - width/2
  • height = clientY - y - height/2

知道了怎么計算,那么邏輯的實現也很明了了~封裝一個use-light-card.ts

接著在頁面中去使用:

這樣就能實現基本的效果啦~

卡片視差效果

卡片的視差效果需要用到樣式中 transform 樣式,主要是配置四個東西:

  • perspective:定義元素在 3D 變換時的透視效果
  • rotateX:X 軸旋轉角度
  • rotateY:Y 軸旋轉角度
  • scale3d:X/Y/Z 軸上的縮放比例

現在就有了卡片視差的效果啦~

給所有卡片添加光源

上面只是給一個卡片增加光源,接下來可以給每一個卡片都增加光源啦!!!

讓光源變成可配置

上面的代碼,總感覺這個 hooks 耦合度太高不太通用,所以我們可以讓光源變成可配置化,這樣每個卡片就可以展示不同大小、顏色的光源了~像下面一樣:

既然是配置化,那我們希望是這么去使用 hooks 的,我們并不需要自己在頁面中去寫光源的dom節點,也不需要自己去寫光源的樣式,而是通過配置傳入 hooks 中:

所以 hooks 內部要自己通過操作 DOM 的方式,去添加、刪除光源,可以使用createElement、appendChild、removeChild 去做這些事~

完整源碼

// use-light-card.ts

import { useEffect, useRef } from 'react';

interface IOptions {
  light?: {
    width?: number; // 寬
    height?: number; // 高
    color?: string; // 顏色
    blur?: number; // filter: blur()
  };
}

export const useLightCard = (option: IOptions = {}) => {
  // 獲取卡片的dom節點
  const cardRef = useRef<HTMLDivElement | null>(null);
  let cardOverflow = '';
  // 光的dom節點
  const lightRef = useRef<HTMLDivElement>(document.createElement('div'));
  // 設置光源的樣式

  const setLightStyle = () => {
    const { width = 60, height = 60, color = '#ff4132', blur = 40 } = option.light ?? {};
    const lightDom = lightRef.current;
    lightDom.style.position = 'absolute';
    lightDom.style.width = `${width}px`;
    lightDom.style.height = `${height}px`;
    lightDom.style.background = color;
    lightDom.style.filter = `blur(${blur}px)`;
  };

  // 設置卡片的 overflow 為 hidden
  const setCardOverflowHidden = () => {
    const cardDom = cardRef.current;
    if (cardDom) {
      cardOverflow = cardDom.style.overflow;
      cardDom.style.overflow = 'hidden';
    }
  };
  // 還原卡片的 overflow
  const restoreCardOverflow = () => {
    const cardDom = cardRef.current;
    if (cardDom) {
      cardDom.style.overflow = cardOverflow;
    }
  };

  // 往卡片添加光源
  const addLight = () => {
    const cardDom = cardRef.current;
    if (cardDom) {
      cardDom.appendChild(lightRef.current);
    }
  };
  // 刪除光源
  const removeLight = () => {
    const cardDom = cardRef.current;
    if (cardDom) {
      cardDom.removeChild(lightRef.current);
    }
  };

  // 監聽卡片的鼠標移入
  const onMouseEnter = () => {
    // 添加光源
    addLight();
    setCardOverflowHidden();
  };

  // use-light-card.ts

  // 監聽卡片的鼠標移動
  const onMouseMove = (e: MouseEvent) => {
    // 獲取鼠標的坐標
    const { clientX, clientY } = e;
    // 讓光跟隨鼠標
    const cardDom = cardRef.current;
    const lightDom = lightRef.current;
    if (cardDom) {
      // 獲取卡片相對于窗口的x和y坐標
      const { x, y } = cardDom.getBoundingClientRect();
      // 獲取光的寬高
      const { width, height } = lightDom.getBoundingClientRect();
      lightDom.style.left = `${clientX - x - width / 2}px`;
      lightDom.style.top = `${clientY - y - height / 2}px`;

      //   設置動畫效果
      const maxXRotation = 10; // X 軸旋轉角度
      const maxYRotation = 10; // Y 軸旋轉角度

      const rangeX = 200 / 2; // X 軸旋轉的范圍
      const rangeY = 200 / 2; // Y 軸旋轉的范圍

      const rotateX = ((clientX - x - rangeY) / rangeY) * maxXRotation; // 根據鼠標在 Y 軸上的位置計算繞 X 軸的旋轉角度
      const rotateY = -1 * ((clientY - y - rangeX) / rangeX) * maxYRotation; // 根據鼠標在 X 軸上的位置計算繞 Y 軸的旋轉角度

      cardDom.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`; //設置 3D 透視
    }
  };
  // 監聽卡片鼠標移出
  const onMouseLeave = () => {
    // 鼠標離開移出光源
    removeLight();
    restoreCardOverflow();
  };

  useEffect(() => {
    // 設置光源樣式
    setLightStyle();
    // 綁定事件
    cardRef.current?.addEventListener('mouseenter', onMouseEnter);
    cardRef.current?.addEventListener('mousemove', onMouseMove);
    cardRef.current?.addEventListener('mouseleave', onMouseLeave);
    return () => {
        // 解綁事件
        cardRef.current?.removeEventListener('mouseenter', onMouseEnter);
        cardRef.current?.removeEventListener('mousemove', onMouseMove);
        cardRef.current?.removeEventListener('mouseleave', onMouseLeave);
    }
  })

  return {
    cardRef,
  };
};

// Index.tsx
import './Index.less'
import { useLightCard } from './use-light-card'

const Index = () => {
    const { cardRef: cardRef1 } = useLightCard()
    const { cardRef: cardRef2 } = useLightCard({
        light: {
            color: '#ffffff',
            width: 100
        }
    })
    const { cardRef: cardRef3 } = useLightCard({
        light: {
            color: 'yellow'
        }
    })

    return <div className='light-card-container'>
        {/* 方塊盒子 */}
        <div className='item' ref={cardRef1}></div>
        {/* 方塊盒子 */}
        <div className='item' ref={cardRef2}></div>
        {/* 方塊盒子 */}
        <div className='item' ref={cardRef3}></div>
    </div>
}

export default Index
// Index.less

.light-card-container {
    background: black;
    width: 100%;
    height: 100%;
    padding: 200px;
    display: flex;
    justify-content: space-between;
  
    .item {
      position: relative;
      width: 125px;
      height: 125px;
      background: #1c1c1f;
      border: 1px solid rgba(255, 255, 255, 0.1);

      // 不需要了
      // .light {
      //   width: 60px;
      //   height: 60px;
      //   background: #ff4132;
      //   filter: blur(40px);
      //   position: absolute;
      // }
    }
}

結語

責任編輯:趙寧寧 來源: 前端之神
相關推薦

2017-02-06 13:00:49

Android翻轉卡片動畫效果

2024-05-22 08:47:41

2020-10-28 09:12:48

React架構Hooks

2022-04-16 20:10:00

React Hookfiber框架

2022-08-21 09:41:42

ReactVue3前端

2022-07-18 09:01:58

React函數組件Hooks

2022-02-10 19:15:18

React監聽系統模式

2019-08-20 15:16:26

Reacthooks前端

2011-07-08 10:15:15

IPhone 動畫

2023-11-06 08:00:00

ReactJavaScript開發

2009-09-22 12:59:58

ibmdwDojo

2021-03-09 09:52:55

技術React Hooks'數據

2021-03-18 08:00:55

組件Hooks React

2022-03-31 17:54:29

ReactHooks前端

2020-09-19 17:46:20

React Hooks開發函數

2009-09-03 16:50:35

C#鼠標形狀

2021-02-24 07:40:38

React Hooks閉包

2012-01-10 14:59:42

jQuery

2010-09-09 12:49:58

鼠標懸停tip效果CSS

2019-03-13 10:10:26

React組件前端
點贊
收藏

51CTO技術棧公眾號

日韩美一区二区三区| 国产精品久久久久久久久免费相片 | 亚洲美女又黄又爽在线观看| 日本一区二区三区四区视频| 国产调教在线观看| 亚洲高清国产拍精品26u| 一区二区三区.www| 欧美美乳视频网站在线观看| 国产又粗又猛又爽又黄的| 亚洲午夜激情在线| 在线观看免费高清视频97| 日韩大尺度视频| 欧美成人精品三级网站| 亚洲一区二区在线免费看| 欧美日韩国产精品一卡| 精品女同一区二区三区| 久久蜜桃精品| 欧美福利视频在线观看| 亚洲这里只有精品| 福利小视频在线| 国产精品一二三在| 欧美中文字幕视频| 亚洲色婷婷一区二区三区| 久久99免费视频| 日韩欧美精品三级| 欧美特级aaa| 欧美极品videos大乳护士| 亚洲同性gay激情无套| 欧美久久久久久| 丁香六月色婷婷| 精品写真视频在线观看 | 裸体武打性艳史| 精品美女久久| 亚洲欧美日韩天堂一区二区| 欧美日韩一区二区区| 国产麻豆一区| 在线观看国产精品网站| 男人和女人啪啪网站| 污的网站在线观看| 亚洲女与黑人做爰| 在线免费一区| 色的视频在线免费看| 国产三级精品视频| 久久综合一区二区三区| 神马午夜电影一区二区三区在线观看| 国产精品77777竹菊影视小说| 国产精品专区一| 五月婷婷激情五月| 男人天堂欧美日韩| 青青久久aⅴ北条麻妃| 国产精品suv一区二区| 欧美日韩第一区| 欧美日韩国产第一页| 日韩a级片在线观看| 亚州av乱码久久精品蜜桃| 久久韩国免费视频| 欧美一级特黄高清视频| 欧美jizz| 欧美一区二区三区视频在线 | 日韩欧美123区| 99久久婷婷| 久久中文字幕国产| 九九视频在线观看| 好看的日韩av电影| 欧美极品少妇xxxxⅹ喷水 | 狠狠色狠色综合曰曰| 337p粉嫩大胆噜噜噜鲁| 亚洲日本天堂| 一本久久a久久免费精品不卡| 日批视频在线免费看| 欧美精品日日操| 在线观看亚洲精品视频| 黄色三级视频在线| 国产精品一区二区三区www| 亚洲高清视频在线| av免费观看国产| 中文字幕乱码在线播放| 91国产精品成人| 亚洲一区二区三区四区五区| 国产欧美日韩电影| 亚洲黄色成人网| 亚洲国产午夜精品| 99久久香蕉| 亚洲欧美一区二区精品久久久 | 自拍偷拍亚洲综合| 精品免费国产| 久久国产精品高清一区二区三区| 国产成人自拍网| 国产精品日韩欧美一区二区| 手机在线观看免费av| 国产偷国产偷精品高清尤物 | 91热精品视频| 日韩一级中文字幕| 中文字幕成人av| 妞干网在线播放| 神马久久资源| 精品欧美一区二区三区精品久久| 久久久久国产精品区片区无码| 成人激情视频| 欧美精品videosex牲欧美| 国产又粗又爽视频| 免费人成在线不卡| 国产亚洲欧美一区二区三区| www在线播放| 亚洲国产欧美在线人成| 国产视频手机在线播放| 岛国成人av| 日韩中文字在线| 人妻大战黑人白浆狂泄| 老司机aⅴ在线精品导航| 中文字幕精品www乱入免费视频| 久一视频在线观看| 美国三级日本三级久久99| 国产伦精品一区二区三区免费视频| 国产视频网站在线| 亚洲国产精品一区二区尤物区| 国产理论在线播放| 欧美绝顶高潮抽搐喷水合集| 久久亚洲私人国产精品va| 99久久久久久久久| 成人av网址在线观看| 精品一区二区成人免费视频| 亚洲成人短视频| 亚洲精品国产suv| caoporn91| 日韩电影在线一区| 久久久久国产精品视频| av影院在线| 91精品国产色综合久久ai换脸| www.日本高清视频| 久久久久99| 久久av一区二区三区漫画| 日本动漫理论片在线观看网站| 欧美系列在线观看| 欧美亚一区二区三区| 亚洲成人精选| 国产在线精品一区免费香蕉 | 色婷婷综合成人av| 日韩不卡高清视频| 久久日一线二线三线suv| 极品粉嫩国产18尤物| 一区二区三区四区高清视频| 久久国产精品电影| 国产精品高潮呻吟AV无码| 欧美国产一区视频在线观看| 黄色片在线免费| 久久爱www成人| 日韩av免费在线观看| 精品美女视频在线观看免费软件 | 在线观看毛片网站| 久久九九久精品国产免费直播| a级黄色片免费| 羞羞电影在线观看www| 欧美日韩国产不卡| 中文字幕观看av| 久久99精品视频| 99re99热| 66精品视频在线观看| 久久久免费观看视频| 免费的黄色av| 欧美日韩亚洲视频| 日本欧美一区二区三区不卡视频| 麻豆国产精品一区二区三区| 国产免费色视频| 美女精品久久| 亚洲网址你懂得| 永久久久久久久| 国产黄色成人av| 大陆av在线播放| 日韩av黄色在线| 国产成人a亚洲精品| 成人免费黄色网页| 日韩一级在线观看| 亚洲图片另类小说| 黄色欧美日韩| 精品国产一区二区三区免费 | 色综合网站在线| 亚洲高潮女人毛茸茸| 韩国成人在线视频| 成年人午夜视频在线观看 | 国产老肥熟一区二区三区| 国产曰肥老太婆无遮挡| 精品国产乱码久久久| 91日本视频在线| av资源新版天堂在线| 国产亚洲精品久久久久动| 国产又粗又大又爽视频| 亚洲福利一二三区| 国产7777777| 粉嫩在线一区二区三区视频| 日本精品久久久久中文字幕| 午夜精品毛片| 欧美国产综合视频| 成人亚洲精品| 日韩av大片免费看| caoporn免费在线视频| 亚洲另类图片色| 国产www免费观看| 色婷婷国产精品| 欧美成人三级视频| 中文字幕免费在线观看视频一区| 黑人巨大猛交丰满少妇| 男女精品网站| 真实国产乱子伦对白视频| 沈樵精品国产成av片| av一区二区三区在线观看| 成人黄色免费短视频| 欧美高清电影在线看| jizzjizz在线观看| 亚洲第一色中文字幕| 一区二区三区播放| 色综合视频在线观看| 久久午夜无码鲁丝片午夜精品| 国产欧美综合在线观看第十页| 稀缺小u女呦精品呦| 久久国产麻豆精品| 黄www在线观看| 好看的日韩av电影| 天天做天天爱天天高潮| 欧洲杯什么时候开赛| 久久久久久久免费| 欧美区一区二区| 91精品久久久久久久久不口人| 亚洲欧美韩国| 午夜免费日韩视频| 在线黄色网页| 久久久国产成人精品| av大片在线播放| 精品视频1区2区| 国内精品福利视频| 亚洲在线免费播放| 一区二区成人免费视频| 中文字幕中文字幕一区二区 | 色棕色天天综合网| 噜噜噜噜噜久久久久久91| 澳门成人av| 成人免费在线一区二区三区| 欧美激情三级| 91九色国产在线| 日韩福利在线观看| 国产主播在线一区| 91精品国产色综合久久不卡粉嫩| 国产精品欧美激情| 成人免费网站在线观看视频| 正在播放欧美一区| 大胆av不用播放器在线播放| 亚洲天堂av电影| 国产精品爽爽久久| 欧美理论片在线| 国产精品一区二区黑人巨大| 欧美日韩国产综合久久| 亚洲天堂视频在线| 欧美女孩性生活视频| 国产精品国产三级国产普通话对白| 欧美三级视频在线播放| 中文字幕一区二区免费| 欧美日韩你懂的| 国产裸体永久免费无遮挡| 日韩一区二区三区在线视频| 精品国产伦一区二区三区| 精品福利二区三区| 日韩福利一区二区| 91精品国产一区二区三区香蕉| 国产视频一区二区三区四区五区| 91精品在线免费| 亚洲成人一级片| 亚洲精品国产suv| 成人在线观看网站| 久久久精品久久| gogo高清在线播放免费| 欧美最顶级的aⅴ艳星| 成人免费av电影| 成人国产精品一区| 亚洲黄色中文字幕| 国产精品www色诱视频| 欧美aaa级| 亚洲一区中文字幕| 久久精品国产亚洲5555| 秋霞在线观看一区二区三区| 婷婷综合五月| 国内少妇毛片视频| 久久免费国产| 男生和女生一起差差差视频| 99久久99久久久精品齐齐| 日本理论中文字幕| 一个色在线综合| 少妇久久久久久久| 日韩女优电影在线观看| 日产精品久久久久久久性色| www.亚洲一区| 牛牛精品一区二区| 91久久精品国产91性色| 欧美理论电影在线精品| 熟妇熟女乱妇乱女网站| 国产精品一国产精品k频道56| 久久国产精品国产精品| 成人的网站免费观看| 懂色av蜜臀av粉嫩av永久| 亚洲国产aⅴ成人精品无吗| 这里只有精品9| 精品国产伦一区二区三区观看方式 | 国内一区二区视频| 国产黄色网址在线观看| 亚洲欧美色一区| 无码视频在线观看| 精品噜噜噜噜久久久久久久久试看 | 国产日韩另类视频一区| 国产精品一区二区三区免费| 成人一区二区| 北条麻妃在线视频观看| 韩国av一区二区| 成人一级片免费看| 欧美日韩中文在线| 国产在线观看你懂的| 欧洲色大大久久| 亚州av在线播放| 久久99久久99精品中文字幕| av成人在线播放| 久久亚洲一区二区| 欧美日韩亚洲一区二区三区在线| 超碰超碰在线观看| 久久日韩粉嫩一区二区三区| 粉嫩aⅴ一区二区三区| 五月激情综合网| www.激情五月| 久久精品欧美视频| 素人一区二区三区| 欧美一区二区三区在线播放| 亚洲精品1234| 逼特逼视频在线| 成人午夜免费av| 久久久久黄色片| 欧美一卡2卡三卡4卡5免费| 69视频在线观看| 国产精品狼人色视频一区| 精品在线观看入口| 91成人在线观看喷潮教学| 国产69精品久久久久毛片 | 欧美日韩伦理片| 91精品国产91久久久久久| 成人av综合网| 国产二区视频在线| 成人av在线影院| 国产污污视频在线观看| 亚洲精品电影久久久| 麻豆视频在线观看免费网站黄| 国产一区在线观| 99精品国产福利在线观看免费| 无码国产精品一区二区免费式直播| 伊人婷婷欧美激情| 丰满熟妇人妻中文字幕| 欧美极品美女电影一区| 精品嫩草影院| 欧美视频第一区| 国产人伦精品一区二区| 一区二区乱子伦在线播放| 一区二区三区视频免费| 黄色精品视频网站| 超碰在线免费观看97| 国产精品香蕉一区二区三区| 久久网中文字幕| 日韩av在线资源| 日韩漫画puputoon| 日本黄色a视频| 成人性色生活片| 中文字幕在线播| 日韩中文字幕免费视频| 欧美专区一区| 欧美一区1区三区3区公司| 日本中文在线一区| 国产午夜手机精彩视频| 亚洲国产成人精品一区二区| 欧美舌奴丨vk视频| 在线观看成人一级片| 岛国av在线一区| 好吊色在线视频| 久久精品国产亚洲7777| 91成人午夜| 日本老熟妇毛茸茸| 亚洲色图.com| 青梅竹马是消防员在线| 国产欧美精品一区二区三区-老狼 国产欧美精品一区二区三区介绍 国产欧美精品一区二区 | 国产伦精品一区二区三区视频痴汉 | free性中国hd国语露脸| 欧美视频日韩视频| 欧洲一区二区三区| 日本不卡二区| 国产成人精品一区二 | 欧美另类久久久品| 丁香花电影在线观看完整版| 日本一区二区三区www| 国产酒店精品激情| 黄色免费av网站| 萌白酱国产一区二区| 亚州av一区| 国产老熟妇精品观看| 国产精品另类一区| 色呦呦视频在线| 91在线精品视频| 手机精品视频在线观看|