最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何在Vue中實現(xiàn)Svelte的Defer Transition

 更新時間:2021年04月12日 09:50:13   作者:Jayden.李  
這篇文章主要介紹了如何在Vue中實現(xiàn)Svelte的Defer Transition,幫助大家更好的理解和學(xué)習(xí)使用vue,感興趣的朋友可以了解下

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

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

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

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

{#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各自接受框架提供的函數(shù)receive和send并且給他們提供了篩選條件。 animate屬性接收內(nèi)置的flip方法。這里的flip不是翻轉(zhuǎn),而是FLIP技術(shù)技術(shù),vue在<transition-group>中也有用到。主要用于整體移動列表剩余條目去填補所失去元素的位置。

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

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

要想達(dá)到同樣的效果,有兩大UI動畫效果要實現(xiàn)。

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

為了實現(xiàn)第二個需求,有幾個問題必須解決:

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

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

 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

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

before-enter: 用于設(shè)置插入條目的transition的初始值。此時無法獲取BoundingClientRect. enter: 動效期。此時enter鉤子函數(shù)的入?yún)l能獲取boundingClientRect after-enter: 動效結(jié)束后的回調(diào)函數(shù) enter-cancelled: 取消enter的鉤子

leave也是類似。

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

這樣,我們就可以在leave時候,拿到leave條目的DOMRect數(shù)據(jù)并且保存起來。在enter的時候, 我們就能同時擁有l(wèi)eave條目和enter條目的位置信息了。

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

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

leave(el, done) {
      console.log("before leave");
      const rect = el.getBoundingClientRect();
      sendRectMap.set(el.dataset.key, rect);
      el.style.display = "none";
},

然后給enter條目元素設(shè)定關(guān)于位置初始狀態(tài),初始化的位置即為leave條目元素的位置,然后當(dāng)transition開始生效的時候,讓其位置恢復(fù)到插入(enter)的位置。

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

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 = '';
});

那么接下來的問題就是,在什么時機去設(shè)置enter條目元素transition的初始狀態(tài),在什么時機去設(shè)置enter條目元素transition的結(jié)束時狀態(tài)。

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

在before-enter鉤子中:

        // 移動元素的標(biāo)識符
        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鉤子中:

        el.style.transition = "all 800ms";
        el.style.transform = "";
        el.style.opacity = 1;
        el.style.display = "block";

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

我們可以在enter中使用setTimeout或者requestAnimationFrame實現(xiàn)defer transition,

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的發(fā)生,
        // 所以to元素的位置其實已經(jīng)到達(dá)了目的地位置,
        // 所以我們需要使用transition手動地將其過渡到from位置,這一行很重要
        el.style.transition = "all 0ms";
        el.style.transform = `translate(${dx}px, ${dy}px)`;
        
        // 初始化結(jié)束后,在下一個animation frame中,使用FLIP技術(shù),使其移動回來。
	requestAnimationFrame(() => {
          el.style.transition = "all 800ms";
          el.style.transform = "";
          el.style.opacity = 1;
          el.style.display = "block";
        });
      });

完整代碼可以參考codepen

最后效果:

以上就是如何在Vue中實現(xiàn)Svelte的Defer Transition的詳細(xì)內(nèi)容,更多關(guān)于Vue 實現(xiàn)Svelte的Defer Transition的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 一文快速學(xué)會阻止事件冒泡的4種方法(原生js阻止,vue中使用修飾符阻止)

    一文快速學(xué)會阻止事件冒泡的4種方法(原生js阻止,vue中使用修飾符阻止)

    冒泡就是事件開始是由最具體的元素接收,然后逐層向上級傳播到較為不具體的元素,這篇文章主要給大家介紹了關(guān)于阻止事件冒泡的4種方法,文中介紹的方法分別是原生js阻止以及vue中使用修飾符阻止的相關(guān)資料,需要的朋友可以參考下
    2023-12-12
  • Vue.js bootstrap前端實現(xiàn)分頁和排序

    Vue.js bootstrap前端實現(xiàn)分頁和排序

    這篇文章主要為大家詳細(xì)介紹了Vue.js結(jié)合bootstrap前端實現(xiàn)分頁和排序效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • vue實現(xiàn)本地存儲添加刪除修改功能

    vue實現(xiàn)本地存儲添加刪除修改功能

    這篇文章主要為大家詳細(xì)介紹了vue實現(xiàn)本地存儲添加刪除修改功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 如何使用vue自定義指令構(gòu)建拖放插件

    如何使用vue自定義指令構(gòu)建拖放插件

    這篇文章主要介紹了如何使用vue自定義指令構(gòu)建拖放插件,幫助大家更好的理解和學(xué)習(xí)使用vue,感興趣的朋友可以了解下
    2021-04-04
  • Vue的elementUI實現(xiàn)自定義主題方法

    Vue的elementUI實現(xiàn)自定義主題方法

    下面小編就為大家分享一篇Vue的elementUI實現(xiàn)自定義主題方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02
  • Vue-Cli配置代理轉(zhuǎn)發(fā)解決跨域問題的方法

    Vue-Cli配置代理轉(zhuǎn)發(fā)解決跨域問題的方法

    本文主要介紹了Vue-Cli配置代理轉(zhuǎn)發(fā)解決跨域問題的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • vue.js父子組件通信動態(tài)綁定的實例

    vue.js父子組件通信動態(tài)綁定的實例

    今天小編就為大家分享一篇vue.js父子組件通信動態(tài)綁定的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • WEB前端性能優(yōu)化的7大手段詳解

    WEB前端性能優(yōu)化的7大手段詳解

    本文將詳細(xì)介紹前端性能優(yōu)化的7大手段,包括減少請求數(shù)量、減小資源大小、優(yōu)化網(wǎng)絡(luò)連接、優(yōu)化資源加載、減少重繪回流、使用性能更好的API和構(gòu)建優(yōu)化
    2020-02-02
  • Vue 項目中如何使用fullcalendar 時間段選擇插件(類似課程表格)

    Vue 項目中如何使用fullcalendar 時間段選擇插件(類似課程表格)

    最近完成一個項目,需要選擇一個會議室,但是最好能夠通過在圖上顯示出該 會議室在某某時間段內(nèi)已經(jīng)被預(yù)定了,初看這個功能感覺很棘手,仔細(xì)分析下實現(xiàn)起來還是挺容易的,下面通過示例代碼講解Vue項目中使用fullcalendar時間段選擇插件,感興趣的朋友一起看看吧
    2024-07-07
  • Vue-CLI 3 scp2自動部署項目至服務(wù)器的方法

    Vue-CLI 3 scp2自動部署項目至服務(wù)器的方法

    這篇文章主要介紹了Vue-CLI 3 scp2自動部署項目至服務(wù)器的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07

最新評論

天水市| 建阳市| 贵港市| 香河县| 秀山| 新和县| 建始县| 府谷县| 怀集县| 辰溪县| 保山市| 九龙坡区| 新邵县| 溧阳市| 汉源县| 慈利县| 灌南县| 郸城县| 佛坪县| 韶关市| 彰武县| 汤原县| 佛冈县| 樟树市| 观塘区| 阜宁县| 仁怀市| 剑河县| 西丰县| 遂宁市| 克拉玛依市| 佳木斯市| 友谊县| 白玉县| 玛沁县| 二连浩特市| 香港| 花垣县| 漳浦县| 湛江市| 丰顺县|