Vue3.0使用Element-ui制作table组件,操作列动态渲染按钮

        大家好,我是一个8年前端开发经验的新博主(实战react方向较多),最近两年互联网行业动荡,工作不稳定,想积累点自己的项目实践经验以备不时之需。第一弹!分享一下最近使用vue3.0二次封装过的el-table组件,带有分页功能,以及操作列按动态数据有条件渲染!希望可以帮助各位在职前端小伙伴解决一些实际问题。

       下一弹分享自定义搜索表单组件<SearchForm/>,喜欢的记得点个赞哦~

知识点:

1、二次封装el-table,减少重复写很多标签

2、table表格自带翻页页签pagination

3、序号列按当前页累加计算

4、操作列按数据有条件渲染

直接先看效果图:(前提先安装UI组件库:npm element-plus --save)

代码比较多,原因是我写的比较全,有经验的可以直接看关键的地方!!

首先,看二次封装过的Table组件代码

<!--
 * @Author: Cocoon_xu
 * @LastEditTime: 2024-02-18 16:41:12
 * @Description: 二次封装表格组件,带翻页控件
-->
<template>
    <!-- 表格 -->
    <el-table
        :data="tableData"
        :border="border"
        :stripe="stripe"
        v-loading="loading"
        style="width: 100%; overflow-x: auto;"
        @selection-change="selectionChange"
    >
      <!-- 复选框 -->
      <el-table-column v-if="isSelectabled" type="selection" width="50" />
      
      <template v-for="(column,index) in tableColunms" :key="index">
        <!-- 文字不需要特殊显示 -->
        <el-table-column
          :type="column.type"
          :prop="column.prop"
          :label="column.label"
          :fixed="column.fixed || true"
          :sortable="column.sortable || false"
          :show-overflow-tooltip="column.overHidden || false"
          :width="column.width"
          :min-width="column.minWidth || '50px'"
          :align="column.align || 'center'"
          :formatter="column.formatter"
        >
            <!-- <template #default="scope" >
                <span v-if="scope.column.type !=='index'">{{ scope.row[column.prop] ? scope.row[column.prop] : "" }}</span>
                <span v-if="scope.column.type ==='index'">{{ (pagination.pageNum-1) * pagination.pageSize + scope.$index + 1}}</span>
            </template> -->
        </el-table-column>
      </template>

      <!-- 操作列插槽 -->
      <el-table-column
        label="操作"
        fixed="right"
        align="center"
      >
        <template #default="scope">
            <!-- 当操作按钮少于3个,建议使用mode:'inline',默认为'dropdown'模式 -->
            <table-dropdown
                :actionColumns='()=>actionColumns(scope)'
                :scope="scope"
                :mode="actionMode || 'dropdown'"
            />
        </template>
      </el-table-column>
    </el-table>
    
    <!-- 分页 -->
    <div class="pagination">
        <el-pagination
            v-model:page-size="pagination.pageSize"
            v-model:current-page="pagination.pageNum"
            :total="total"
            :layout="layout"
            :page-sizes="pageSizesArr"
            @size-change="sizeChange"
            @current-change="currentChange"
        />
    </div>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';
import TableDropdown from '@/components/TableDropdown/dropdown.vue'

const emits = defineEmits(['sizeChange', 'currentChange'])
const props = defineProps({
    tableData:{
        type: Array,
        default:[]
    },
    tableColunms:{
        type: Array,
        default: []
    },
    actionColumns:{
        type: Function,
        default:() => {}
    },
    actionMode:{
        type: String,
        default: 'dropdown'
    },
    opColunms:{
        type: Object,
        default: {}
    },
    border:{ // 是否带有纵向边框
        type: Boolean,
        default: false
    },
    loading:{
        type: Boolean,
        default: false
    },
    isSelectabled: { // 是否带有复选框
        type: Boolean,
        default: false
    },
    pagination: {
        type: Object,
        default: () => {
            return {pageSize: 10, pageNum: 1}
        }
    },
    pageSizesArr:{
        type: Array,
        default: () => {
            return [10,20,30,50]
        }
    },
    stripe: { // 是否为斑马纹 table
        type: Boolean,
        default: false
    },
    total: {
        type: Number,
        required: true,
        default: 0
    },
    layout:{
        type: String,
        default: "total, sizes, prev, pager, next, jumper"
    }
})
// 触发选择框
const selectionChange = (val) => {
   console.log(val)
}
// 切换分页size
const sizeChange = (val) => {
    emits('sizeChange', val)
}
// 切换分页
const currentChange = (val) => {
    emits('currentChange', val)
}

</script>

<style lang="scss">
/* .el-table .warning-row {
  --el-table-tr-bg-color: var(--el-color-warning-light-9);
}
.el-table .success-row {
  --el-table-tr-bg-color: var(--el-color-success-light-9);
} */
.pagination{
    margin: 15px auto;
    display: flex;
    justify-content: center;
}
.el-table{
    .el-table__header .cell{
      color: #000;
    }
}
</style>

我们可以看到Table组件里调用了TableDropdown,也是我自定义的一个组件,用于表格的操作列按表格数据有条件渲染成不同的按钮。下面为此组件的代码:

<!--
 * @Author: Cocoon_xu
 * @LastEditTime: 2024-02-18 16:38:25
 * @Description: 表格操作列表
-->
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
    actionColumns:{
      type: Function,
      default: () => {}
   },
   scope: {
      type: Object,
      default: {}
   },
   mode: {
      type: String,
      default: 'dropdown'
   }
})

</script>

<template>
    <template v-if="mode === 'inline'">
        <el-button
            v-for="(item,index) in actionColumns(scope)"
            text
            :key="index"
            :icon="item.icon"
            :disabled="item.disabled"
            :style="{marginLeft:0, color: item.color}"
            @click="(e)=>{
                e.preventDefault();
                let row = JSON.parse(JSON.stringify(scope.row))
                item.event(row);
            }"
        >
            {{ item.label }}
        </el-button> 
    </template>
    <template v-else>
        <el-dropdown>
            <span class="el-dropdown-link">
                <el-icon color="#409EFC"><Menu/></el-icon>
            </span>
            <template #dropdown>
                <el-dropdown-menu>
                    <el-dropdown-item
                        v-for="(item, index) in actionColumns(scope)"
                        :key="index"
                        :icon="item.icon"
                        :disabled="item.disabled"
                        @click="(e)=>{
                            e.preventDefault();
                            let row = JSON.parse(JSON.stringify(scope.row))
                            item.event(row);
                        }"
                    >
                       <span>{{ item.label }}</span>
                    </el-dropdown-item>
                </el-dropdown-menu>
            </template>
        </el-dropdown>
    </template>
</template>

<style lang="scss">
.table-menu{
    background: transparent;
    .el-menu-item{
        padding: 0;
        height: 24px;
        line-height: 24px;
    }
}
</style>

最后,就是调用组件的使用

<!--
 * @Author: Cocoon_xu
 * @LastEditTime: 2024-02-18 16:38:25
 * @Description: 组件调用
-->

<template>
    <div class="table-box">
        <common-table
            :loading="loading"
            :tableColunms="tableColunms"
            :actionColumns="actionColumns"
            :tableData="tableData"
            :pagination="pagination"
            :total="total"
            :stripe="true"
            :isSelectabled="false"
            @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange"
        ></common-table>
    </div>
</template>

<script setup>
import { ref, onMounted, h } from 'vue';
import CommonTable from '@/components/Table/index.vue';

const loading = ref(false)
const tableData = ref([])
const total = ref(0)
const pagination = ref({
    pageSize: 10,
    pageNum: 1
})
const tableColunms = [
    {
        label:'序号',
        width: 80,
        formatter:(row, columm, cellValue, index) => {
            return (pagination.value.pageNum-1) * pagination.value.pageSize + index + 1
        }
    },{
        label:'标题',
        prop:'title',
        minWidth: 120,
        overHidden: true
    },{
        label:'发布人',
        prop:'sendByName',
    },{
        label:'审核状态',
        prop:'submitStatus',
        minWidth: 70,
        formatter: (row, column, cellValue, index) => {
            if(cellValue === '1'){
                return h('span',{class:'draft'},'草稿')
            }else if(row.auditStatus === 'active'){
                return h('span',{class:'waitExamine'},'待审核')
            }else if(row.auditStatus === 'completed'){
                return h('span',{class:'pass'},'已通过')
            }else if(row.auditStatus === 'terminated'){
                return h('span',{class:'error'},'审批终止')
            }else if(row.auditStatus === 'rejected'){
                return h('span',{class:'error'},'被退回')
            }else{
                return '--'
            }
        }
    }
]
// 操作列按钮
const actionColumns = (scope) =>{
    let btns = [{
        label:'查看',
        type:'check',
        icon:'View',
        color:'#409EFC',
        disabled: false,
        event:(row) => {
            console.log(row)
            detail(row)
        }
    }];
    if(scope.row.auditStatus == 1 || (scope.row.auditStatus == 'rejected')){
      btns.push({
        label:'编辑',
        type:'edit',
        icon:'Edit',
        color:'#409EFC',
        disabled: false,
        event:(row) => {
            console.log(row)
        }
      })
    }
    if((scope.row.sendStatus == 0 && scope.row.auditStatus != 'completed'))){
      btns.push({
        label:'删除',
        type:'delete',
        icon:'Delete',
        color:'#409EFC',
        disabled: false,
        event:(row) => {
            console.log(row)
        }
      })
    }
    return btns;
}

// 切换当前分页
const handleCurrentChange = (val) => {
    pagination.value = {
        pageNum: val,
        pageSize: pagination.value.pageSize
    }
    getConListInfoPagefn();
}
// 切换分页size
const handleSizeChange = (val) => {
    pagination.value = {
        pageNum: 1,
        pageSize: val
    }
    getConListInfoPagefn();
}


</script>

代码部分结束!希望对你有所帮助!

  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值