AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

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

Vue3 實現最近很火的酷炫功能:卡片懸浮發光

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

有趣的動畫效果

前幾天在網上看到了一個很有趣的動畫效果,如下,光會跟隨鼠標在卡片上進行移動,并且卡片會有視差的效果。rIC28資訊網——每日最新資訊28at.com

那么在 Vue3 中應該如何去實現這個效果呢?rIC28資訊網——每日最新資訊28at.com

圖片圖片rIC28資訊網——每日最新資訊28at.com

基本實現思路

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

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

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

圖片圖片rIC28資訊網——每日最新資訊28at.com

可以看到現在的效果是這樣:rIC28資訊網——每日最新資訊28at.com

圖片圖片rIC28資訊網——每日最新資訊28at.com

實現光源跟隨鼠標

在實現之前我們需要注意幾點:rIC28資訊網——每日最新資訊28at.com

1、鼠標移入時需要設置卡片 overflow: hidden,否則光會溢出,而鼠標移出時記得還原。rIC28資訊網——每日最新資訊28at.com

2、獲取鼠標坐標時需要用clientX/Y而不是pageX/Y,因為前者會把頁面滾動距離也算進去,比較嚴謹。rIC28資訊網——每日最新資訊28at.com

剛剛說到實現思路時我們說到了mouseenter、mousemove、mouseleave,其實mouseenter、mouseleave 這二者的邏輯比較簡單,重點是 mouseover 這個監聽函數。rIC28資訊網——每日最新資訊28at.com

而在 mouseover 這個函數中,最重要的邏輯就是:光怎么跟隨鼠標移動呢?rIC28資訊網——每日最新資訊28at.com

或者也可以這么說:怎么計算光相對于卡片盒子的 left 和 top。rIC28資訊網——每日最新資訊28at.com

對此我專門畫了一張圖,相信大家一看就懂怎么算了。rIC28資訊網——每日最新資訊28at.com

圖片圖片rIC28資訊網——每日最新資訊28at.com

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

知道了怎么計算,那么邏輯的實現也很明了了~封裝一個use-light-card.ts:rIC28資訊網——每日最新資訊28at.com

圖片圖片rIC28資訊網——每日最新資訊28at.com

接著在頁面中去使用:rIC28資訊網——每日最新資訊28at.com

圖片圖片rIC28資訊網——每日最新資訊28at.com

這樣就能實現基本的效果啦~rIC28資訊網——每日最新資訊28at.com

圖片圖片rIC28資訊網——每日最新資訊28at.com

卡片視差效果

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

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

圖片圖片rIC28資訊網——每日最新資訊28at.com

現在就有了卡片視差的效果啦~rIC28資訊網——每日最新資訊28at.com

圖片圖片rIC28資訊網——每日最新資訊28at.com

給所有卡片添加光源

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

圖片圖片rIC28資訊網——每日最新資訊28at.com

圖片圖片rIC28資訊網——每日最新資訊28at.com

讓光源變成可配置

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

圖片圖片rIC28資訊網——每日最新資訊28at.com

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

圖片rIC28資訊網——每日最新資訊28at.com

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

圖片圖片rIC28資訊網——每日最新資訊28at.com

完整源碼

<!-- Index.vue --><template>  <div class="container">    <!-- 方塊盒子 -->    <div class="item" ref="cardRef1"></div>    <!-- 方塊盒子 -->    <div class="item" ref="cardRef2"></div>    <!-- 方塊盒子 -->    <div class="item" ref="cardRef3"></div>  </div></template><script setup lang="ts">import { useLightCard } from './use-light-card';const { cardRef: cardRef1 } = useLightCard();const { cardRef: cardRef2 } = useLightCard({  light: {    color: '#ffffff',    width: 100,  },});const { cardRef: cardRef3 } = useLightCard({  light: {    color: 'yellow',  },});</script><style scoped lang="less">.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);  }}</style>
// use-light-card.tsimport { onMounted, onUnmounted, ref } from 'vue';interface IOptions {  light?: {    width?: number; // 寬    height?: number; // 高    color?: string; // 顏色    blur?: number; // filter: blur()  };}export const useLightCard = (option: IOptions = {}) => {  // 獲取卡片的dom節點  const cardRef = ref<HTMLDivElement | null>(null);  let cardOverflow = '';  // 光的dom節點  const lightRef = ref<HTMLDivElement>(document.createElement('div'));  // 設置光源的樣式  const setLightStyle = () => {    const { width = 60, height = 60, color = '#ff4132', blur = 40 } = option.light ?? {};    const lightDom = lightRef.value;    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.value;    if (cardDom) {      cardOverflow = cardDom.style.overflow;      cardDom.style.overflow = 'hidden';    }  };  // 還原卡片的 overflow  const restoreCardOverflow = () => {    const cardDom = cardRef.value;    if (cardDom) {      cardDom.style.overflow = cardOverflow;    }  };  // 往卡片添加光源  const addLight = () => {    const cardDom = cardRef.value;    if (cardDom) {      cardDom.appendChild(lightRef.value);    }  };  // 刪除光源  const removeLight = () => {    const cardDom = cardRef.value;    if (cardDom) {      cardDom.removeChild(lightRef.value);    }  };  // 監聽卡片的鼠標移入  const onMouseEnter = () => {    // 添加光源    addLight();    setCardOverflowHidden();  };  // use-light-card.ts  // 監聽卡片的鼠標移動  const onMouseMove = (e: MouseEvent) => {    // 獲取鼠標的坐標    const { clientX, clientY } = e;    // 讓光跟隨鼠標    const cardDom = cardRef.value;    const lightDom = lightRef.value;    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();  };  onMounted(() => {    // 設置光源樣式    setLightStyle();    // 綁定事件    cardRef.value?.addEventListener('mouseenter', onMouseEnter);    cardRef.value?.addEventListener('mousemove', onMouseMove);    cardRef.value?.addEventListener('mouseleave', onMouseLeave);  });  onUnmounted(() => {    // 解綁事件    cardRef.value?.removeEventListener('mouseenter', onMouseEnter);    cardRef.value?.removeEventListener('mousemove', onMouseMove);    cardRef.value?.removeEventListener('mouseleave', onMouseLeave);  });  return {    cardRef,  };};

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

本文鏈接:http://www.tebozhan.com/showinfo-26-90040-0.htmlVue3 實現最近很火的酷炫功能:卡片懸浮發光

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

上一篇: Python 并發編程的 12 個實用技巧

下一篇: ViewRootImpl如何負責管理繪制視圖樹和刷新界面

標簽:
  • 熱門焦點
  • 小米官宣:2023年上半年出貨量中國第一!

    今日早間,小米電視官方微博帶來消息,稱2023年小米電視上半年出貨量達到了中國第一,同時還表示小米電視的巨屏風暴即將開始。“公布一個好消息2023年#小米電視上半年出貨量中國
  • Redmi Buds 4開箱簡評:才199還有降噪 可以無腦入

    在上個月舉辦的Redmi Note11T Pro系列新機發布會上,除了兩款手機新品之外,Redmi還帶來了兩款TWS真無線藍牙耳機產品,Redmi Buds 4和Redmi Buds 4 Pro,此前我們在Redmi Note11T
  • 企業采用CRM系統的11個好處

    客戶關系管理(CRM)軟件可以為企業提供很多的好處,從客戶保留到提高生產力。  CRM軟件用于企業收集客戶互動,以改善客戶體驗和滿意度。  CRM軟件市場規模如今超過580
  • 讓我們一起聊聊文件的操作

    文件【1】文件是什么?文件是保存數據的地方,是數據源的一種,比如大家經常使用的word文檔、txt文件、excel文件、jpg文件...都是文件。文件最主要的作用就是保存數據,它既可以保
  • 使用Webdriver-manager解決瀏覽器與驅動不匹配所帶來自動化無法執行的問題

    1、前言在我們使用 Selenium 進行 UI 自動化測試時,常常會因為瀏覽器驅動與瀏覽器版本不匹配,而導致自動化測試無法執行,需要手動去下載對應的驅動版本,并替換原有的驅動,可能還
  • 三分鐘白話RocketMQ系列—— 如何發送消息

    我們知道RocketMQ主要分為消息 生產、存儲(消息堆積)、消費 三大塊領域。那接下來,我們白話一下,RocketMQ是如何發送消息的,揭秘消息生產全過程。注意,如果白話中不小心提到相關代
  • 2023年,我眼中的字節跳動

    此時此刻(2023年7月),字節跳動從未上市,也從未公布過任何官方的上市計劃;但是這并不妨礙它成為中國最受關注的互聯網公司之一。從2016-17年的抖音強勢崛起,到2018年的&ldquo;頭騰
  • OPPO K11評測:旗艦級IMX890加持 2000元檔最強影像手機

    【Techweb評測】中端機型用戶群體巨大,占了中國目前手機市場的大頭,一直以來都是各手機品牌的“必爭之地”,其中OPPO K系列機型一直以來都以高品質、
  • 與兆芯合作 聯想推出全新旗艦版筆記本電腦開天N7系列

    聯想與兆芯合作推出全新聯想旗艦版筆記本電腦開天 N7系列。這個系列采用兆芯KX-6640MA處理器平臺,KX-6640MA 處理器是采用了陸家嘴架構,16nm 工藝,4 核 4 線
Top