当前位置:   article > 正文

vue3组件封装系列-表格及分页_vue3封装table、分页组件

vue3封装table、分页组件

第二弹来了,不知道有多少人是看过我的第一篇文章的,今天本来是没想更新的,但是现在项目正在验收期准备上线,闲着还不如来发发文。虽然这两天可能会高产,下一次高产就不知道是什么时候了。话不多说,先上图。

在这里插入图片描述

上面就是效果图了,基于vue3+element-plus觉得还行的可以继续看下去

源码

src\components\MTable\index.vue

<template>
    <div class="table-list-root">
        <el-table
            ref="mtable"
            v-loading="loading"
            v-bind="$attrs"
            :border="border"
            :header-row-style="defaultHeaderRowStyle"
            :header-cell-style="defaultHeaderCellStyle"
            :cell-style="defaultCellStyle"
            class="table-list__main"
        >
            <template #empty>
                <el-empty description="暂无数据" />
            </template>
            <el-table-column v-for="filed in columns" :key="filed.prop" v-bind="filed">
                <template v-if="filed.prop && $slots[filed.prop]" #default="scope">
                    <slot :name="filed.prop" :row="scope.row" />
                </template>
            </el-table-column>
        </el-table>
        <div v-if="pagination" class="table-list__footer">
            <el-pagination
                v-bind="paginationProps"
                @current-change="handleCurrentChange"
                @size-change="handleSizeChange"
            />
        </div>
    </div>
</template>
<script setup lang="ts">
import { type PropType, ref, toRefs } from 'vue';
import useTable from './uses/useTable';
import usePagination from './uses/usePagination';
defineOptions({
    inheritAttrs: false
});
type filed = {
    prop?: string;
    [propName: string]: any;
};
const props = defineProps({
    loading: {
        type: Boolean,
        default: false
    },
    // 表格列
    columns: {
        type: Array as PropType<filed[]>,
        default: () => []
    },
    border: {
        type: Boolean,
        default: true
    },
    pagination: {
        type: Object,
        default: () => null
    }
});
// 这里其实可以使用defineModel,我这样写只是为了让习惯vue2的稍微清晰一点
const emit = defineEmits(['update:pagination']);
const mtable = ref(null);
const { pagination } = toRefs(props);

const { defaultHeaderRowStyle, defaultHeaderCellStyle, defaultCellStyle } = useTable();
const { paginationProps, handleSizeChange, handleCurrentChange } = usePagination(emit, pagination);
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

src\components\MTable\uses\useTable.ts

这个文件其实就是一些自定义样式,不想分开写的也可以写在一起

import { ref } from 'vue';

export default function useTable() {
  const defaultHeaderRowStyle = ref({
    borderRadius: '4px 4px 0px 0px',
    backgroundColor: '#F8F8F8',
    padding: '0',
    height: '54px',
    lineHeight: '54px',
  });
  const defaultHeaderCellStyle = ref({
    backgroundColor: '#F8F8F8',
    color: '#282828',
    fontSize: '14px',
    padding: '0',
    height: '54px',
  });
  const defaultCellStyle = ref({
    color: '#323233',
    fontSize: '14px',
    lineHeight: '20px',
  });
  return {
    defaultHeaderRowStyle,
    defaultHeaderCellStyle,
    defaultCellStyle,
  };
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

src\components\MTable\uses\usePagination.ts

这里是关于分页的处理

import { computed } from 'vue';

export default function usePagination(emit:any, pagination:any) {
  const paginationProps = computed(() => {
    const paginationVal = pagination.value
    return {
      background: true,
      layout: 'prev, pager, next, sizes, jumper',
      currentPage: paginationVal.page,
      pageSize: paginationVal.size,
      ...paginationVal,
    }
  });

  const handleSizeChange = (pageSize:number | string) => {
    emit('update:pagination', {
      ...pagination.value,
      size: pageSize,
    });
  };
  const handleCurrentChange = (currentPage:number | string) => {
    emit('update:pagination', {
      ...pagination.value,
      page: currentPage,
    });
  };

  return {
    paginationProps,
    handleSizeChange,
    handleCurrentChange,
  };
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

关于组件的源码其实就这些了,下面简单写个使用示例

<template>
<MTable
    v-model:pagination="pagination"
    :loading="loading.tableLoading"
    :data="tableData"
    :columns="TABLECOLUMN"
    @update:pagination="getTableData"
>
    <template #sent_staff="{ row }">
        自定义成员列xxxxxx
    </template>
    <template #action="{ row }">
        <el-button type="primary" link>预览</el-button>
        <el-button type="primary" link>删除</el-button>
        <el-button type="primary" link>再次发送</el-button>
    </template>
</YzTable>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import MTable from '@/components/MTable/index.vue';
const searchQuery = ref({});
const pagination = ref({
    page: 1,
    size: 10,
    total: 0
});
const tableData = ref([]);
const loading = ref({
    tableLoading: false,
});

onMounted(() => {
    handleQuery();
});

// 点击查询
const handleQuery = async () => {
    pagination.value.page = 1;
    await getTableData();
};

// 请求表格数据
const getTableData = async () => {
    const dataValue = {
        ...searchQuery.value,
        page: pagination.value.page,
        page_size: pagination.value.size
    };
    loading.value.tableLoading = true;
    try {
        const data = await xxxxxxxx(dataValue);
        tableData.value = data.data;
        pagination.value.total = data.total;
    } finally {
        loading.value.tableLoading = false;
    }
};

const TABLECOLUMN = [
    {
        label: '序号',
        type: 'index',
        width: 70
    },
    {
        label: '计划名称',
        prop: 'name'
    },
    {
        label: '发送类型',
        prop: 'send_type',
        formatter: (row: any) => planSendType[row.send_type]
    },
    {
        label: '发送时间',
        prop: 'send_time',
        minWidth: 130,
        formatter: (row: any) => Moment.format(Number(row.send_time))
    },
    {
        label: '创建人',
        prop: 'creator.name'
    },
    {
        label: '所属部门',
        prop: 'creator',
        formatter: (row: any) => row.creator?.department?.name || '-'
    },
    {
        label: '已发送成员',
        prop: 'sent_staff'
    },
    {
        label: '未发送成员',
        prop: 'unsent_staff'
    },
    {
        label: '已送达客户',
        prop: 'delivered'
    },
    {
        label: '未送达客户',
        prop: 'not_delivered'
    },
    {
        label: '创建时间',
        prop: 'created_at',
        minWidth: 130,
        formatter: (row: any) => Moment.format(Number(row.created_at))
    },
    {
        label: '状态',
        prop: 'plan_status',
        formatter: (row: any) => planStatusType[row.plan_status]
    },
    {
        label: '操作',
        prop: 'action',
        fixed: 'right',
        width: 250
    }
];
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124

以上只是简单的示例,如果结合我上一篇文章,那么整个列表页面,除了表格顶部那些个操作按钮,就全部都是数据驱动了,至于按钮那一块的封装,过于简单,并不准备放出来,如果需要的话可以留言。

还是老样子,除了那几个固定的key必须,其他都不是必须的,并且支持全部table的属性,目前的缺陷是无法自定义表格header,这个目前还没有好的解决方案。总体来说够用了,那种有header定制的也不多,或者整个项目都差不多,可以直接写在组件里面

这一期写到这里也就差不多了,有什么意见建议的欢迎提出。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/701557
推荐阅读
相关标签
  

闽ICP备14008679号