vue3流水线分页表格开发?😁 useTable了解一下

前言

在后台管理系统日常开发中分页表格是比较多的场景,这些开发场景都大同小异,但在每一个页面都重复实现是比较boring的(浪费时间拧螺丝🤐)。在Vue2中你可能会是使用mixins去实现这一套交互,包括数据、搜索、分页加载等,但是使用mixins存在命名冲突问题,并且随着业务堆叠会对项目维护带来巨大的问题。

随着Vue3的问世,hook的运用也在vue中使用起来,详情戳文档#组合式函数, 虽然篇幅没有涉及hook,vue3官方文档也没有定义hooks,但却处处都是hooks😁

什么是hooks

其实在行业里面没有一个标准的明确的定义,在我看来就是具有满足一类业务场景的可复用方法(类似于utils),hooks与mixins、utils区别:

  1. hooks和utils的最大区别就是hooks是特定的业务场景的衍生物,而utils更偏向通用工具。
  2. hooks其实和mixins最大的区别在思想上,vue hooks是利用Vue的组合式 API (Composition API)来封装和复用有状态逻辑的函数、耦合度更低。而mixins是基于potions Api,使用自由度更低、存在命名冲突,这一点也让维护难度增大。

尝试封装

  1. 状态声明:表格列表数据、查询参数、页码、页面等等
  2. 基本交互方法,包括切换页码、每页条数、查询、数据拉取、重置标调
  3. 支持立即执行、数据格式化 通过options控制
  4. 支持初始化查询参数扩展 通过initParam传入
js 复制代码
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
    }

}

使用方法

只要定义好参数传入即可,使用非常的简便,不需要业务重复实现,有特殊场景业务自行扩充即可

js 复制代码
const {
    loading,
    tableData,
    pagination,
    search,
    onSizeChange,
    searchParam,
    onPageChange,
    isPaginationVisible
   
} = useTable({
    request,
    dataCallback,
    initParam: { }
})

总结

随着vue3支持使用hooks,使用hooks进行开发可以减少重复性的工作,我们日常开发也越来越快(造轮子的好处😁)。目前vue也有一套比较成熟的hooks库VueUse,感兴趣的可以前往了解。

相关推荐
软件技术NINI5 分钟前
html知识点框架
前端·html
深情废杨杨8 分钟前
前端vue-插值表达式和v-html的区别
前端·javascript·vue.js
GHUIJS9 分钟前
【vue3】vue3.3新特性真香
前端·javascript·vue.js
众生回避14 分钟前
鸿蒙ms参考
前端·javascript·vue.js
洛千陨15 分钟前
Vue + element-ui实现动态表单项以及动态校验规则
前端·vue.js
GHUIJS1 小时前
【vue3】vue3.5
前端·javascript·vue.js
&白帝&2 小时前
uniapp中使用picker-view选择时间
前端·uni-app
魔术师卡颂2 小时前
如何让“学源码”变得轻松、有意义
前端·面试·源码
谢尔登2 小时前
Babel
前端·react.js·node.js
ling1s2 小时前
C#基础(13)结构体
前端·c#