日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

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

來源: 責編: 時間:2024-06-05 17:43:48 153觀看
導讀有趣的動畫效果前幾天在網上看到了一個很有趣的動畫效果,如下,光會跟隨鼠標在卡片上進行移動,并且卡片會有視差的效果,那么在 React 中應該如何去實現這個效果呢?基本實現思路其實實現思路很簡單,無非就是分幾步:首先,卡片是

有趣的動畫效果

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

BoY28資訊網——每日最新資訊28at.com

基本實現思路

其實實現思路很簡單,無非就是分幾步:BoY28資訊網——每日最新資訊28at.com

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

我們先在 Index.tsx 中準備一個卡片頁面,光的CSS效果可以使用filter: blur() 來實現:BoY28資訊網——每日最新資訊28at.com

BoY28資訊網——每日最新資訊28at.com

卡片視差效果

卡片的視差效果需要用到樣式中 transform 樣式,主要是配置四個東西:BoY28資訊網——每日最新資訊28at.com

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

BoY28資訊網——每日最新資訊28at.com

給所有卡片添加光源

上面只是給一個卡片增加光源,接下來可以給每一個卡片都增加光源啦!!!BoY28資訊網——每日最新資訊28at.com

BoY28資訊網——每日最新資訊28at.com

讓光源變成可配置

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

BoY28資訊網——每日最新資訊28at.com

既然是配置化,那我們希望是這么去使用 hooks 的,我們并不需要自己在頁面中去寫光源的dom節點,也不需要自己去寫光源的樣式,而是通過配置傳入 hooks 中:BoY28資訊網——每日最新資訊28at.com

BoY28資訊網——每日最新資訊28at.com

BoY28資訊網——每日最新資訊28at.com

BoY28資訊網——每日最新資訊28at.com

BoY28資訊網——每日最新資訊28at.com

所以 hooks 內部要自己通過操作 DOM 的方式,去添加、刪除光源,可以使用createElement、appendChild、removeChild 去做這些事~BoY28資訊網——每日最新資訊28at.com

BoY28資訊網——每日最新資訊28at.com

BoY28資訊網——每日最新資訊28at.com

完整源碼

// use-light-card.tsimport { 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.tsximport './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;      // }    }}

結語

BoY28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-92131-0.html使用 React Hooks 實現鼠標懸浮卡片發光的動畫效果

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 25個每個開發人員都應該知道的CSS 技巧

下一篇: C# 異常處理:每個 .NET 開發者都應掌握的核心知識點

標簽:
  • 熱門焦點
  • 天貓精靈Sound Pro體驗:智能音箱沒有音質?來聽聽我的

    這幾年除了手機作為智能生活終端最主要的核心之外,第二個可以成為中心點的產品是什么?——是智能音箱。 手機在執行命令的時候有兩種操作方式,手和智能語音助手,而智能音箱只
  • 2023年Q2用戶偏好榜:12+256G版本成新主流

    3月份的性能榜、性價比榜和好評榜之后,就要輪到2023年的第二季度偏好榜了,上半年的新機潮已經過去,最明顯的肯定就是大內存和存儲的機型了,另外部分中端機也取消了屏幕塑料支架
  • 十個可以手動編寫的 JavaScript 數組 API

    JavaScript 中有很多API,使用得當,會很方便,省力不少。 你知道它的原理嗎? 今天這篇文章,我們將對它們進行一次小總結。現在開始吧。1.forEach()forEach()用于遍歷數組接收一參
  • 三言兩語說透設計模式的藝術-單例模式

    寫在前面單例模式是一種常用的軟件設計模式,它所創建的對象只有一個實例,且該實例易于被外界訪問。單例對象由于只有一個實例,所以它可以方便地被系統中的其他對象共享,從而減少
  • 使用LLM插件從命令行訪問Llama 2

    最近的一個大新聞是Meta AI推出了新的開源授權的大型語言模型Llama 2。這是一項非常重要的進展:Llama 2可免費用于研究和商業用途。(幾小時前,swyy發現它已從LLaMA 2更名為Lla
  • Python異步IO編程的進程/線程通信實現

    這篇文章再講3種方式,同時講4中進程間通信的方式一、 Python 中線程間通信的實現方式共享變量共享變量是多個線程可以共同訪問的變量。在Python中,可以使用threading模塊中的L
  • 重估百度丨大模型,能撐起百度的“今天”嗎?

    自象限原創 作者|程心 羅輯2023年之前,對于自己的&ldquo;今天&rdquo;,百度也很迷茫。&ldquo;新業務到 2022 年底還是 0,希望 2023 年出來一個 1。&rdquo;這是2022年底,李彥宏
  • iQOO 11S或7月上市:搭載“雞血版”驍龍8Gen2 史上最強5G Soc

    去年底,iQOO推出了“電競旗艦”iQOO 11系列,作為一款性能強機,iQOO 11不僅全球首發2K 144Hz E6全感屏,搭載了第二代驍龍8平臺及144Hz電競屏,同時在快充
  • DRAM存儲器10月價格下跌,NAND閃存本月價格與上月持平

    10月30日,據韓國媒體消息,自今年年初以來一直在上漲的 DRAM 存儲器的交易價格僅在本月就下跌了近 10%,此次是全年首次降價,而NAND 閃存本月價格與上月持平。市
Top 主站蜘蛛池模板: 余庆县| 宁乡县| 凤山县| 资源县| 锡林郭勒盟| 洞口县| 南木林县| 娱乐| 永泰县| 阜新市| 敦化市| 内江市| 盐边县| 桂平市| 嘉义县| 历史| 商丘市| 永福县| 临潭县| 维西| 当阳市| 中宁县| 普兰县| 观塘区| 壤塘县| 巢湖市| 宜宾县| 靖州| 巫溪县| 报价| 阿尔山市| 安康市| 昌宁县| 台东县| 太白县| 碌曲县| 白河县| 河西区| 平远县| 南木林县| 宜章县|