前言在后台管理系统日常开发中分页表格是比较多的场景,这些开发场景都大同小异,但在每一个页面都重复实现是比较boring的(浪费时间拧螺丝)。在Vue2中你可能会是使用mixins去实现这一套交互,包括数据、搜索、分页加载等,但是使用mixins存在命名冲突问题,并且随着业务堆叠会对项目维护带来巨大的问题。
但在Vue3发布之后,hook的运用也在vue中使用起来,详情戳文档 #组合式函数, 虽然篇幅没有涉及hook,vue3官方文档也没有定义hooks,但却处处都是hooks
什么是hooks其实在行业里面没有一个标准的明确的定义,在我看来就是具有满足一类业务场景的可复用方法(类似于utils),hooks与mixins、utils区别:
hooks和utils的最大区别就是hooks是特定的业务场景的衍生物,而utils更偏向通用工具。hooks其实和mixins最大的区别在思想上,vue hooks是利用Vue的组合式 API (Composition API)来封装和复用有状态逻辑的函数、耦合度更低。而mixins是基于potions Api,使用自由度更低、存在命名冲突,这一点也让维护难度增大。尝试封装状态声明:表格列表数据、查询参数、页码、页面等等基本交互方法,包括切换页码、每页条数、查询、数据拉取、重置标调支持立即执行、数据格式化 通过options控制支持初始化查询参数扩展 通过initParam传入import { reactive, computed, toRefs, onBeforeMount } from "vue";/** * @description table 页面表格操作方法封装 * @param {Function} request 请求方法 这里我使用的自己基于axios封装的类似await-to-js库 * @param {Object} initParam 获取数据初始化参数(非必传,默认为{}) * @param {Boolean} isPageAble 是否有分页(非必传,默认为true) * @param {Boolean} immediate 是否立即触发 (非必传,默认为true) * @param {Function} dataCallBack 对后台返回的数据进行处理的方法(非必传) * @param {Number} minPageShowCount 最小显示页码选择器条数 * */export function useTable ({ request, initParam, isPageAble = true, immediate = true, dataCallBack, minPageShowCount = 10 }) { //初始页面 const INITIAL_PAGE_PARAMS = { // 当前页数 current: 1, // 每页显示条数 size: 10, // 总条数 total: 0 } const state = reactive({ tableData: [], //分页数据 pagination: { ...INITIAL_PAGE_PARAMS }, // 查询参数(只包括查询) searchParam: {}, // 初始化默认的查询参数 searchInitParam: {}, // 总参数(包含分页和查询参数) totalParam: {}, // 是否加载中 loading: false, // 接口返回的所有内容 responseData: null }) //这里传入后台需要的页码数据 字段名自行定义即可 const pageParam = computed(() => ({ page: state.pagination.current, pageSize: state.pagination.size })) //是否展示分页器 const isPaginationVisible = computed(() => { return isPageAble && state.pagination.total > minPageShowCount }) //获取数据 const getTableData = async() => { Object.assign(state.totalParam, isPageAble ? pageParam.value : {}, initParam) initParam && (state.searchInitParam = initParam) state.loading = true; const [error, res] = await request(state.totalParam) if(error) { //这里根据业务需求做判断 xxx.error(error.msg) return } state.tableData = res.data.list; state.responseData = res try { dataCallBack && (state.tableData = dataCallBack(res)); } catch (error) { console.error(error,'Format error') Message.error('格式化数据错误') } state.loading = false; isPageAble && updatePagination({ total: 数据总数 }); } if(immediate) onBeforeMount(async () => { await getTableData() }) const updatePagination = (pagination) => { Object.assign(state.pagination, pagination); }; const updatedTotalParam = () => { state.totalParam = {}; // 处理查询参数,可以给查询参数加自定义前缀操作 let currentSearchParam = {}; // 防止手动清空输入框携带参数(这里可以自定义查询参数前缀) for (let key in state.searchParam) { // * 某些情况下参数为 false/0 也应该携带参数 if (Reflect.has(state.searchParam, key)) { currentSearchParam[key] = state.searchParam[key]; } } Object.assign(state.totalParam, currentSearchParam, isPageAble ? pageParam.value : {}); }; const resetParams = () => { state.searchParam = state.searchInitParam; state.pagination = INITIAL_PAGE_PARAMS; Object.assign(state.totalParam, state.searchParam, isPageAble ? pageParam.value : {}); } const refreshTable = () => { resetParams() getTableData() } const search = () => { state.pagination.current = 1; updatedTotalParam(); getTableData(); }; const onSizeChange = (val) => { state.pagination.current = 1; state.pagination.pageSize = val; getTableData(); }; const onPageChange = (val) => { state.pagination.current = val; getTableData(); }; return { ...toRefs(state), isPaginationVisible, refreshTable, search, onSizeChange, onPageChange, getTableData }}
使用方法只要定义好参数传入即可,使用非常的简便,不需要业务重复实现,有特殊场景业务自行扩充即可
const { loading, tableData, pagination, search, onSizeChange, searchParam, onPageChange, isPaginationVisible } = useTable({ request, dataCallback, initParam: { }})
总结随着vue3支持使用hooks,使用hooks进行开发可以减少重复性的工作,我们日常开发也越来越快(造轮子的好处)。目前vue也有一套比较成熟的hooks库VueUse,感兴趣的可以前往了解。
作者:打蛋_99链接:https://juejin.cn/post/7293786797061668902