最近在 Vue.js 项目重构中,体会到了 Composable 的代码复用价值. 这里梳理一下.
业务中, 很常见的 CRUD 需求主要有如下通用的构成:
界面
- 数据列表
- 新增按钮
- 每行数据对应 1 个编辑按钮
- 每行数据对应 1 个删除按钮
功能
- 页面加载时, 获取列表数据(带有 loading 指示)
- 点击新增或者编辑按钮时, 能够弹出表单.
- 修改相应的表单后, 列表数据需要更新.
- 点击删除按钮, 能够给出数据删除提醒.
- 删除之后, 列表数据随之更新.
- 如果数据操作出现异常,给出弹窗反馈.
- 数据上传成功, 给出弹窗反馈.
之前每开发一个功能时, 上面的过程几乎都要走一遍, 虽然难度不大, 但过程枯燥,容易遗漏犯错. 而采用 Composable 之后, 上面的逻辑完全可以抽离出来,形成一个组合函数 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: "确认删除?",
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,
};
}
应用
面对一个新的CRUD业务时, 只用定义好 actions
参数, 然后调用 useList
即可获得页面所需要的全部数据.
// actions 参数给出了获取列表,删除列表的方法.
const actions = {
getList: async () => await api.get(some_url),
deleteItem: async (id) => await api.delete(some_url + id + "/"),
};
// 调用组合函数
const {
loading,
formVisible,
list,
openForm,
deleteFn,
updateList,
} = useList(actions);
借助 Quasar 实现组件视图模板:
<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>
短短几十行代码, 就能实现一个功能完备的列表页.
可以按照此逻辑, 编写自己的useForm
组合函数, 实现表单页面的通用逻辑抽离. 这样开发效率将大大提高. 而且, 令人兴奋的是, 不仅仅是Vue.js 3支持组合函数, Vue.js 2.7也同样支持上述写法.