維護loading加載狀態(tài)的幾個方法小結
前言
在項目開發(fā)中,當頁面請求接口時,組件局部或者頁面全局顯示loading加載遮罩可謂是司空見慣了,下面來討論一下如何優(yōu)雅的使用loading狀態(tài)。下文引用了比較常用的兩個組件Button按鈕和Table表格作為例子,談談如何優(yōu)雅的維護loading加載狀態(tài)。
Butoon組件原始加載用法
<template>
<div>
<div>數(shù)據(jù):{{ list }}</div>
<el-button type="primary" @click="asyncFetch" :loading="loading">異步獲取</el-button>
<el-button type="primary" @click="syncFetch" :loading="loading">同步獲取</el-button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { FetchApi } from '@/api'
const loading = ref(false)
const list = ref([])
// 異步調用
const asyncFetch = () => {
loading.value = true
FetchApi().then(res => {
console.log(res)
list.value = res
}).finally(() => {
loading.value = false
})
}
// 同步調用
const syncFetch = async () => {
loading.value = true
try {
const res = await FetchApi()
console.log(res)
list.value = res
} catch (error) {
console.log(error)
}
loading.value = false
}
</script>
由以上代碼可看出,在每次點擊按鈕提交時,都需要在調用接口前開啟加載狀態(tài),在接口調用結束時,無論成功與否,都結束加載狀態(tài)。為了簡化這一操作步驟,減少代碼冗余,我們可以封裝一個button組件,把loading狀態(tài)及相關邏輯提取這個組件當中。
封裝Button組件
<template>
<!-- 新版本vue中,透傳可省略v-bind="$attrs" -->
<el-button v-bind="$attrs" :loading="loading" :onClick="handleClick">
<slot></slot>
</el-button>
</template>
<script setup>
import { ref } from 'vue'
const { onClick } = defineProps(['onClick'])
const loading = ref(false)
// 重寫點擊方法
const handleClick = async () => {
loading.value = true
try {
// 傳遞的onClick方法必須為同步的
onClick && await onClick()
} catch (error) {
console.error(error)
}
loading.value = false
}
</script>
以上對button組件進行二次封裝,把一些重復的業(yè)務邏輯放到該組件中,為了能夠知道異步方法什么時候執(zhí)行結束,將點擊方法通過prop參數(shù)的形式傳遞到子組件中,交給子組件在合適的時機執(zhí)行,學過react的話應該對此操作比較熟悉。
組件加載用法
Page.vue
<template>
<div>
<div>數(shù)據(jù):{{ list }}</div>
<ViButton type="primary" :onClick="syncFetch">同步獲取</ViButton>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { FetchApi } from '@/api'
import ViButton from '@/components/ViButton/ViButton.vue'
const list = ref([])
// 同步調用
const syncFetch = async () => {
const res = await FetchApi()
list.value = res
}
</script>
需要注意的是,我們需要把FetchApi()異步方法轉為同步,這是為了在Button組件中能夠方便地知道FetchApi方法的執(zhí)行結束時機,否則在Button組件中將不能正確的隱藏loading狀態(tài)。
封裝表格組件
<template>
<!-- 新版本vue中,透傳可省略v-bind="$attrs" -->
<el-table v-bind="$attrs" v-loading="loading">
<slot></slot>
</el-table>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const props = defineProps({
// 獲取數(shù)據(jù)方法
fetchData: {
type: Function,
default: () => {}
},
// 默認是onMounted立即執(zhí)行fetchData
immediateFetch: {
type: Boolean,
default: true
}
})
const loading = ref(false)
const getList = async () => {
loading.value = true
try {
await props.fetchData()
} catch (error) {
console.log(error)
}
loading.value = false
}
onMounted(() => {
props.immediateFetch && getList()
})
// 暴露經過loading處理的fetch方法,比如搜索時候需要在父組件手動調用
defineExpose({ fetchData: getList })
</script>
組件加載用法
page.vue
<template>
<div>
<ViTable ref="ViTableRef" :data="list" :fetchData="syncFetch" :immediateFetch="false">
<el-table-column prop="name" label="姓名"></el-table-column>
</ViTable>
<el-button @click="onSearch">查詢</el-button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { FetchApi } from '@/api'
import ViTable from '@/components/ViTable/ViTable.vue'
const list = ref([])
const ViTableRef = ref(null)
// 同步調用
const syncFetch = async () => {
console.log('syncFetch')
const res = await FetchApi()
list.value = res
console.log(list.value)
}
// 搜索
const onSearch = () => {
ViTableRef.value.fetchData()
}
</script>
以上需要注意的有兩點:
- 數(shù)據(jù)是否需要在表格掛載完成立即獲?。?/li>
- 需要對外暴露經過
loading加工的fetch方法,目的是滿足需要手動調用獲取數(shù)據(jù)的需求,比如點擊搜索;
以上方式當需要手動調用時似乎還是有些麻煩,下面我們改成useHook方式來試試~
封裝useLoading鉤子函數(shù)
useLoading.js
import { ref } from 'vue'
// 多個組件共享統(tǒng)一狀態(tài)
const loading = ref(false)
export const useLoading = (prop = {
fetchData: () => {}
}) => {
// 對外暴露loading給table組件或者button組件使用
// 內部只負責處理業(yè)務邏輯,不負責調用,這樣更加靈活
return {
loading,
fetchData: async () => {
loading.value = true
try {
await prop.fetchData()
} catch (error) {
console.log(error)
}
loading.value = false
}
}
}
ViTablePlus.vue
<template>
<!-- 新版本vue中,透傳可省略v-bind="$attrs" -->
<el-table v-bind="$attrs" v-loading="loading">
<slot></slot>
</el-table>
</template>
<script setup>
import { useLoading } from '@/hooks/useLoading'
const { loading } = useLoading()
</script>
用法
Page.vue
<template>
<div>
<ViTablePlus :data="list" :fetchData="syncFetch" :immediateFetch="false">
<el-table-column prop="name" label="姓名"></el-table-column>
</ViTablePlus>
<el-button @click="onSearch">查詢</el-button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { FetchApi } from '@/api'
import ViTablePlus from '@/components/ViTablePlus/ViTablePlus.vue'
import { useLoading } from '@/hooks/useLoading'
// 手動執(zhí)行經過loading處理的fetchData方法
const { fetchData } = useLoading({
fetchData: syncFetch
})
const list = ref([])
// 需要使用function定義方法,進行變量提升,因為useLoading在syncFetch方法定義前執(zhí)行
async function syncFetch() {
const res = await FetchApi()
list.value = res
}
// 搜索
const onSearch = () => {
// 經過loading處理的fetchData方法
fetchData()
}
onMounted(() => {
// 經過loading處理的fetchData方法
fetchData()
})
</script>
總結
本文講了在二次封裝的Button和Table組件內部維護loading狀態(tài),為了能夠獲取到異步方法的調用完成時機,我們把異步方法轉為同步方法后,通過prop的方式傳遞到子組件,委托子組件在恰當?shù)臅r機執(zhí)行。但把loading狀態(tài)封裝到組件內部還是不夠靈活,最后使用useLoading鉤子函數(shù)維護一個全局狀態(tài),提供靈活的跨組件狀態(tài)共享。
以上就是維護loading加載狀態(tài)的幾個方法小結的詳細內容,更多關于維護loading加載狀態(tài)的資料請關注腳本之家其它相關文章!
相關文章
js+css實現(xiàn)的圓角邊框TAB選項卡滑動門代碼分享(2款)
這篇文章主要為大家詳細介紹了兩種js+css實現(xiàn)的圓角邊框TAB選項卡滑動門效果,很實用的代碼,推薦給大家,有需要的小伙伴可以參考下2015-08-08
JavaScript面試Module?Federation實現(xiàn)原理詳解
這篇文章主要為大家介紹了JavaScript面試Module?Federation實現(xiàn)原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10
Javascript數(shù)組的?splice?方法詳細介紹
這篇文章主要介紹了Javascript數(shù)組的splice方法詳細介紹,splice方法通過刪除或替換現(xiàn)有元素或者原地添加新的元素來修改數(shù)組,并以數(shù)組形式返回被修改的內容。此方法會改變原數(shù)組2022-09-09

