欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Vue開發(fā)一個很火的卡片動畫效果

 更新時間:2024年02月06日 08:17:49   作者:imber  
這篇文章主要為大家詳細(xì)介紹了如何基于Vue開發(fā)一個很火的卡片動畫效果,大致包含兩個效果,光的跟隨效果還有卡片傾斜像?3D?的效果,感興趣的可以了解一下

扣子這個 AI 平臺,可以看到它首頁的卡片效果還是很酷炫的;大致包含兩個效果,光的跟隨效果還有卡片傾斜像 3D 的效果

github 在你沒有登錄的時候,首頁也有這樣一個卡片效果

我們也來實(shí)現(xiàn)一下,寫一個這樣的效果

先準(zhǔn)備三個盒子

這里用的react組件和tailwind來寫樣式,盒子不管你怎么寫,但是得有 relative 定位,因為光需要用定位來跟隨

export default function Home() {
  return (
    <main className="min-h-screen p-24 flex justify-center items-center bg-black gap-5">
      <div className="w-[384px] h-[384px] flex-center flex-col rounded-lg border border-[rgba(255,255,255,0.1)] bg-[#1C1C1F]"></div>
      <div className="w-[384px] h-[384px] flex-center flex-col rounded-lg border border-[rgba(255,255,255,0.1)] bg-[#1C1C1F]"></div>
      <div className="w-[384px] h-[384px] flex-center flex-col rounded-lg border border-[rgba(255,255,255,0.1)] bg-[#1C1C1F]"></div>
    </main>
  )
}

實(shí)現(xiàn)光源跟隨效果

1、需要監(jiān)聽盒子上的 mouseMove 事件和 mouseLeave 事件,進(jìn)入的時候顯示光源并計算隨鼠標(biāo)滾動的位置

2、需要注意光源不能擋住元素上面的位置,所以要設(shè)置低一點(diǎn)的層級

3、光源的模糊效果可以用filter:blur(100px)實(shí)現(xiàn)

'use client'
import { useRef, useState } from 'react'

export default function Home() {
  const cardRef = (useRef < HTMLDivElement) | (null > null) //卡片
  const lightRef = (useRef < HTMLDivElement) | (null > null) //光源
  const [isShowLight, setIsShowLight] = useState(false) //是否顯示光源
  // 光源隨鼠標(biāo)移動
  const [pos, setPos] = useState({
    left: '0px',
    top: '0px'
  })

  return (
    <main className="h-screen p-24 flex justify-center items-center bg-black gap-5">
      <div
        className="w-[384px] h-[384px] flex-center flex-col rounded-lg border border-[rgba(255,255,255,0.1)] bg-[#1C1C1F] relative overflow-hidden"
        onMouseMove={(e: React.MouseEvent<HTMLDivElement>) => {
          if (cardRef.current) {
            // 進(jìn)入盒子顯示光源
            setIsShowLight(true)
            // 父元素相對于頁面窗口
            const { x, y } = cardRef.current.getBoundingClientRect()
            // 鼠標(biāo)在頁面位置
            const { clientX, clientY } = e
            //光源隨鼠標(biāo)移動
            setPos({
              left: clientX - x - 100 + 'px', // 100為光源寬度的1/2
              top: clientY - y - 100 + 'px' // 100為光源高度的1/2
            })
          }
        }}
        onMouseLeave={() => {
          // 離開盒子隱藏光源
          setIsShowLight(false)
        }}
        ref={cardRef}
      >
        <div
          className={`${
            isShowLight ? '' : 'hidden'
          } absolute h-[200px] w-[200px] rounded-full bg-[#ff4132] blur-[150px] filter`}
          ref={lightRef}
          style={pos}
        ></div>
      </div>
      <div className="w-[384px] h-[384px] flex-center flex-col rounded-lg border border-[rgba(255,255,255,0.1)] bg-[#1C1C1F] relative"></div>
      <div className="w-[384px] h-[384px] flex-center flex-col rounded-lg border border-[rgba(255,255,255,0.1)] bg-[#1C1C1F] relative"></div>
    </main>
  )
}

實(shí)現(xiàn) 3D 卡片視差效果

1、主要是通過transform:'perspective(1000px) rotateX(10deg) rotateY(10deg) scale3d(1, 1, 1)'這個屬性實(shí)現(xiàn)

perspective(1000px): 這個函數(shù)定義了元素的透視效果。它接受一個參數(shù),表示視點(diǎn)(觀察者)與屏幕之間的距離。在這個例子中,透視距離被設(shè)置為 1000 像素,使得元素在進(jìn)行 3D 變換時產(chǎn)生透視效果。也就是偏移幅度。

rotateX(10deg): 這個函數(shù)定義了元素繞其 X 軸旋轉(zhuǎn)的角度。它接受一個參數(shù),表示旋轉(zhuǎn)的角度。在這個例子中,元素繞 X 軸順時針旋轉(zhuǎn)了 10 度。

rotateY(10deg): 這個函數(shù)定義了元素繞其 Y 軸旋轉(zhuǎn)的角度。它接受一個參數(shù),表示旋轉(zhuǎn)的角度。在這個例子中,元素繞 Y 軸順時針旋轉(zhuǎn)了 10 度。

scale3d(1, 1, 1): 這個函數(shù)定義了元素在三個軸上的縮放比例。它接受三個參數(shù),分別表示 X 軸、Y 軸和 Z 軸上的縮放比例。在這個例子中,元素在三個軸上的縮放比例都為 1,表示不進(jìn)行縮放。

import { useRef, useState } from 'react'

export default function Home() {
  const cardRef = (useRef < HTMLDivElement) | (null > null) //卡片
  const lightRef = (useRef < HTMLDivElement) | (null > null) //光源
  const [isShowLight, setIsShowLight] = useState(false) //是否顯示光源
  // 光源隨鼠標(biāo)移動
  const [pos, setPos] = useState({
    left: '0px',
    top: '0px'
  })

  return (
    <main className="h-screen p-24 flex justify-center items-center bg-black gap-5">
      <div
        className="w-[400px] h-[400px] flex-center flex-col rounded-lg border border-[rgba(255,255,255,0.1)] bg-[#1C1C1F] relative overflow-hidden"
        onMouseMove={(e: React.MouseEvent<HTMLDivElement>) => {
          if (cardRef.current) {
            setIsShowLight(true) // 進(jìn)入盒子顯示光源

            const { x, y } = cardRef.current.getBoundingClientRect() // 父元素相對于頁面窗口
            const { clientX, clientY } = e // 鼠標(biāo)在頁面位置

            const offsetX = clientX - x // 計算鼠標(biāo)在盒子內(nèi)的水平偏移量
            const offsetY = clientY - y // 計算鼠標(biāo)在盒子內(nèi)的垂直偏移量

            setPos({
              left: offsetX - 100 + 'px', // 100為光源寬度的1/2
              top: offsetY - 100 + 'px' // 100為光源高度的1/2
            })

            // 新增

            const maxXRotation = 10 // 最大繞 X 軸旋轉(zhuǎn)角度
            const maxYRotation = 10 // 最大繞 Y 軸旋轉(zhuǎn)角度

            const rangeX = 400 / 2 // X 軸旋轉(zhuǎn)范圍
            const rangeY = 400 / 2 // Y 軸旋轉(zhuǎn)范圍

            const rotateX = ((offsetY - rangeY) / rangeY) * maxXRotation // 根據(jù)鼠標(biāo)在 Y 軸上的位置計算繞 X 軸的旋轉(zhuǎn)角度
            const rotateY = -1 * ((offsetX - rangeX) / rangeX) * maxYRotation // 根據(jù)鼠標(biāo)在 X 軸上的位置計算繞 Y 軸的旋轉(zhuǎn)角度

            cardRef.current.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)` //設(shè)置3D透視
          }
        }}
        onMouseLeave={() => {
          // 離開盒子隱藏光源
          setIsShowLight(false)
        }}
        ref={cardRef}
        style={{
          willChange: 'transform',
          transform:
            'perspective(1000px) rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1)'
        }}
      >
        <div
          className={`${
            isShowLight ? '' : 'hidden'
          } absolute h-[200px] w-[200px] rounded-full bg-[#ff4132] blur-[150px] filter`}
          ref={lightRef}
          style={pos}
        ></div>
      </div>
      <div className="w-[400px] h-[400px] flex-center flex-col rounded-lg border border-[rgba(255,255,255,0.1)] bg-[#1C1C1F] relative"></div>
      <div className="w-[400px] h-[400px] flex-center flex-col rounded-lg border border-[rgba(255,255,255,0.1)] bg-[#1C1C1F] relative"></div>
    </main>
  )
}

封裝成好用的 Hook

聰明的你肯定看到了只實(shí)現(xiàn)了一個盒子,如果頁面很多盒子的時候怎么辦,所以還是要封裝個Hook來邏輯復(fù)用

然后統(tǒng)一的光源有點(diǎn)丑,所以設(shè)置個不同的光源

'use client'

import { useRef, useState, useEffect } from 'react'

const useCardAnimation = () => {
  const cardRef = (useRef < HTMLDivElement) | (null > null) // 卡片
  const lightRef = (useRef < HTMLDivElement) | (null > null) // 光源
  const [isShowLight, setIsShowLight] = useState(false) // 是否顯示光源
  const [pos, setPos] = useState({ left: '0px', top: '0px' }) // 光源位置

  useEffect(() => {
    const handleMouseMove = (e: MouseEvent) => {
      if (cardRef.current) {
        setIsShowLight(true) // 進(jìn)入盒子顯示光源

        const { x, y } = cardRef.current.getBoundingClientRect() // 父元素相對于頁面窗口
        const { clientX, clientY } = e // 鼠標(biāo)在頁面位置

        const offsetX = clientX - x // 計算鼠標(biāo)在盒子內(nèi)的水平偏移量
        const offsetY = clientY - y // 計算鼠標(biāo)在盒子內(nèi)的垂直偏移量

        setPos({
          left: offsetX - 100 + 'px', // 100為光源寬度的1/2
          top: offsetY - 100 + 'px' // 100為光源高度的1/2
        })

        const maxXRotation = 5 // 最大繞 X 軸旋轉(zhuǎn)角度
        const maxYRotation = 5 // 最大繞 Y 軸旋轉(zhuǎn)角度

        const rangeX = 400 / 2 // X 軸旋轉(zhuǎn)范圍
        const rangeY = 400 / 2 // Y 軸旋轉(zhuǎn)范圍

        const rotateX = ((offsetY - rangeY) / rangeY) * maxXRotation // 根據(jù)鼠標(biāo)在 Y 軸上的位置計算繞 X 軸的旋轉(zhuǎn)角度
        const rotateY = -1 * ((offsetX - rangeX) / rangeX) * maxYRotation // 根據(jù)鼠標(biāo)在 X 軸上的位置計算繞 Y 軸的旋轉(zhuǎn)角度

        cardRef.current.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)` // 設(shè)置3D透視
      }
    }

    const handleMouseLeave = () => {
      setIsShowLight(false) // 離開盒子隱藏光源
      if (cardRef.current) {
        cardRef.current.style.transform = `perspective(1000px) rotateX(0deg) rotateY(0deg)` // 設(shè)置3D透視
      }
    }

    cardRef.current?.addEventListener('mousemove', handleMouseMove)
    cardRef.current?.addEventListener('mouseleave', handleMouseLeave)

    return () => {
      cardRef.current?.removeEventListener('mousemove', handleMouseMove)
      cardRef.current?.removeEventListener('mouseleave', handleMouseLeave)
    }
  }, [])

  return { cardRef, lightRef, isShowLight, pos }
}

export default function Home() {
  const {
    cardRef: cardRef1,
    lightRef: lightRef1,
    isShowLight: isShowLight1,
    pos: pos1
  } = useCardAnimation()
  const {
    cardRef: cardRef2,
    lightRef: lightRef2,
    isShowLight: isShowLight2,
    pos: pos2
  } = useCardAnimation()
  const {
    cardRef: cardRef3,
    lightRef: lightRef3,
    isShowLight: isShowLight3,
    pos: pos3
  } = useCardAnimation()

  return (
    <main className="h-screen p-24 flex justify-center items-center bg-black gap-5">
      <div
        className="w-[400px] h-[400px] flex-center flex-col rounded-lg border border-[rgba(255,255,255,0.1)] bg-[#1C1C1F] relative overflow-hidden"
        ref={cardRef1}
        style={{
          willChange: 'transform',
          transform:
            'perspective(1000px) rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1)'
        }}
      >
        <div
          className={`${
            isShowLight1 ? '' : 'hidden'
          } absolute h-[200px] w-[200px] rounded-full bg-[#ff4132] blur-[150px] filter`}
          ref={lightRef1}
          style={pos1}
        ></div>
      </div>
      <div
        className="w-[400px] h-[400px] flex-center flex-col rounded-lg border border-[rgba(255,255,255,0.1)] bg-[#1C1C1F] relative overflow-hidden"
        ref={cardRef2}
        style={{
          willChange: 'transform',
          transform:
            'perspective(1000px) rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1)'
        }}
      >
        <div
          className={`${
            isShowLight2 ? '' : 'hidden'
          } absolute h-[200px] w-[200px] rounded-full bg-[#f9b613] blur-[150px] filter`}
          ref={lightRef2}
          style={pos2}
        ></div>
      </div>
      <div
        className="w-[400px] h-[400px] flex-center flex-col rounded-lg border border-[rgba(255,255,255,0.1)] bg-[#1C1C1F] relative overflow-hidden"
        ref={cardRef3}
        style={{
          willChange: 'transform',
          transform:
            'perspective(1000px) rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1)'
        }}
      >
        <div
          className={`${
            isShowLight3 ? '' : 'hidden'
          } absolute h-[200px] w-[200px] rounded-full bg-[#3191f7] blur-[150px] filter`}
          ref={lightRef3}
          style={pos3}
        ></div>
      </div>
    </main>
  )
}

以上就是基于Vue開發(fā)一個很火的卡片動畫效果的詳細(xì)內(nèi)容,更多關(guān)于Vue卡片動畫效果的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue中Quill富文本編輯器的使用教程

    Vue中Quill富文本編輯器的使用教程

    這篇文章主要介紹了Vue中Quill富文本編輯器的使用教程,包括自定義工具欄、自定義字體選項、圖片拖拽上傳、圖片改變大小等使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • vue?perfect-scrollbar(特定框架里使用非該框架定制庫/插件)

    vue?perfect-scrollbar(特定框架里使用非該框架定制庫/插件)

    這篇文章主要為大家介紹了vue?perfect-scrollbar在特定框架里使用一款并非為該框架定制的庫/插件如何實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>
    2023-05-05
  • vue2.6.10+vite2開啟template模板動態(tài)編譯的過程

    vue2.6.10+vite2開啟template模板動態(tài)編譯的過程

    這篇文章主要介紹了vue2.6.10+vite2開啟template模板動態(tài)編譯,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-02-02
  • vue 自定指令生成uuid滾動監(jiān)聽達(dá)到tab表格吸頂效果的代碼

    vue 自定指令生成uuid滾動監(jiān)聽達(dá)到tab表格吸頂效果的代碼

    這篇文章主要介紹了vue 自定指令生成uuid滾動監(jiān)聽達(dá)到tab表格吸頂效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • Vue中實(shí)現(xiàn)路由跳轉(zhuǎn)的三種方式(超詳細(xì)整理)

    Vue中實(shí)現(xiàn)路由跳轉(zhuǎn)的三種方式(超詳細(xì)整理)

    這篇文章給大家詳細(xì)的整理了Vue中實(shí)現(xiàn)路由跳轉(zhuǎn)的三種方式,使用vue-router,聲明式-router-link,編程式這三種方法,分別有詳細(xì)的代碼示例,需要的朋友可以參考下
    2023-09-09
  • 詳解vuex中mutations方法的使用與實(shí)現(xiàn)

    詳解vuex中mutations方法的使用與實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了vuex中mutations方法的使用與實(shí)現(xiàn)的相關(guān)知識,文中的示例代碼簡潔易懂,具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-11-11
  • element step組件在另一側(cè)加時間軸顯示

    element step組件在另一側(cè)加時間軸顯示

    本文主要介紹了element step組件在另一側(cè)加時間軸顯示,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 動畫詳解Vue3的Composition?Api

    動畫詳解Vue3的Composition?Api

    為讓大家更好的理解Vue3的Composition?Api本文采用了詳細(xì)的動畫演繹,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Vue3前端與Python(Django)后端接口簡單代碼示例

    Vue3前端與Python(Django)后端接口簡單代碼示例

    這篇文章主要介紹了如何使用Django創(chuàng)建項目和應(yīng)用,配置跨域訪問,并編寫視圖和API,同時還講述了如何使用Vue3創(chuàng)建項目,編寫組件調(diào)用后端API,需要的朋友可以參考下
    2025-01-01
  • 教你三分鐘掌握Vue過濾器filters及時間戳轉(zhuǎn)換

    教你三分鐘掌握Vue過濾器filters及時間戳轉(zhuǎn)換

    這篇文章教你三分鐘掌握Vue過濾器filters及時間戳轉(zhuǎn)換,本文將結(jié)合時間戳轉(zhuǎn)換的例子帶你快速了解filters的用法,需要的朋友可以參考下
    2023-03-03

最新評論