最近在 Vue.js 項(xiàng)目重構(gòu)中,體會到了 Composable 的代碼復(fù)用價值. 這里梳理一下.
業(yè)務(wù)中, 很常見的 CRUD 需求主要有如下通用的構(gòu)成:
界面
- 數(shù)據(jù)列表
- 新增按鈕
- 每行數(shù)據(jù)對應(yīng) 1 個編輯按鈕
- 每行數(shù)據(jù)對應(yīng) 1 個刪除按鈕
功能
- 頁面加載時, 獲取列表數(shù)據(jù)(帶有 loading 指示)
- 點(diǎn)擊新增或者編輯按鈕時, 能夠彈出表單.
- 修改相應(yīng)的表單后, 列表數(shù)據(jù)需要更新.
- 點(diǎn)擊刪除按鈕, 能夠給出數(shù)據(jù)刪除提醒.
- 刪除之后, 列表數(shù)據(jù)隨之更新.
- 如果數(shù)據(jù)操作出現(xiàn)異常,給出彈窗反饋.
- 數(shù)據(jù)上傳成功, 給出彈窗反饋.
之前每開發(fā)一個功能時, 上面的過程幾乎都要走一遍, 雖然難度不大, 但過程枯燥,容易遺漏犯錯. 而采用 Composable 之后, 上面的邏輯完全可以抽離出來,形成一個組合函數(shù) useList
import { onMounted, ref, watch } from "vue";
import { Dialog, Notify } from "quasar";
export function useList(actions) {
const loading = ref(false);
const list = ref([]);
const formVisible = ref(false);
const openForm = () => {
formVisible.value = true;
};
const loadData = async () => {
loading.value = true;
try {
list.value = await actions.getList();
} catch (error) {
console.error(error);
} finally {
loading.value = false;
}
};
const deleteFn = async (id) => {
Dialog.create({
title: "提醒",
message: "確認(rèn)刪除?",
ok: {
unelevated: true,
color: "negative",
},
cancel: {
flat: true,
color: "black",
},
persistent: true,
}).onOk(async () => {
try {
await actions.deleteItem(id);
Notify.create({
message: "刪除成功",
type: "positive",
});
const index = list.value.findIndex((el) => el.id === id);
if (index !== -1) {
list.value.splice(index, 1);
}
} catch (error) {
Notify.create({
message: "刪除失敗",
type: "negative",
});
}
});
};
const updateList = async (data) => {
const index = list.value.findIndex((el) => el?.id === data.id);
if (index !== -1) {
list.value.splice(index, 1, data);
} else {
// 新增
list.value.splice(0, 0, data);
}
};
onMounted(() => loadData());
return {
loading,
list,
formVisible,
openForm,
deleteFn,
updateList,
};
}
應(yīng)用
面對一個新的CRUD業(yè)務(wù)時, 只用定義好 actions
參數(shù), 然后調(diào)用 useList
即可獲得頁面所需要的全部數(shù)據(jù).
// actions 參數(shù)給出了獲取列表,刪除列表的方法.
const actions = {
getList: async () => await api.get(some_url),
deleteItem: async (id) => await api.delete(some_url + id + "/"),
};
// 調(diào)用組合函數(shù)
const {
loading,
formVisible,
list,
openForm,
deleteFn,
updateList,
} = useList(actions);
借助 Quasar 實(shí)現(xiàn)組件視圖模板:
<q-card>
<q-table
:data="list"
:loading="loading"
>
<template v-slot:top>
<q-btn
:disable="loading"
label="新增"
@click="openForm"
/>
</template>
<template v-slot:body-cell-id="props">
<q-td :props="props">
<q-btn label="編輯" @click="openForm(props.row)" />
<q-btn label="刪除" @click="deleteFn(props.row.id)"/>
</q-td>
</template>
</q-table>
<meeting-assign-form-modal
v-model="formVisible"
@update="updateList" />
</q-card>
短短幾十行代碼, 就能實(shí)現(xiàn)一個功能完備的列表頁.
可以按照此邏輯, 編寫自己的useForm
組合函數(shù), 實(shí)現(xiàn)表單頁面的通用邏輯抽離. 這樣開發(fā)效率將大大提高. 而且, 令人興奮的是, 不僅僅是Vue.js 3支持組合函數(shù), Vue.js 2.7也同樣支持上述寫法.