1. 程式人生 > >終極方案-前端元件切換樣式還原

終極方案-前端元件切換樣式還原

本文使用 Vue 做例子,其他框架或原生一樣原理

先看效果

效果

這個文章的啟發是來自這幾天跟別人討論跨平臺解決方案時候意外發現,許多多年前端經驗的跨平臺開發工程師,都在考慮元件切換引起的瞬間白屏以及元件返回,原元件顯示還原問題。

誤導思路

厲害的前端工程師總是可以解決問題,比如上面那個問題,我們拿 A、B 兩個元件做例項。

  1. 元件切換,手寫(transition)或使用 Vue-Router 來做 A、B 元件切換動畫
  2. A 切換到 B,沒有什麼問題,無外乎動畫優雅度問題
  3. B 回到 A,B 走了,沒問題,但是 A 的出現便出現了問題

A 具體出現的問題,請允許我用語言描述,因為我後面的程式碼示例並非列表型別。

場景:列表到詳情頁面,列表上百個。

  • 使用者使用滾動,到下個或下下個螢幕的列表項,點選前往詳情,詳情瀏覽完畢後,點選返回或後退到列表頁。

  • 問題出現,列表內容得重新填充,還要把列表所在的滾動位置還原。

OK,有小夥伴說,記錄下滾動的 scroll 即可。沒錯,但是如果這個頁面有很多表格(有點扯),或者有其他各種互動變化,然後返回呢?一一去記錄配置嗎?

一一配置當然沒有問題,但是工作量以及 bug 機率,嘖嘖嘖……

分析原因

原因本身就是切換層級問題,簡單來說就是:兄弟元件的切換,就是一個此消彼長的過程。

說人話!

好吧,就是說上面的 A 與 B 頁面只能存活一個的意思。

A 出現,B 就不見;同樣的,B 出現,A 頁面也就消失了。

所以,從 B 返回 A 時候,A 需要重新渲染 DOM,從而導致相關的問題,也就是說,如果 A 是個簡單頁面,就不存在這個問題了。

推出結論

  1. 層級問題
  2. 解決層級問題的方案
  3. 所謂方案就是 B 出現時候 A 不消失

明白了麼,這個原理,小夥伴。

話不多說,終於上程式碼:

Router

import Vue from 'vue'
import VueRouter from 'vue-router'
import Delegate from '../component/delegate/delegate.vue'
import Rule from '../component/rule/rule.vue'
import Rank from '../component/rank/rank.vue'
import More from '../component/more/more.vue'
import Login from '../component/login/login.vue'
import Empty from '../component/empty/empty.vue'

Vue.use(VueRouter)

export default new VueRouter({
  routes: [
    {path: '/empty', component: Empty, alias: '/'},
    {path: '//delegate', component: Delegate},
    {path: '/rule', component: Rule},
    {path: '/rank', component: Rank},
    {path: '/more', component: More},
    {path: '/login', component: Login},
  ]
})

注意幾方面東西。

  1. 斜槓代表了層級,因為我懶得寫子級 route,所以出現 //delegate 來代表子子級。
  2. empty 作用,後面說,但是這裡注意預設是 empty 即可,即 alias: '/'

animation

.push-enter {
  transform: translateX(100%);
  opacity: 0.8;
}

.push-enter-active {
  transition: all 0.3s ease;
}

.push-enter-to, .push-leave {
  transform: translateX(0);
  opacity: 1;
}

.push-leave-active {
  transition: all 0.3s ease;
}

.push-leave-to, .pop-enter {
  transform: translateX(-50%);
  opacity: 0.8; 
}

.pop-enter-active {
  transition: all 0.3s ease;
}

.pop-enter-to, .pop-leave {
  transform: translateX(0);
  opacity: 1;
}

.pop-leave-active {
  transition: all 0.3s ease;
  z-index: 999;
}

.pop-leave-to {
  transform: translateX(100%);
}

動畫效果,這裡模仿的是移動端頁面切換動畫,有移動端經驗小夥伴能看懂,就是類似 VC 與 Activity 切換那種出棧入棧效果。

但是截止位置,都沒有解決上面的問題,沒錯,重點是下面。

放置一個空的子元件在當前頁面上

說是說沒解決,實際上邏輯上已經有那個意思了,回看 Router 那裡,是不是有個 Empty,沒錯,這個就是在每個頁面都顯示出來的時候,放置在已有頁面上的一個子元件,只不過大小為 0x0,位置隨意,建議放在左上角,因為我們控制的 CSS 是修改 x 方向。

<template>
  <div id="empty"></div>
</template>

<script>
export default {

}
</script>

<style>
</style>

我這裡偷懶,所以就這樣寫了 empty.vue 了。

然後就是配置與 Empty 同級的兄弟元件了,也許你已經想到,這個兄弟元件的位置在右邊,然後在螢幕外面等著呢(儘管目前可能沒有渲染)。

所以,它的關鍵樣式(公有)是這樣的:

.page {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}

配合上面的入場動畫,就可以實現類似在右邊划進來的效果了。

這裡提一下,建議使用 absolute 來代替 fixed,雖然 fixed 看似一勞永逸,但是在不同平臺上會有不同的問題。

到這裡,基本原理說清楚了,下面簡單總結:

  1. 做的不是兄弟元件視覺切換
  2. 做的是父子級視覺切換
  3. 但是實際上依然是兄弟元件切換
  4. 一個預設的 Empty 元件放在了已有的父元件上面,大小 0x0
  5. 切換的是這個 0x0 元件與其兄弟元件變化

實際效果

全功能 Demo

體驗地址:全功能 Demo

仿寫:仿寫


Github

如果解決了你遇到的問題,請隨手丟個 star 哈。