使用vue3组合式函数封装页面公用方法

1.为什么要使用组合式函数进行封装

应用中页面很多方法都能在多个页面公用,如果每个页面都重新写一遍所有方法,如表格数据的增删改查、分页、数据的条件查询、重置等,那么会重现很多冗余并且十分繁琐。

官网:在 Vue 应用的概念中,“组合式函数”(Composables) 是一个利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数。组合式函数约定用驼峰命名法命名,并以“use”作为开头。如果组合式函数接收 ref 参数,则返回数据仍具有响应性。

如果你的组合式函数在接收 ref 为参数时会产生响应式 effect,请确保使用 watch() 显式地监听此 ref,或者在 watchEffect() 中调用 unref() 来进行正确的追踪。

抽取组合式函数不仅是为了复用,也是为了代码组织。

所谓的有状态,我的理解就是有可能会变化的数据。

2.封装模板

//组合函数
export function func(param){
    const pageNum,page....
    func1(){ ....}
    func2(){ ....}
    func3(){ ....}

return {
    pageNum,page,
    func1,func2,func3
    }
}

//使用:
const {
  pageNum,page,func1,func2,func3
} = func({ param });

3.封装实例

import { ref, unref } from 'vue'
import { useRouter } from 'vue-router'
import { setTableData } from "@/composables/transferToTableV2"

/**
 * loading状态
 * @param {*} request url请求
 * @param {*} form 不同页面传入的表单
 * @returns 
 */
export function useDataGrid({ request, form, tableConfig }) {
    const router = useRouter();

    //分页
    const pageNum = ref(Number.parseInt(router.currentRoute.value.query.pageNum) || 1);
    const total = ref(0); //总页数
    const pageSize = ref(16); //每页多少条
    const pages = ref(0);

    // 加载状态
    const loading = ref(true);

    //表格数据(el-table-v2)
    const columns = ref([]);
    const data = ref([]);
    const selectedId = ref([]);
    const tableData = ref([]); //列表数据

    const code = ref(500);

    //所有下拉框
    const allType = ref({});

    // 添加资源更新记录Form打开标识
    const dialogVisible = ref(false);

    // 获取列表数据
    const getDataGrid = async(params) => {
        loading.value = true;
        await request(params).then(res => {
            code.value = res.data.code;
            if (res.data && res.data.code === 200) {
                total.value = res.data.data.total;
                pageNum.value = res.data.data.pageNum;
                pageSize.value = res.data.data.pageSize;
                pages.value = res.data.data.pages;
                tableData.value = res.data.data.list ? res.data.data.list : res.data.data;

            } else if (res.data.code === 400 && res.data.errorMsg === "暂无记录!") {
                total.value = 0; //没有数据时分页页数置为1
            } else {
                ElMessage.error("内部服务器错误:" + res.data.errorMsg);
            }

            // 监听到data.value值改变后需要重新设置
            function setTableStyleAndData() {
                const { columnsVal, dataVal } = setTableData({
                    code: code.value,
                    cnColumnNameArr: tableConfig.cnColumnNameArr,
                    hiddenIndex: tableConfig.hiddenIndex,
                    columnWidth: tableConfig.columnWidth,
                    selectedId: selectedId.value,
                    cellRenderer: tableConfig.cellRenderer,
                    tableData: tableData.value
                });
                columns.value = unref(columnsVal);
                data.value = unref(dataVal);
            }

            setTableStyleAndData();

            // 数据设置完后再设置loading为false
            loading.value = false;

        }).catch(error => {
            console.log(error);
            loading.value = false;
            ElMessage.error("列表数据显示失败");
        });
    }
    getDataGrid(form);

    function loadDataGrid() {
        if (form) form.pageNum = pageNum.value;
        getDataGrid(form);
        router.push({ path: router.currentRoute.value.path, query: { pageNum: pageNum.value } });
    }

    // 获取下拉框
    async function getSelectOptions(request) {
        let result = await request();
        if (result.data.code === 200) {
            loading.value = false;
            allType.value = result.data.data;
        } else {
            ElMessage.error("获取下拉框数据类型失败:服务器内部错误");
        }
    }

    const deleteOneById = (id, action, request) => {
        ElMessageBox.confirm('请确认是否删除?', '警告!', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning',
        }).then(() => {
            async function deleteOne(param) {
                let result = await request(param);
                if (result.data.code === 200) {
                    ElMessage.success(action + "成功");
                    loadDataGrid();
                    selectedId.value = [];
                } else {
                    ElMessage.error(action + "失败:" + result.data.errorMsg);
                }
            }
            if (typeof id === 'number') {
                deleteOne(id);
            } else {
                id.forEach(item => {
                    deleteOne(item);
                });
            }
        }).catch(() => {});
    }

    /**
     * 删除一条:可以以数组形式删除
     * @param {*} id 
     */
    const deleteById = (id, request) => {
        let ids = [];
        ids.push(id);
        batchDelByIds(ids, request);
    }

    /**
     * 批量删除 参数:ids List集合类型   RquestParam
     * @param {*} ids 
     */
    const batchDelByIds = (ids, request) => {
        // 判断ids没有值,不能删除
        if (ids.length === 0) {
            ElMessage.warning("请选择要删除的数据");
            return;
        }
        ElMessageBox.confirm('请确认是否删除?', '警告!', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning',
        }).then(async() => {
            // 区分单个删除和批量删除
            await request({ ids: ids.join(",") }).then((res) => {
                if (res.data && res.data.code === 200) {
                    ElMessage.success("删除成功");
                    // 删除成功后,重新显示当前页面,且清空ids
                    loadDataGrid();
                    selectedId.value = [];
                } else {
                    ElMessage.error("删除失败");
                }
            }).catch(error => {
                ElMessage.error("服务器内部错误");
            });
        }).catch(() => {});
    }

    /**
     * 根据id更新记录
     * @param {*} id 
     * @param {*} action 
     * @param {*} request 请求api方法
     */
    const updateById = async(id, action, request) => {
        let result = await request({ id });
        if (result.data.code === 200) {
            ElMessage.success(action + "成功");
            loadDataGrid();
        } else {
            ElMessage.error(action + "失败:" + result.data.errorMsg);
        }
    }

    /**
     * 批量更新
     * @param {*} ids 
     * @param {*} action 操作类型
     * @param {*} request 请求api方法
     */
    const batchUpdateById = async(ids, action, request) => {
        let result = await request({ ids: ids.join(",") });
        if (result.data.code === 200) {
            ElMessage.success(action + "成功");
            // 删除成功后,重新显示当前页面,且清空ids
            loadDataGrid();
            selectedId.value = [];
        } else {
            ElMessage.error(action + "失败:" + result.data.errorMsg);
        }
    }

    const dialogAddOrEdit = async(visible, action, param, request) => {
        dialogVisible.value = visible;
        let result = await request(param);
        if (result.data.code === 200) {
            ElMessage.success(action + "成功");
            loadDataGrid();
        } else {
            ElMessage.error(action + "失败:" + result.data.errorMsg);
        }
    }

    return {
        pageNum,
        total,
        pageSize,
        pages,
        loading,
        tableData,
        selectedId,
        columns,
        data,
        allType,
        dialogVisible,
        loadDataGrid,
        getSelectOptions, //下拉框
        deleteOneById, //普通删除一条
        deleteById, //删除一条,可以ids 数组形式删除
        batchDelByIds, //批量删除 ids数组形式删除
        updateById, //更新一条
        batchUpdateById, //批量更新
        dialogAddOrEdit, //弹框(添加或编辑)
    }
}

4.使用

// 通过组合函数获取和声明页面所需要的变量及方法
const {
  pageNum,
  total,
  pageSize,
  pages,
  loading,
  selectedId,
  tableData,
  columns,
  data,
  allType,
  dialogVisible,
  loadDataGrid,
  getSelectOptions,
  deleteById, //删除一条
  batchDelByIds, //批量删除
  updateById, //更新一条
  batchUpdateById, //批量更新
  dialogAddOrEdit, //弹框(添加或编辑)
} = useDataGrid({
  request: dataGrid, form: resourceForm, tableConfig: {
    cnColumnNameArr, hiddenIndex, columnWidth, cellRenderer
  }
});

5.问题:获取的响应性数据columns,data等,但columns.value后无值

解决:使用watchEffect(()=>{})即可监听在数据有值后再进行数据操作

watchEffect(() => {
  if (columns.value.length > 0) {
    columns.value[0].fixed = true
    columns.value[1].fixed = TableV2FixedDir.LEFT
    columns.value[2].fixed = TableV2FixedDir.LEFT
    columns.value[3].fixed = TableV2FixedDir.LEFT
  }

  data.value.map(item => {
    item['状态'] = transferStatus(item['状态']);
  });
  tableData.value.length>0 && tableData.value.map(item => {
    if(typeof item['setted'] === "number") item['setted'] = transferStatus(item['setted']);
  });

  // 设置类型
  if (JSON.stringify(allType.value) == "{}") return;
  // 动态设置options
  let tempFileType = addFormOptions(allType.value.file_type);
  let tempProductionVersion = addFormOptions(allType.value.production_version);
  let tempServer = addFormOptions(allType.value.server);
  let tempSubmitter = addFormOptions(allType.value.submitter);
  let tempSetted = allType.value.setted;

  tempSetted = addFormOptions(tempSetted);
  tempSetted = tempSetted.map(item => {
    item['label'] = transferStatus(item['label']);
    return item;
  });

  configData.value.formItems[1].options = tempFileType;
  configData.value.formItems[2].options = tempSubmitter;
  configData.value.formItems[3].options = tempServer;
  configData.value.formItems[4].options = tempProductionVersion;
  configData.value.formItems[5].options = tempSetted;
});

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值