從列表到詳情,沒你想的那麼簡單

来源:https://www.cnblogs.com/zhuanzhuanfe/archive/2017/12/28/8137503.html
-Advertisement-
Play Games

前言 本文先假設我們使用的是 vue + vuex + vue-router 的情況來展開討論,React 全家桶的情況應該類似。 在日常的前端研發中,我們經常會遇到如題的場景:比如從商品列表進入商品詳情,從訂單列表進入訂單詳情。先看一個 demo~ 看起來是不是還算絲滑流暢,跟客戶端效果較為接近~ ...


前言

本文先假設我們使用的是 vue + vuex + vue-router 的情況來展開討論,React 全家桶的情況應該類似。

在日常的前端研發中,我們經常會遇到如題的場景:比如從商品列表進入商品詳情,從訂單列表進入訂單詳情。先看一個 demo~

Alt text

看起來是不是還算絲滑流暢,跟客戶端效果較為接近~

正文開始

很多同學應該會說,這不是很容易麽,用 vue-router + transition 就好啦。

<template>
  <transition name="custom-classes-transition"
    :enter-active-class="`animated ${transitionEnter}`"
    :leave-active-class="`animated ${transitionLeave}`">
    <router-view/>
  </transition>
</template>

<script>
export default {
  data: () => ({
    transitionEnter: '',
    transitionLeave: ''
  }),
  watch: {
    '$route' (to, from) {
      const toDepth = to.path.split('/').length
      const fromDepth = from.path.split('/').length
      if (toDepth < fromDepth) {
        this.transitionEnter = 'slideInLeft'
        this.transitionLeave = 'slideOutRight'
      } else {
        this.transitionEnter = 'slideInRight'
        this.transitionLeave = 'slideOutLeft'
      }
    }
  }
}
</script>

 

如上所示,slide 的動畫使用 animated.css

<style lang='scss'>
$use-slideInLeft: true;
$use-slideInRight: true;
$use-slideOutLeft: true;
$use-slideOutRight: true;
import "node_modules/animate-sass/animate";
.animated {
  top: 0;
  width: 100%;
  height: 100%;
  animation-duration: calc(300ms);
}
.slideOutRight, .slideOutLeft {
  position: fixed;
}
</style>

 

然後定義好 router 的路徑規則,筆者採用 restful 的方式命名。

export default new Router({
  routes: [{ // 商品列表
    path: '/',
    name: 'auctionroom',
    component: () => import('app/auction-room/room/app.vue')
  }, {       // 商品詳情
    path: ':activityId',
    name: 'auctionroom-item',
    component: () => import('app/auction-room/item/app.vue')
  }]
})

 

真這麼容易就能完成需求麽?

墓碑元素和路由守衛

實際情況是,我們在進入詳情頁之前,並沒有拿到詳情的數據!一般都會選擇在 vue 組件實例生命周期的 created 鉤子,獲取對應的後端數據介面。

而這個過程跟 transition 的動畫是並行的,會出現右側頁面還未拿到數據就劃入屏幕的情況。如大家所想,我們會儘量讓數據源表現的像現實世界遇到的,比如有網路延遲等等。

在這種情況發生時,其實是需要放置一個墓碑條目占位在對應位置,等到數據取到後墓碑條目會被實際內容替代。這樣設計的原因是,我們希望墓碑元素在被實際數據替代前可以有一個漂亮的過渡,而不是出現那種生硬的或者讓人迷失的效果。

Alt text

先略這個醜陋的墓碑,實際情況的墓碑元素應該是有設計的,在很多新聞客戶端如今日頭條中會見到~

比起這一種方案,更常見的方式是在導航完成前獲取數據,使用 router 的 beforeRouteEnter 鉤子。這個方式固然不錯,但同樣有潛在的問題:

  • 在獲取數據時,用戶會停留在當前的界面,因此建議在數據獲取期間,顯示一些進度條或者別的指示。如果數據獲取失敗,同樣有必要展示一些全局的錯誤提醒。
  • 不!能!獲取組件實例 this,因為當守衛執行前,組件實例還沒被創建

vuex + keep-alive 和返回刷新

其實在渲染詳情的時候,我們在當前列表已經有了一個商品的 Collection,一般是個數組。那為什麼不能在進入詳情時,使用當前已有的數據做填充呢?詳情頁將這些數據立即渲染,然後再通過介面獲取其餘部分的數據,等完整數據獲取之後再回填到頁面上~

採用這個方案,我們必須引入 vuex , 才能在多個頁面組件之間傳遞數據(耗時<10毫秒),而無需等待網路響應(ajax耗時 > 50毫秒)。同時依賴後端介面對於列表和詳情的處理須保持一致,即詳情介面的欄位只可能 ≥ 列表介面的欄位。

這也是目前筆者使用的,代碼大致如下:

goDetail () {
  const {activityId} = this
  this.$store.commit('AUCTION_DETAIL', this.$props)
  this.$router.push({
    name: 'auctionroom-item',
    params: { activityId }})
}

 

OK,進入的邏輯兼顧了流暢的動畫同時並行了數據的非同步獲取,那麼新的問題又來了!我們需要考慮另一種情況:如果用戶在列表頁下翻了很多次,那麼進入詳情頁再返回,定位得保持不變吧,怎麼解決?

分頁VS無限滾動

關於分頁,最常見的2種模式就是頁碼分頁或使用滾動條,這塊在產品設計界也經常被拿出來討論,找了2篇人人都是產品經理的文章,有興趣的同學可以延伸閱讀。

比較簡單的結論可歸納為,頁碼則適用於那些用戶在尋找特定信息的搜索結果列表頁以及那些用戶的瀏覽記錄比較重要的場合,後者適用於向Twitter等那些用戶重在消費無限的信息流而並不常搜尋特定的信息的應用,或者說前者多見於 PC 端,後者多見於 H5 。

如果是頁碼的模式,那麼返回就不再是問題了,因為翻頁信息通常會攜帶在頁面url中,返回時我們只需要刷新當前頁面的信息就可以了。問題這次的項目是後者,產品同學無法接受進入詳情的回退讓用戶重新回頂部~

引入 keep-alive

要解決這個問題,需要使用 vue 的一個特性 keep-alive,使用原理:

  1. 包裹動態組件時會緩存組件實例,而不是銷毀
  2. keep-alive 內路由切換時會調用 activated 和 deactivated 這兩個鉤子
  3. 套在 router-view 外面,受到影響的範圍就是 router-view 裡面的路由跳轉。

註意事項:

  • 使用後會導致 created 可能不被調用,需要把一些邏輯移到 activated
  • 針對不需要保留狀態的情況,可以在 deactivated 中調用 $destroy()

返回不刷新的問題解決了,但是產品同學又帶來了新的問題,比如用戶如果在詳情頁操作了!比如從訂單列表進入詳情後,更改了訂單狀態,那麼列表頁需要刷新這一條數據。

用 vuex 同樣可以解決這個問題,在詳情頁的 deactivated 鉤子更新列表中對應的該條數據,同樣依賴後端對於詳情和列表介面描述訂單採用同樣的數據格式,代碼大致如下:

deactivated () {
  this.$store.commit('AUCTION_LIST_INDEX', this.index, this.$data)
}

 

最終效果如下:

Alt text

對於訂單這種,只有用戶自己操作的數據,用這個方式就能滿足需求。但對於商品、競拍品這類,用戶訪問時間內有大量數據更新的情況,該方案其實不太完美~

我們或許需要在列表頁中緩存當前可視區域的頁碼,可以使用 vue-scroller,然後在返回時刷新當前可視區域的數據。然而這就完了嗎?你或許還是太天真!

無盡滾動的複雜度

做過 android、ios、react-native 開發的同學或許都知道大名鼎鼎的 ListView、ScrollView、RecyclerView

或許 Web 端一般沒有類似的需求,但其實你也應該知道,DOM節點越多,記憶體占用越高。我們或許需要在可視區域內,復用列表節點,回收看不見的節點,但為了保持滾動條不因為內容回收導致的塌陷而變化, 還需要對他們做合併。

Alt text

我就不做過多的拆解,掘金上有一篇來自 Google 大神的譯文和一篇對應的引申:

  1. [譯] 無盡滾動的複雜度 -- 來自 Google 大神的拆解
  2. 設計無限滾動下拉載入,實踐高性能頁面真諦

Alt text

據文中觀察,在真正產品線上使用這項技術的還比較少。可能是因為實現複雜度和收益比並不很高。但是,淘寶移動端檢索頁面實現了類似的思想。如下圖,

Alt text

總結

借用:當你想提供一個高性能的有良好用戶體驗的功能時,可能技術上一個簡單的問題,就會演變成複雜問題的。這篇文章便是一個例證。隨著 “Progressive Web Apps” 逐漸成為移動設備的一等公民(會嗎?),高性能的良好體驗會變得越來越重要。開發者也必須持續的研究使用一些模式來應對性能約束。這些設計的基礎當然都是成熟的技術為根本。

我的看法:其實這種優化為什麼不是瀏覽器去做!?

最後做個小廣告,轉轉優品手機幫賣,讓您高價賣掉自個的舊手機~ 如果對您有幫助,還請轉發到朋友圈~

 

 如果你喜歡我們的文章,關註我們的公眾號和我們互動吧。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 0x01 先說總結: 參照https://www.cnblogs.com/jiaoxiake/p/6818786.html 最後說的步驟, 參考:https://www.52pojie.cn/thread-586058-1-1.html 通過DexExtractor將加固後的apk還原odex,拖到 ...
  • 需求: Unity3D 一般用於做游戲 而且是跨平臺的。原本設計是Android 應用端A(原生開發)進行一些業務處理,最後由A 打開Android 應用端B(Unity3D 游戲開發)進行游戲操作。 這樣導致的問題: 1、A應用打開B應用 , 數據之間的傳遞不方便 2、正常關閉,異常關閉的交互及技 ...
  • Data.parse()獲取時間戳,在Android是沒有問題的,但是在ISO就不行了,原因在於轉化成時間戳的時間格式不一樣。 Android的格式是如“2017-12-12 12:12:12”,ISO得轉化成這樣的格式才行“2017/12/12 12:12:12”; 上代碼: Android: 結 ...
  • 使用chrome瀏覽器,輸入chrome://inspect可以調試android app裡面的網頁,如果inspect的時候,是空白, 問題截圖: 那就在C:\Windows\System32\drivers\etc\hosts文件加入 61.91.161.217 chrome-devtools- ...
  • 一,Default.png 包含應用程式預設扉頁的PNG圖像文件。用戶運行應用程式時,iPhone會用此圖片顯示一個動畫,產生由小變大來到屏幕前的效果。應用程式的Default.png文件載入後會不斷變大,直到充滿整個屏幕。在應用程式完成啟動前,這個分變率大小為320*480的圖片將一直顯示在屏幕上 ...
  • 第一個section上邊多餘間距處理 每個section下邊多餘間距處理 備註:若傳入的 height == 0,則 height 被設置成預設值 若 height 小於屏幕半像素對應的高度,則不會被渲染,所以這裡返回CGFLOAT_MIN,其實返回0.01也是可以的 補充:代碼順序的不同導致第一個 ...
  • 記錄一下用得比較熟練的git命令 git clone: 克隆遠程代碼到本地,使用格式: git clone url (項目所在的遠程倉庫路徑) git clone 只是克隆master上的代碼,要想克隆其他分支的代碼,可以先使用git branch -r來查看遠程分支,再使用 git checkou ...
  • Nicescroll滾動條插件是一個非常強大的基於jQuery的滾動條插件,不需要增加額外的css,幾乎全瀏覽器相容。ie6+,實現只需要一段代碼,侵入性非常小,樣式可完全自定義,支持觸摸事件,可在觸摸屏上使用。 Nicescroll官網地址:http://www.areaaperta.com/ni ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...