歡迎光臨
每天分享高質量文章

vue中的動畫:transition元件研究(上)

logo

Transition 元件通常有三類用法:CSS 過渡,CSS 動畫和 JavaScript 鉤子。我們分別用幾個示例來說明,這裡我希望你可以敲程式碼執行感受一下。

首先來看 CSS 過渡:

<template>
    <div class="app">
        <button @click="show = !show">
            Toggle render
        </button>
        <transition name="fade">
            <p v-if="show">hello</p>
        </transition>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                show: true
            }
        }
    }
</script>

<style>
    .fade-enter-active,
    .fade-leave-active {
        transition: opacity 0.5s ease;
    }

    .fade-enter-from,
    .fade-leave-to {
        opacity: 0;
    }
</style>

CSS 過渡主要定義了一些過渡的 CSS 樣式,當我們點選按鈕切換文字顯隱的時候,就會應用這些 CSS 樣式,實現過渡效果。

接著來看 CSS 動畫:

<template>
    <div class="app">
        <button @click="show = !show">Toggle show</button>
        <transition name="bounce">
            <p v-if="show">Vue is an awesome front-end MVVM framework. We can use it to build multiple apps.</p>
        </transition>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                show: true
            }
        }
    }
</script>

<style>
    .bounce-enter-active {
        animation: bounce-in 0.5s;
    }

    .bounce-leave-active {
        animation: bounce-in 0.5s reverse;
    }

    @keyframes bounce-in {
        0% {
            transform: scale(0);
        }
        50% {
            transform: scale(1.5);
        }
        100% {
            transform: scale(1);
        }
    }
</style>

和 CSS 過渡類似,CSS 動畫主要定義了一些動畫的 CSS 樣式,當我們去點選按鈕切換文字顯隱的時候,就會應用這些 CSS 樣式,實現動畫效果。

最後,是 JavaScript 鉤子:

<template>
    <div class="app">
        <button @click="show = !show">
            Toggle render
        </button>
        <transition
            @before-enter="beforeEnter"
            @enter="enter"
            @before-leave="beforeLeave"
            @leave="leave"
            css="false"
        >
            <p v-if="show">hello</p>
        </transition>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                show: true
            }
        },
        methods: {
            beforeEnter(el) {
                el.style.opacity = 0
                el.style.transition = 'opacity 0.5s ease'
            },
            enter(el) {
                this.$el.offsetHeight
                el.style.opacity = 1
            },
            beforeLeave(el) {
                el.style.opacity = 1
            },
            leave(el) {
                el.style.transition = 'opacity 0.5s ease'
                el.style.opacity = 0
            }
        }
    }
</script>

Transition 元件也允許在一個過渡元件中定義它過渡生命週期的 JavaScript 鉤子函式,我們可以在這些鉤子函式中編寫 JavaScript 操作 DOM 來實現過渡動畫效果。

Transition 元件的核心思想

透過前面三個示例,我們不難發現都是在點選按鈕時,透過修改 v-if 的條件值來觸發過渡動畫的。

其實 Transition 元件過渡動畫的觸發條件有以下四點:

  • 條件渲染 (使用 v-if);
  • 條件展示 (使用 v-show);
  • 動態元件;
  • 元件根節點。

所以你只能在上述四種情況中使用 Transition 元件,在進入/離開過渡的時候會有 6 個 class 切換。

  • v-enter-from:定義進入過渡的開始狀態。在元素被插入之前生效,在元素被插入之後的下一幀移除。
  • v-enter-active:定義進入過渡生效時的狀態。在整個進入過渡的階段中應用,在元素被插入之前生效,在過渡動畫完成之後移除。這個類可以被用來定義進入過渡的過程時間,延遲和曲線函式。
  • v-enter-to:定義進入過渡的結束狀態。在元素被插入之後下一幀生效 (與此同時 v-enter-from 被移除),在過渡動畫完成之後移除。
  • v-leave-from:定義離開過渡的開始狀態。在離開過渡被觸發時立刻生效,下一幀被移除。
  • v-leave-active:定義離開過渡生效時的狀態。在整個離開過渡的階段中應用,在離開過渡被觸發時立刻生效,在過渡動畫完成之後移除。這個類可以被用來定義離開過渡的過程時間,延遲和曲線函式。
  • v-leave-to:定義離開過渡的結束狀態。在離開過渡被觸發之後下一幀生效 (與此同時 v-leave-from 被刪除),在過渡動畫完成之後移除。

其實說白了 Transition 元件的核心思想就是,Transition 包裹的元素插入刪除時,在適當的時機插入這些 CSS 樣式,而這些 CSS 的實現則決定了元素的過渡動畫。

大致瞭解了 Transition 元件的用法和核心思想後,接下來我們就來探究 Transition 元件的實現原理。

Transition 元件的實現原理

為了方便你的理解,我們還是結合示例來分析:

<template>
    <div class="app">
        <button @click="show = !show">
            Toggle render
        </button>
        <transition name="fade">
            <p v-if="show">hello</p>
        </transition>
    </div>
</template>

先來看模板編譯後生成的 render 函式:

import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock, createCommentVNode as _createCommentVNode, Transition as _Transition, withCtx as _withCtx } from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
    return (_openBlock(), _createBlock("template", null, [
        _createVNode("div", { class: "app" }, [
            _createVNode("button", {
                onClick: $event => (_ctx.show = !_ctx.show)
            }, " Toggle render ", 8 /* PROPS */, ["onClick"]),
            _createVNode(_Transition, { name: "fade" }, {
                default: _withCtx(() => [
                    (_ctx.show)
                        ? (_openBlock(), _createBlock("p", { key: 0 }, "hello"))
                        : _createCommentVNode("v-if", true)
                    ]),
                _: 1
            })
        ])
    ]))
}

對於 Transition 元件部分,生成的 render 函式主要建立了Transition 元件 vnode,並且有一個預設插槽。

如果你仔細研究transition的實現你會發現,Transition 元件是在 BaseTransition 的基礎上封裝的高階函式式元件。由於整個 Transition 的實現程式碼較多,我就挑重點,為你講清楚整體的實現思路。

Transition 元件的實現其實可以分成元件的渲染、鉤子函式的執行、模式的應用三個部分看待。

其中最重要的就是元件的渲染:我們應當重點看 setup 函式部分的邏輯。

Transition 元件和前面學習的 KeepAlive 元件一樣,是一個抽象元件,元件本身不渲染任何實體節點,只渲染第一個子元素節點。

注意,Transition 元件內部只能巢狀一個子元素節點,如果有多個節點需要用 TransitionGroup 元件。

如果 Transition 元件內部巢狀的是 KeepAlive 元件,那麼它會繼續查詢 KeepAlive 元件巢狀的第一個子元素節點,來作為渲染的元素節點。

如果 Transition 元件內部沒有巢狀任何子節點,那麼它會渲染空的註釋節點。

在渲染的過程中,Transition 元件還會透過 resolveTransitionHooks 去定義元件建立和刪除階段的鉤子函式物件,然後再透過 setTransitionHooks函式去把這個鉤子函式物件設定到 vnode.transition 上。

渲染過程中,還會判斷這是否是一次更新渲染,如果是會對不同的模式執行不同的處理邏輯,我會在後續介紹模式的應用時詳細說明。

以上就是 Transition 元件渲染做的事情,你需要記住的是Transition 渲染的是元件巢狀的第一個子元素節點!

贊(0)

評論 搶沙發

  • 暱稱 (必填)
  • 郵箱 (必填)
  • 網址

分享創造快樂