激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - vue.js - 如何在Vue中實現Svelte的Defer Transition

如何在Vue中實現Svelte的Defer Transition

2022-02-28 16:17Jayden.李 vue.js

這篇文章主要介紹了如何在Vue中實現Svelte的Defer Transition,幫助大家更好的理解和學習使用vue,感興趣的朋友可以了解下

最近觀看了Rich Harris的<Rethinking Reactivity>視頻,驚嘆于Svelte框架的高效同時,還發現了Vue所不具備的一些關于動畫的原生支持—defer transitions.

先看看Svelte所謂的defer transition的效果吧。

如何在Vue中實現Svelte的Defer Transition

這是使用Svelte做的Todo Demo應用。整個todo分成3個部分。輸入部分,todo列表和done列表。當點擊todo列表中的條目時,相應條目會被“移動”到done列表,反之亦然。

在這里,條目從一個列表轉移到另一個列表,不是很突兀的閃現,而是非常友好地從點擊處,移動到目的地;同時,當列表中條目離開時,剩余的條目會絲滑地向上移動填補空缺的位置。在Svelte里,只需要僅僅加上幾行代碼,就能實現,對于開發者非常友好且高效。 參考如下代碼或者Svelte教程

?
1
2
3
4
5
6
7
8
9
10
{#each todos.filter(t => !t.done) as todo (todo.id)}
    <label
    in:receive="{{key: todo.id}}"
        out:send="{{key: todo.id}}"
        animate:flip>
        <input type=checkbox on:change={() => mark(todo, true)}>
            {todo.description}
            <button on:click="{() => remove(todo)}">remove</button>
    </label>
{/each}

僅僅在element上加上了in、out和animate屬性。這里,in和out各自接受框架提供的函數receive和send并且給他們提供了篩選條件。 animate屬性接收內置的flip方法。這里的flip不是翻轉,而是FLIP技術技術,vue在<transition-group>中也有用到。主要用于整體移動列表剩余條目去填補所失去元素的位置。

于是我就在想,如果是Vue的話,如何能達到相應的效果呢。 (不想看詳細說明的話,可以直接查看code pen中的代碼)

Vue原生提供了兩個組件支持動畫。transition和transition-group。由于是list的移動,所以我們這里使用transition-group。具體使用方法可以參考Vue教程Transitions & Animation。

要想達到同樣的效果,有兩大UI動畫效果要實現。

列表中條目消失時,剩余條目移動補齊空位
條目消失同時在另外一個列表插入時,條目移動
第一個需求的實現比較簡單,vue原生已經提供了良好的支持,參考Vue文檔中的List-Move-Transitions即可

為了實現第二個需求,有幾個問題必須解決:

  1. 消失條目的位置信息
  2. 插入條目的位置信息
  3. 動效開始與結束的時機

我們先看看前兩個問題的如何解決。根據文檔的介紹,transition-group提供了javascript hook。分別是:

?
1
2
3
4
5
6
7
8
9
v-on:before-enter
v-on:enter
v-on:after-enter
v-on:enter-cancelled
 
v-on:before-leave
v-on:leave
v-on:after-leave
v-on:leave-cancelled

可視化表示的話,大概是如下圖所示:

如何在Vue中實現Svelte的Defer Transition

before-enter: 用于設置插入條目的transition的初始值。此時無法獲取BoundingClientRect. enter: 動效期。此時enter鉤子函數的入參el能獲取boundingClientRect after-enter: 動效結束后的回調函數 enter-cancelled: 取消enter的鉤子

leave也是類似。

所以,我們能拿到條目元素DOMRect信息的時機只有enter和leave的時候。

這樣,我們就可以在leave時候,拿到leave條目的DOMRect數據并且保存起來。在enter的時候, 我們就能同時擁有leave條目和enter條目的位置信息了。

位置信息是拿到了,那怎么才能在條目進入的時候,有從消失條目移動過來的效果呢。(可以先想想, 再看后面的解釋)。

所以,我們想要達成移動的效果,首先需要隱藏掉leave條目元素,

?
1
2
3
4
5
6
leave(el, done) {
      console.log("before leave");
      const rect = el.getBoundingClientRect();
      sendRectMap.set(el.dataset.key, rect);
      el.style.display = "none";
},

然后給enter條目元素設定關于位置初始狀態,初始化的位置即為leave條目元素的位置,然后當transition開始生效的時候,讓其位置恢復到插入(enter)的位置。

這種方法其實就是所謂的FLIP技術。transition-group組件里也使用了這種技術來移動剩余列表填充移走條目空白。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var first = el.getBoundingClientRect();
 
// Now set the element to the last position.
el.classList.add('totes-at-the-end');
 
// Read again. This forces a sync
// layout, so be careful.
var last = el.getBoundingClientRect();
 
// You can do this for other computed
// styles as well, if needed. Just be
// sure to stick to compositor-only
// props like transform and opacity
// where possible.
var invert = first.top - last.top;
 
// Invert.
el.style.transform =
    `translateY(${invert}px)`;
 
// Wait for the next frame so we
// know all the style changes have
// taken hold.
requestAnimationFrame(function() {
 
  // Switch on animations.
  el.classList.add('animate-on-transforms');
 
  // GO GO GOOOOOO!
  el.style.transform = '';
});

那么接下來的問題就是,在什么時機去設置enter條目元素transition的初始狀態,在什么時機去設置enter條目元素transition的結束時狀態。

按照上面提到的javascript hook,我們可以在before-enter鉤子函數里設置初始狀態,接著在enter鉤子函數里設置transition結束狀態。那么,我們的初始狀態是什么呢?我們通過getBoundingClientRect,可以獲取到enter元素(后用to來標識)的DOMRect數據,包括top, left, bottom, right, width, height , x, y。 同時我們也能通過之前保存的leave位置map獲取到leave條目的位置信息(稱為from)。所以在before-enter時,我們通過計算得到的偏移量,通過translate去初始化to元素的位置。然后再在enter階段,translate其值到from, 再加上transition到css中即可。

在before-enter鉤子中:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 移動元素的標識符
const key = el.dataset.key;
// enter條目 map,注意這里,在before-enter鉤子中,
// receiveRectMap是get不到to的。需要特殊處理。后面有提及
const to = receiveRectMap.get(key);
// leave條目 map
const from = sendRectMap.get(key);
 
// 計算偏移量
const dx = from.left - to.left;
const dy = from.top - to.top;
 
// 初始化to條目的位置
el.style.transform = `translate(${dx}px, ${dy}px)`;
el.style.opacity = 0;

在enter鉤子中:

?
1
2
3
4
el.style.transition = "all 800ms";
el.style.transform = "";
el.style.opacity = 1;
el.style.display = "block";

上面的代碼中,在before-enter里面,to是通過receiveRectMap.get(key)來獲取的。但是,這時,receiveRectMap中還沒有對應key的DOMRect值。雖然,before-enter的入參是el(HTMLElement),但是該el元素的DOMRect中的所有值都為0,所以我們需要在enter方法中,把el塞入到receiveRectMap中。這樣就會有一個矛盾,那就是無法在before-enter中通過translate初始化to元素的位置了。所以,我們這里使用defer transition技術,延遲transition的發生。

我們可以在enter中使用setTimeout或者requestAnimationFrame實現defer transition,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
requestAnimationFrame(() => {
        const key = el.dataset.key;
          // 這樣,receiveRectMap中就有該key的值了。
        const to = receiveRectMap.get(key);
        const from = sendRectMap.get(key);
 
        const dx = from.left - to.left;
        const dy = from.top - to.top;
 
        // 由于我們延遲了transition的發生,
        // 所以to元素的位置其實已經到達了目的地位置,
        // 所以我們需要使用transition手動地將其過渡到from位置,這一行很重要
        el.style.transition = "all 0ms";
        el.style.transform = `translate(${dx}px, ${dy}px)`;
        
        // 初始化結束后,在下一個animation frame中,使用FLIP技術,使其移動回來。
    requestAnimationFrame(() => {
          el.style.transition = "all 800ms";
          el.style.transform = "";
          el.style.opacity = 1;
          el.style.display = "block";
        });
      });

完整代碼可以參考codepen

最后效果:

如何在Vue中實現Svelte的Defer Transition

以上就是如何在Vue中實現Svelte的Defer Transition的詳細內容,更多關于Vue 實現Svelte的Defer Transition的資料請關注服務器之家其它相關文章!

原文鏈接:https://juejin.cn/post/6949441502321836046

延伸 · 閱讀

精彩推薦
  • vue.jsVue多選列表組件深入詳解

    Vue多選列表組件深入詳解

    這篇文章主要介紹了Vue多選列表組件深入詳解,這個是vue的基本組件,有需要的同學可以研究下...

    yukiwu6752022-01-25
  • vue.jsVue2.x-使用防抖以及節流的示例

    Vue2.x-使用防抖以及節流的示例

    這篇文章主要介紹了Vue2.x-使用防抖以及節流的示例,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下...

    Kyara6372022-01-25
  • vue.js詳解vue 表單綁定與組件

    詳解vue 表單綁定與組件

    這篇文章主要介紹了vue 表單綁定與組件的相關資料,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下...

    Latteitcjz6432022-02-12
  • vue.js用vite搭建vue3應用的實現方法

    用vite搭建vue3應用的實現方法

    這篇文章主要介紹了用vite搭建vue3應用的實現方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下...

    Asiter7912022-01-22
  • vue.js梳理一下vue中的生命周期

    梳理一下vue中的生命周期

    看過很多人講vue的生命周期,但總是被繞的云里霧里,尤其是自學的同學,可能js的基礎也不是太牢固,聽起來更是吃力,那我就已個人之淺見,以大白話...

    CRMEB技術團隊7992021-12-22
  • vue.jsVue中引入svg圖標的兩種方式

    Vue中引入svg圖標的兩種方式

    這篇文章主要給大家介紹了關于Vue中引入svg圖標的兩種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的...

    十里不故夢10222021-12-31
  • vue.jsVue2.x 項目性能優化之代碼優化的實現

    Vue2.x 項目性能優化之代碼優化的實現

    這篇文章主要介紹了Vue2.x 項目性能優化之代碼優化的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    優小U9632022-02-21
  • vue.jsVue項目中實現帶參跳轉功能

    Vue項目中實現帶參跳轉功能

    最近做了一個手機端系統,其中遇到了父頁面需要攜帶參數跳轉至子頁面的問題,現已解決,下面分享一下實現過程,感興趣的朋友一起看看吧...

    YiluRen丶4302022-03-03
主站蜘蛛池模板: 性生活香蕉视频 | 国产亚洲精品久久 | 成年人黄色免费电影 | 欧美一级做性受免费大片免费 | 91短视频在线观看免费最新 | 亚洲一区二区三区视频免费 | 国产91免费看| 欧美日韩在线视频一区 | 欧美成人午夜一区二区三区 | 2021国产精品视频 | 四季久久免费一区二区三区四区 | 久久久久国产精品久久久久 | 国产精品久久久久久久久久久久午夜 | 色中色在线播放 | 国产免费最爽的乱淫视频a 午夜精品久久久久久久99热浪潮 | 久久久久久久国产视频 | 亚洲性生活视频 | 渔夫荒淫艳史 | 蜜桃av鲁一鲁一鲁一鲁 | 国产午夜电影在线观看 | 欧美黑大粗硬毛片视频 | 久久777国产线看观看精品 | 黄色片网站免费观看 | 色中射| 宅男噜噜噜66一区二区 | omofun 动漫在线观看 | 国产精品99久久久久久久女警 | 日韩激情在线视频 | 久久精品亚洲国产奇米99 | 国产69精品久久久久9999不卡免费 | 人成免费a级毛片 | 妇子乱av一区二区三区 | 午夜av男人的天堂 | 女人久久久www免费人成看片 | hd porn 4k video xhicial | 午夜视频久久 | 51色视频 | 又黄又爽免费无遮挡在线观看 | 中文字幕综合在线观看 | 中文字幕在线观看国产 | 中文字幕h |