記錄--這樣封裝列表 hooks,一天可以開發 20 個頁面

来源:https://www.cnblogs.com/smileZAZ/archive/2023/01/30/17076271.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 這樣封裝列表 hooks,一天可以開發 20 個頁面 前言 在做移動端的需求時,我們經常會開發一些列表頁,這些列表頁大多數有著相似的功能:分頁獲取列表、上拉載入、下拉刷新··· 在 Vue 出來 compositionAPI 之前,我們想 ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

這樣封裝列表 hooks,一天可以開發 20 個頁面

前言

在做移動端的需求時,我們經常會開發一些列表頁,這些列表頁大多數有著相似的功能:分頁獲取列表、上拉載入、下拉刷新···

Vue 出來 compositionAPI 之前,我們想要復用這樣的邏輯還是比較麻煩的,好在現在 Vue2.7+都支持 compositionAPI語法了,這篇文章我將 手把手帶你用 compositionAPI 封裝一個名為 useList hooks來實現列表頁的邏輯復用。

基礎版

需求分析

一個列表,最基本的需求應該包括: 發起請求,獲取到列表的數組,然後將該數組渲染成相應的 DOM 節點。要實現這個功能,我們需要以下變數:

  • list : 數組變數,用來存放後端返回的數據,併在 template模板中使用 v-for來遍歷渲染成我們想要的樣子。
  • listReq: 發起 http 請求的函數,一般是 axios的實例

代碼實現

有了上面的分析,我們可以很輕鬆地在 setup中寫出如下代碼:

import { ref } from 'vue'
import axios from 'axios' // 簡單示例,就不給出封裝axios的代碼了

const list = ref([])

const listReq = () => {
  axios.get('/url/to/getList').then((res) => {
    list.value = res.list
  })
}

listReq()

這樣,我們就完成了一個基本的列表需求的邏輯部分。大部分的列表需求都是類似的邏輯,既然如此,Don't Repeat Yourself!(不要重覆寫你的代碼!),我們來把它封裝成通用的方法:

  • 首先,既然是通用的,會在多個地方使用,那麼數據肯定不能亂了,我們要在每次使用 useList的時候都拿到獨屬於自己的那一份數據。是不是感覺很熟悉?對的,就是以前的 data為什麼是一個函數那個問題!所以我們的 useList是需要導出一個函數,我們從這個函數中獲取數據與方法。讓這個函數導出一個對象/數組,這樣調用的時候 解構就可以拿到我們需要的變數和方法了
// useList.js 中

const useList = () => {
  // 待補充的函數體
  return {}
}

export default useList
  • 然後,不同的地方調用的介面肯定不一樣,我們想一次封裝,不再維護,那麼咱們乾脆在使用的時候,把調用介面的方法傳進來就可以了
// useList.js 中
import { ref } from 'vue'
const useList = (listReq) => {
  if (!listReq) {
    return new Error('請傳入介面調用方法!')
  }
  const list = ref([])
  const getList = () => {
    listReq().then((res) => (list.value = res.list))
  }

  return {
    list,
    getList,
  }
}

export default useList

這樣,我們就完成了一個簡單的列表 hooks,使用的時候直接:

// setup中
import useList from '@/utils'
const { list, getList } = useList(axios.get('url/to/get/list'))
getList()

等等!列表好像不涉及到 DOM操作,那咱們再偷點懶,直接在 useList內部就調用了吧!

// useList.js中
import { ref } from 'vue'
const useList = (listReq) => {
  if (!listReq) {
    return new Error('請傳入介面調用方法!')
  }
  const list = ref([])
  const getList = () => {
    listReq().then((res) => (list.value = res.list))
  }
  getList() // 直接初始化,省去在外面初始化的步驟
  return {
    list,
    getList,
  }
}

export default useList

這時有老哥要說了,那我要是一個頁面有多個列表怎麼辦?嘿嘿,別忘了,解構的時候是可以重命名的

// setup中

const { list: goodsList, getList: getGoodsList } = useList(
  axios.get('/url/get/goods')
)
const { list: recommendList, getList: getRecommendList } = useList(
  axios.get('/url/get/goods')
)

這樣,我們就同時在一個頁面裡面,獲取到了商品列表以及推薦列表所需要的變數與方法啦

帶分頁版

如果數據量比較大的話,所有的數據全部拿出來渲染顯然不合理,所以我們一般要進行分頁處理,我們來分析一下這個需求:

需求分析

  • 要分頁,那咱們肯定要告訴後端當前請求的是第幾頁、每頁多少條,可能有些地方還需要展示總共有多少條,為了方便管理,咱們把這些分頁數據統一放到 pageInfo對象中
  • 分頁了,那咱們肯定還有載入下一頁的需求,需要一個 loadmore函數
  • 分頁了,那咱們肯定還會有刷新的需求,需要一個 initList函數

代碼實現

需求分析好了,代碼實現起來就簡單了,廢話少說,上代碼!

// useList.js中
import { ref } from 'vue'
const useList = (listReq) => {
  if (!listReq) {
    return new Error('請傳入介面調用方法!')
  }
  const list = ref([])

  // 新增pageInfo對象保存分頁數據
  const pageInfo = ref({
    pageNum: 1,
    pageSize: 10,
    total: 0,
  })
  const getList = () => {
    // 分頁數據作為參數傳遞給介面調用函數即可
    // 將請求這個Promise返回出去,以便鏈式then
    return listReq(pageInfo.value).then((res) => {
      list.value = res.list
      // 更新總數量
      pageInfo.value.total = res.total
      // 返回出去,交給then預設的Promise,以便後續使用
      return res
    })
  }

  // 新增載入下一頁的函數
  const loadmore = () => {
    // 下一頁,那咱們把當前頁自增一下就行了
    pageInfo.value.pageNum += 1
    // 如果已經是最後一頁了(本次獲取到空數組)
    getList().then((res) => {
      if (!res.list.length) {
        uni.showToast({
          title: '沒有更多了',
          icon: 'none',
        })
      }
    })
  }

  // 新增初始化
  const initList = () => {
    // 初始化一般是要把所有的查詢條件都初始化,這裡只有分頁,咱就回到第一頁就行
    pageInfo.value.pageNum = 1
    getList()
  }

  getList()
  return {
    list,
    getList,
    loadmore,
    initList,
  }
}

export default useList

完工!跑起來試試,Perfec......等等,好像不太對...

載入更多,應該是把兩次請求的數據合併到一起渲染出來才對,這怎麼直接替換掉了?

回頭看看代碼,原來是咱們漏了拼接的邏輯,補上,補上

// useList.js中

// ...省略其餘代碼
const getList = () => {
  // 分頁數據作為參數傳遞給介面調用函數即可
  return listReq(pageInfo.value).then((res) => {
    // 當前頁不為1則是載入更多,需要拼接數據
    if (pageInfo.value.pageNum === 1) {
      list.value = res.list
    } else {
      list.value = [...list.value, ...res.list]
    }
    pageInfo.value.total = res.total
    return res
  })
}
// ...省略其餘代碼

帶 hooks 版

上面的分頁版,我們給出了 載入更多初始化列表功能,但是還是要手動調用。仔細想想,咱們刷新列表,一般都是在頁面頂部下拉的時候刷新的;而載入更多,一般都是在滾動到底部的時候載入的。既然都是一樣的觸發時機,那咱們繼續封裝吧!

需求分析

  • uni-app 中提供了 onPullDownRefreshonReachBottom鉤子,在其中處理相關邏輯即可
  • 有些列表可能不是在頁面中,而是在 scroll-view中,還是需要手動處理,因此上面的函數咱們依然需要導出

代碼實現

鉤子函數(hooks)接受一個回調函數作為參數,咱們直接把上面的函數傳入即可

需要註意的是,uni-app 中,下拉刷新的動畫需要手動關閉,咱們還需要改造一下 listReq函數

// useList中
import { onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'

// ...省略其餘代碼
onPullDownRefresh(initList)
onReachBottom(loadmore)

const getList = () => {
  // 分頁數據作為參數傳遞給介面調用函數即可
  return listReq(pageInfo.value)
    .then((res) => {
      // ...省略其餘代碼
    })
    .finally((info) => {
      // 不管成功還是失敗,關閉下拉刷新的動畫
      uni.stopPullDownRefresh()
      // 在最後再把前面返回的消息return出去,以便後續處理
      return info
    })
}

// ...省略其餘代碼

帶參數

其實在實際開發中,我們在發起請求時可能還需要其他的參數,上面我們都是固定的只有分頁的參數,可以稍加改造

需求分析

可能大家第一反應是多一個參數,或者用 展開運算符 (...)再定義一個形參就行了。這麼做肯定是沒問題的,不過在這裡的話不夠優雅~

我們這裡是要增加一個傳給後端的參數,一般都是一起以 JSON 對象的形式傳過去,既然如此,那咱們把所有的參數都用一個對象接受,發起請求的時候和分頁參數對象合併為一個對象,代碼的可讀性會更高,使用者在使用時也可以自由地定義 key-value 鍵值對

代碼實現

// useList中

const useList = (listReq, data) => {
  // ...省略其餘代碼

  // 判斷第二個參數是否是對象,以免後面使用展開運算符時報錯
  if (data && Object.prototype.toString.call(data) !== '[object Object]') {
    return new Error('額外參數請使用對象傳入')
  }
  const getList = () => {
    const params = {
      ...pageInfo.value,
      ...data,
    }
    return listReq(params).then((res) => {
      // ...省略其餘代碼
    })
  }
  // ...省略其餘代碼
}

// ...省略其餘代碼

帶預設配置版

有些時候我們的列表是在頁面中間,不需要觸底載入更多;有時候我們可能需要在不同的地方調用相同的介面,但是需要獲取的數據量不一樣....

為了適應各種各樣的需求,我們可以稍加改造,添加一個帶有預設值的配置對象,

// useList.js中

const defaultConfig = {
  pageSize: 10, // 每頁數量,其實也可以在data裡面覆蓋
  needLoadMore: true, // 是否需要下拉載入
  data: {}, // 這個就是給介面用的額外參數了
  // 還可以根據自己項目需求添加其他配置
}

// 添加一個有預設值的參數,依然滿足大部分列表頁傳入介面即可使用的需求
const useList = (listReq, config = defaultConfig) => {
  // 解構的時候賦上初始值,這樣即使配置參數只傳了一個參數,也不影響其他的配置
  const {
    pageSize = defaultConfig.pageSize,
    needLoadMore = defaultConfig.needLoadMore,
    data = defaultConfig.data,
  } = config

  // 應用相應的配置
  if (needLoadMore) {
    onReachBottom(loadmore)
  }

  const pageInfo = ref({
    pageNum: 1,
    pageSize,
    total: 0,
  })

  // ...省略其餘代碼
}

// ...省略其餘代碼

這樣一來,咱們就實現了一個滿足大部分移動端列表頁的邏輯復用 hooks

web 端的幾乎只有載入更多(翻頁)的時候邏輯不太一樣,不需要拼接數據,在封裝的時候可以把分頁器的處理邏輯一起封裝進來

本文轉載於:

https://juejin.cn/post/7165467345648320520

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


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

-Advertisement-
Play Games
更多相關文章
  • 一:背景 1. 講故事 年前遇到了好幾例托管堆被損壞的案例,有些運氣好一些,從被破壞的托管堆記憶體現場能觀測出大概是什麼問題,但更多的情況下是無法做出準確判斷的,原因就在於生成的dump是第二現場,借用之前文章的一張圖,大家可以理解一下。 為了幫助更多受此問題困擾的朋友,這篇來整理一下如何 快狠準 的 ...
  • 1.背景知識 CRLF用來表示文本換行的方式 ,CR是回車的意思,對應 \r ;LF 是換行的意思,對應 \n Windows 換行符是 \r\n Unix 換行是 \n 如果一個將要在Linux伺服器上使用的文件,比如某個配置文件,在windows電腦打開,編輯過,那麼文件每一行末尾會多有\r 。 ...
  • 一:什麼是乙太網: 乙太網是一種區域網技術,乙太網是一種用於數據鏈路層的協議類型。 二:乙太網的由來: 乙太網是美國施樂(Xerox)公司的Palo Alto研究中心(簡稱為PARC)於1975年研製成功的。那時乙太網是一種基帶匯流排區域網,當時的數據率為2.94 Mbit/s。乙太網用無源電纜作為總 ...
  • 網卡 網卡,又叫做通信適配器(adapter),早期的時候是插在機箱裡面的網路介面板,這種介面板又稱為網路介面卡NIC(Network Interface Card)或簡稱為“網卡”。因為後面集成到主板上了,所以又叫做通信適配器(adapter)。 網卡的作用: 電腦和外界區域網進行連接是通過通信 ...
  • 一、背景 二、概述 三、下線流程與原理 1.讀取待下線節點列表 2.判斷節點下線模式 3.設置超時時間 4.RMNode 處理下線事件 5.監控節點的狀態、下線節點 四、相關的Yarn集群配置 一、背景 接手部門 Hadoop 和 Flink 集群半年了,一直忙著上雲的事兒,很少有時間去琢磨運維的事 ...
  • 前言 SELinux是什麼 安全增強型 Linux(SELinux)是一種採用安全架構的 Linux® 系統,它能夠讓管理員更好地管控哪些人可以訪問系統。它最初是作為 Linux 內核的一系列補丁,由美國國家安全局(NSA)利用 Linux 安全模塊(LSM)開發而成。 SELinux工作原理 SE ...
  • MySQL具有開源免費,運維簡單,性能好等優點,是在汽車之家使用最多的一種資料庫。資料庫作為應用的後端存儲,承擔著數據持久化存儲的功能,是應用可以正常對外提供服務的關鍵組件,資料庫的高可用非常重要。 相對於成熟的商業資料庫軟體,開源的 MySQL高可用需要使用者自己進行設計和研發,本文介紹汽車... ...
  • Flutter 3.7 發佈,本人對其中後臺 isolate 通道比較感興趣,迫不及待翻譯了下Aaron Clarke文章,第一次翻譯,有不足地方歡迎各位大佬們評論區指正,我將持續更新到本文,謝謝。 原文地址:Introducing background isolate channels | by ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...