国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁技術(shù)文章
文章詳情頁

徹底搞懂Transition內(nèi)置組件

瀏覽:7日期:2022-06-13 15:16:30
目錄前言Transition 內(nèi)置組件觸發(fā)條件再分類六個過渡時機Transition 組件 & CSS transition 屬性核心原理實現(xiàn) Transition 組件原生 DOM 如何實現(xiàn)過渡?原生 DOM 元素移動示例進場動效離場動效實現(xiàn) Transition 組件最后前言

<Transition> 作為一個 Vue 中的內(nèi)置組件,它可以將 進入動畫 和 離開動畫 應(yīng)用到通過 默認插槽 傳遞給目標元素或組件上。

也許你有在使用,但是一直不清楚它的原理或具體實現(xiàn),甚至不清楚其內(nèi)部提供的各個 class 到底怎么配合使用,想看源碼又被其中各種引入搞得七葷八素...

本篇文章就以 Transition 組件為核心,探討其核心原理的實現(xiàn),文中不會對其各個屬性再做額外解釋,畢竟這些看文檔就夠了,希望能夠給你帶來幫助!!!

Transition 內(nèi)置組件觸發(fā)條件

<Transition> 組件的 進入動畫 或 離開動畫 可通過以下的條件之一觸發(fā):

由 v-if 所觸發(fā)的切換由 v-show 所觸發(fā)的切換由特殊元素 <component name="x"> 切換的動態(tài)組件改變特殊的 key 屬性再分類

其實我們可以將以上情況進行 再分類:

組件 掛載 和 銷毀

v-if 的變化<component name="x"> 的變化key 的變化

組件 樣式 屬性 display: none | x 設(shè)置

v-show 的變化

【擴展】v-if 和 v-for 一起使用時,在 Vue2 和 Vue3 中的不同

在 Vue2 中,當它們處于同一節(jié)點時,v-for 的優(yōu)先級比 v-if 更高,即 v-if 將分別重復(fù)運行于每個 v-for 循環(huán)中,也就是 v-if 可以正常訪問 v-for 中的數(shù)據(jù)在 Vue3 中,當它們處于同一節(jié)點時,v-if 的優(yōu)先級比 v-for 更高,即此時只要 v-if 的值為 false 則 v-for 的列表就不會被渲染,也就是 v-if 不能訪問到 v-for 中的數(shù)據(jù)六個過渡時機

總結(jié)起來就分為 進入 和 離開 動畫的 初始狀態(tài)、生效狀態(tài)、結(jié)束狀態(tài),具體如下:

v-enter-from

進入 動畫的 起始狀態(tài)在元素插入之前添加,在元素插入完成后的 下一幀移除

v-enter-active

進入 動畫的 生效狀態(tài),應(yīng)用于整個進入動畫階段在元素被插入之前添加,在過渡或動畫完成之后移除這個 class 可以被用來定義進入動畫的持續(xù)時間、延遲與速度曲線類型

v-enter-to

進入 動畫的 結(jié)束狀態(tài)在元素插入完成后的下一幀被添加 (也就是 v-enter-from 被移除的同時),在過渡或動畫完成之后移除

v-leave-from

離開 動畫的 起始狀態(tài)在離開過渡效果被觸發(fā)時立即添加,在一幀后被移除

v-leave-active

離開 動畫的 生效狀態(tài),應(yīng)用于整個離開動畫階段在離開過渡效果被觸發(fā)時立即添加,在 過渡或動畫完成之后移除這個 class 可以被用來定義離開動畫的持續(xù)時間、延遲與速度曲線類型

v-leave-to

離開 動畫的 結(jié)束狀態(tài)在一個離開動畫被觸發(fā)后的 下一幀 被添加 (即 v-leave-from 被移除的同時),在 過渡或動畫完成之后移除

其中的 v 前綴是允許修改的,可以 <Transition> 組件傳一個 name 的 prop 來聲明一個過渡效果名,如下就是將 v 前綴修改為 **`modal `** 前綴:

<Transition name='modal'> ... </Transition>Transition 組件 & CSS transition 屬性

以上這個簡單的效果,核心就是兩個時機:

v-enter-active 進入動畫的 生效狀態(tài)v-leave-active 離開動畫的 生效狀態(tài)

再配合簡單的 CSS 過渡屬性就可以達到效果,代碼如下:

<template> <div class='home'> <transition name='golden'> <!-- 金子列表 --> <div v-show='show'><img :key='idx' v-for='idx in 3' src='https://www.jb51.net/assets/golden.jpg'/> </div> </transition> </div> <!-- 錢袋子 --> <img @click='show = !show' src='https://www.jb51.net/assets/purse.png' /></template><script setup lang='ts'>import { ref, computed } from 'vue'const show = ref(true)</script><style lang='less' scoped>.home { min-height: 66px;}.golden-box { transition: all 1s ease-in; .golden { width: 100px; position: fixed; transform: translate3d(0, 0, 0); transition: all .4s; &:nth-of-type(1) { left: 45%; top: 100px; } &:nth-of-type(2) { left: 54%; top: 50px; } &:nth-of-type(3) { right: 30%; top: 100px; } } &.golden-enter-active { .golden { transform: translate3d(0, 0, 0); transition-timing-function: cubic-bezier(0, 0.57, 0.44, 1.97); } .golden:nth-of-type(1) { transition-delay: 0.1s; } .golden:nth-of-type(2) { transition-delay: 0.2s; } .golden:nth-of-type(3) { transition-delay: 0.3s; } } &.golden-leave-active { .golden:nth-of-type(1) { transform: translate3d(150px, 140px, 0); transition-delay: 0.3s; } .golden:nth-of-type(2) { transform: translate3d(0, 140px, 0); transition-delay: 0.2s; } .golden:nth-of-type(3) { transform: translate3d(-100px, 140px, 0); transition-delay: 0.1s; } }}.purse { position: fixed; width: 200px; margin-top: 100px; cursor: pointer;}</style>

當然動畫的效果是多種多樣的,不僅只是局限于這一種,例如可以配合:

CSS 的 transition 過渡屬性(上述例子使用的方案)CSS 的 animation 動畫屬性

gsap 庫

核心原理

通過上述內(nèi)容其實不難發(fā)現(xiàn)其核心原理就是:

當 組件(DOM) 被 掛載 時,將過渡動效添加到該 DOM 元素上當 組件(DOM) 被 卸載 時,不是直接卸載,而是等待附加到 DOM 元素上的 動效執(zhí)行完成,然后在真正執(zhí)行卸載操作,即 延遲卸載時機

在上述的過程中,<Transition> 組件會為 目標組件/元素 通過添加不同的 class 來定義 初始、生效、結(jié)束 三個狀態(tài),當進入下一個狀態(tài)時會把上一個狀態(tài)對應(yīng)的 class 移除。

那么你可能會問了,v-show 的形式也不符合 掛載/卸載 的形式呀,畢竟它只是在修改 DOM 元素的 display: none | x 的樣式!

讓源碼中的注釋來回答:

v-if、<component name="x">、key 控制組件 顯示/隱藏 的方式是 掛載/卸載 組件,而 v-show 控制組件 顯示/隱藏 的方式是 修改/重置 display: none | x 屬性值,從本質(zhì)上看方式不同,但從結(jié)果上看都屬于控制組件的 顯示/隱藏,即功能是一致的,而這里所說的 掛載/卸載 是針對大部分情況來說的,畢竟四種觸發(fā)方式中就有三種符合此情況。

實現(xiàn) Transition 組件

所謂 Transition 組件畢竟是 Vue 的內(nèi)置組件,換句話說,組件的編寫要符合 Vue 的規(guī)范(即 聲明式寫法),但為了更好的理解核心原理,我們應(yīng)該從 原生 DOM 的過渡開始(即 命令式寫法)探討。

原生 DOM 如何實現(xiàn)過渡?

所謂的 過渡動效 本質(zhì)上就是一個 DOM 元素在 兩種狀態(tài)間的轉(zhuǎn)換,瀏覽器 會根據(jù)我們設(shè)置的過渡效果 自行完成 DOM 元素的過渡。

而 狀態(tài)的轉(zhuǎn)換 指的就是 初始化狀態(tài) 和 結(jié)束狀態(tài) 的轉(zhuǎn)換,并且配合 CSS 中的 transition 屬性就可以實現(xiàn)兩個狀態(tài)間的過渡,即 運動過程。

原生 DOM 元素移動示例

假設(shè)要為一個元素在垂直方向上添加進場動效:從 原始位置 向上移動 200px 的位置,然后在 1s 內(nèi)運動回 原始位置。

進場動效

用 CSS 描述

// 描述物體 .box { width: 100px; height: 100px; background-color: red; box-shadow: 0 0 8px; border-radius: 50%; } // 初始狀態(tài) .enter-from { transform: translateY(-200px); } // 運動過程 .enter-active { transition: transform 1s ease-in-out; } // 結(jié)束狀態(tài) .enter-to { transform: translateY(0); }

用 JavaScript 描述

// 創(chuàng)建元素const div = document.createElement('div')div.classList.add('box')// 添加 初始狀態(tài) 和 運動過程div.classList.add('enter-from')div.classList.add('enter-active')// 將元素添加到頁面上document.body.appendChild(div)// 切換元素狀態(tài)div.classList.remove('enter-from')div.classList.add('enter-to')

從 命令式編程 的步驟上來看,似乎每一步都沒有問題,但實際的過渡動畫是不會生效的,雖然在代碼中我們有 狀態(tài)的切換,但這個切換的操作對于 瀏覽器 來講是在 同一幀中進行的,所以只會渲染 最終狀態(tài),即 enter-to 類所指向的狀態(tài)。

requestAnimationFrame 實現(xiàn)下一幀的變化

window.requestAnimationFrame(callback) 會在瀏覽器在 下次重繪之前 調(diào)用指定的 回調(diào)函數(shù) 用于更新動畫。

也就是說,單個的 requestAnimationFrame() 方法是在 當前幀 中執(zhí)行的,也就是如果想要在 下一幀 中執(zhí)行就需要使用兩個 requestAnimationFrame() 方法嵌套的方式來實現(xiàn),如下:

// 嵌套的 requestAnimationFrame 實現(xiàn)在下一幀中,切換元素狀態(tài) requestAnimationFrame(() => { requestAnimationFrame(() => { div.classList.remove('enter-from'); div.classList.add('enter-to'); }); });

transitionend 事件監(jiān)聽動效結(jié)束

以上就完成元素的 進入動效,那么在動效結(jié)束之后,別忘了將原本和 進入動效 相關(guān)的 類 移除掉,可以通過 transitionend 事件 監(jiān)聽動效是否結(jié)束,如下

// 嵌套的 requestAnimationFrame 實現(xiàn)在下一幀中,切換元素狀態(tài) requestAnimationFrame(() => { requestAnimationFrame(() => { div.classList.remove('enter-from'); div.classList.add('enter-to'); // 動效結(jié)束后,移除和動效相關(guān)的類 div.addEventListener('transitionend', () => {div.classList.remove('enter-to');div.classList.remove('enter-active'); }); }); });

以上就是 進場動效 的實現(xiàn),如下:

離場動效

有了進場動效的實現(xiàn)過程,在定義 離場動效 時就可以選擇和 進場動效 相對應(yīng)的形式,即 初始狀態(tài)、過渡過程、結(jié)束狀態(tài)。

用 CSS 描述

// 初始狀態(tài) .leave-from { transform: translateY(0); } // 過渡狀態(tài) .leave-active { transition: transform 2s ease-out; } // 結(jié)束狀態(tài) .leave-to { transform: translateY(-300px); }

用 JavaScript 描述

所謂的 離場 就是指 DOM 元素 的 卸載,但因為要有離場動效要展示,所以不能直接卸載對應(yīng)的元素,而是要 等待離場動效結(jié)束之后在進行卸載。

為了直觀一些,我們可以添加一個離場的按鈕,用于觸發(fā)離場動效。

// 創(chuàng)建離場按鈕 const btn = document.createElement('button'); btn.innerText = '離場'; document.body.appendChild(btn); // 綁定事件 btn.addEventListener('click', () => { // 設(shè)置離場 初始狀態(tài) 和 運動過程 div.classList.add('leave-from'); div.classList.add('leave-active'); // 嵌套的 requestAnimationFrame 實現(xiàn)在下一幀中,切換元素狀態(tài) requestAnimationFrame(() => { requestAnimationFrame(() => {div.classList.remove('leave-from');div.classList.add('leave-to');// 動效結(jié)束后,移除和動效相關(guān)的類div.addEventListener('transitionend', () => { div.classList.remove('leave-to'); div.classList.remove('leave-active'); // 離場動效結(jié)束,移除目標元素 div.remove();}); }); }); });

離場動效,如下:

實現(xiàn) Transition 組件

以上的實現(xiàn)過程,可以將其進行抽象化為三個階段:

beforeEnterenterleave

現(xiàn)在要從 命令式編程 轉(zhuǎn)向 聲明式編程 了,因為我們要去編寫 Vue 組件 了,即基于 VNode 節(jié)點來實現(xiàn),為了和普通的 VNode 作為區(qū)分,Vue 中會為目標元素的 VNode 節(jié)點上添加 transition 屬性:

Transition 組件 本身不會渲染任何額外的內(nèi)容,它只是通過 默認插槽 讀取過渡元素,并渲染需要過渡的元素Transition 組件 作用,是在過渡元素的 VNode 節(jié)點上添加和 transition 相關(guān)的 鉤子函數(shù)<script lang='ts'>import { defineComponent } from 'vue';const nextFrame = (callback: () => unknown) => { requestAnimationFrame(() => { requestAnimationFrame(callback) })}export default defineComponent({ name: 'Transition', setup(props, { slots }) { // 返回 render 函數(shù) return () => { // 通過默認插槽,獲取目標元素 const innerVNode = (slots as any).default() // 為目標元素添加 transition 相關(guān)鉤子 innerVNode.transition = {beforeEnter(el: any) { console.log(111) // 設(shè)置 初始狀態(tài) 和 運動過程 el.classList.add('enter-from'); el.classList.add('enter-active');},enter(el: any) { // 在下一幀切換狀態(tài) nextFrame(() => { // 切換狀態(tài) el.classList.remove('enter-from'); el.classList.add('enter-to'); // 動效結(jié)束后,移除和動效相關(guān)的類 el.addEventListener('transitionend', () => { el.classList.remove('enter-to'); el.classList.remove('enter-active'); }); })},leave(el: any) { // 設(shè)置離場 初始狀態(tài) 和 運動過程 el.classList.add('leave-from'); el.classList.add('leave-active'); // 在下一幀中,切換元素狀態(tài) nextFrame(() => { // 切換元素狀態(tài) el.classList.remove('leave-from'); el.classList.add('leave-to'); // 動效結(jié)束后,移除和動效相關(guān)的類 el.addEventListener('transitionend', () => { el.classList.remove('leave-to'); el.classList.remove('leave-active'); // 離場動效結(jié)束,移除目標元素 el.remove(); }); })} } // 返回修改過的 VNode return innerVNode } }})</script>最后

從整體來看,Transition 組件 的核心并不算復(fù)雜,特別是以 命令式編程 實現(xiàn)之后,但話說回來在 Vue 源碼中實現(xiàn)的還是很全面的,比如:

提供 props 實現(xiàn)用戶自定義類名提供 內(nèi)置模式,即先進后出(in-out)、后進先出(enter-to)支持 v-show 方式觸發(fā)過渡效果

以上就是徹底搞懂Transition內(nèi)置組件的詳細內(nèi)容,更多關(guān)于Transition內(nèi)置組件的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標簽: JavaScript
相關(guān)文章:
主站蜘蛛池模板: 成人免费在线视频网 | 欧美88| 国产精品视频九九九 | 免费国产成人高清在线看软件 | 91青草久久久久久清纯 | 久久semm亚洲国产 | 有码 在线 | 综合久色| 久久久久国产一级毛片高清片 | 欧美三级美国一级 | a毛片在线 | 亚洲aⅴ男人的天堂在线观看 | 久久国产精品免费 | 性欧美高清久久久久久久 | 欧洲性大片xxxxx久久久 | a级毛片免费观看在线播放 a级毛片免费看 | 香蕉视频在线观看黄 | 九九色网站 | 模特精品一区二区三区 | 亚洲国产精品久久久久666 | 亚洲依依成人综合在线网址 | 国产精品videosse | 一区二区三区精品国产 | 国产成人午夜性a一级毛片 国产成人午夜性视频影院 国产成人香蕉久久久久 | 特级生活片 | 国产一区二区三区在线观看影院 | 亚洲深夜福利视频 | 久久只有这才是精品99 | 久久久不卡国产精品一区二区 | 91人成亚洲高清在线观看 | 欧美日韩乱国产 | 欧美一区视频 | 国产成人亚洲综合网站不卡 | 韩国免费特一级毛片 | 综合激情网站 | 国产亚洲精品成人一区看片 | 欧美zoofilia杂交videos | 欧美一区二区三区免费播放 | 国产午夜精品不卡观看 | 99久免费精品视频在线观看2 | 在线色网址 |