【基于vue3 对element-plus Table二次封装,render函数实现自定义内容】

最近没有工作,写点小项目。写写笔记记录一下。
这里把element-plus的table进行二次封装,实现“显示/隐藏列”、“按钮插槽”以及实现类似iview框架直接的在表头里面写render函数。

1.封装效果

在这里插入图片描述

2. 实现代码

A-table.vue
HTML部分

<!-- 表格 (START) -->
      <div class="table">
        <div style="padding: 0px 10px">
    <!-- 表格头部操作栏 (START) -->
          <div style="float: left">
            <slot name="header-l"></slot>
          </div>
          <div  style="float: right">
            <slot name="header-r"></slot>
            <!-- 表头筛选 -->
            <div class="transfer">
              <el-popover placement="bottom" trigger="click" title="显示/隐藏列" width="340px">
                <template #reference>
                  <el-button :icon="Filter" size="mini"></el-button>
                </template>
                <el-checkbox-group v-model="checkedValue" @change="handleColumnsChange" style="height: 140px; overflow: auto">
                  <el-checkbox  v-for="item in checkColumns" :key="item.prop" :label="item.label"></el-checkbox>
                </el-checkbox-group>
              </el-popover>
            </div>
          </div>
        </div>
    <!-- 表格头部操作栏 (END) -->

    <!-- 表格内容 (START) -->
        <el-table
          :data="tableDataValue"
          v-loading="options.loading"
          :size="options.size"
          :max-height="options.maxHeight"
          :stripe="options.stripe"
          :border="options.border"
          :fit="options.fit"
          :highlight-current-row="options.heightCurrentRow"
          :lazy="options.lazy"
          ref="eleTable"
          @row-click="clickRow"
          @row-dblclick="dblclickRow"
          @row-contextmenu="contextmenu"
          @header-click="headClick"
          @header-contextmenu="headcontextmenu"
          @select="select"
          @select-all="selectAll"
          @current-change="rowChange"
          @selection-change="handleSelectionChange">
          <template v-for="(item, index) in filterColumns" :key="index">
            <!-- 复选框 (START)-->
            <el-table-column v-if="item.type === 'selection'" type="selection" :width="item.minWidth?item.minWidth : 60" ></el-table-column>
            <!-- 复选框 (END) -->

            <!-- 序号 (START) -->
            <el-table-column v-else-if="item.type === 'index'" type="index" :label="item.label?item.label : '序号'" :width="item.minWidth?item.minWidth : 80" :align="item.align?item.align : 'center'"></el-table-column>
            <!-- 序号 (END) -->

            <!-- 自定义slot (START) -->
            <slot v-else-if="item.slot" :name="item.slot" :tit="index"></slot>
            <!-- 自定义slot (END) -->

            <!-- 默认渲染列 (START) -->
            <el-table-column v-else
              :prop="item.prop"
              :label="item.label"
              :align="item.align"
              :min-width="item.minWidth"
              :show-overflow-tooltip="true"
            >
              <template #default="scope">
                <template v-if="!item.render">
                  <span>{{scope.row[item.prop]}}</span>
                </template>
                <template v-else>
                  <E-expand :column="item" :row="scope.row" :render="item.render" :index="scope.$index" />
                </template>
              </template>
            </el-table-column>
          </template>
        </el-table>
    <!-- 表格内容 (END) -->

    <!-- 分页 (START) -->
        <div style="text-align: right">
          <el-pagination
            v-model:currentPage="pageNum"
            :page-size="mPageSize"
            :page-sizes="pageSizeOpts"
            layout="total, sizes, prev, pager, next, jumper"
            :total="total"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange">
          </el-pagination>
        </div>
    <!-- 分页 (END) -->
      </div>
<!-- 表格 (END) -->

JS部分

<script>
import { computed, getCurrentInstance, onMounted, reactive, toRefs, watch,toRaw } from 'vue'
import {useStore} from 'vuex'
import {Filter, ElMessage} from '@element-plus/icons-vue'
import EExpand from './eExpand'
export default {
  components: {EExpand },
  name: 'IviewVue3JsATable',
  props: {
    config: {type: Object},
    action: {type: String}, // 请求地址
    tableHeight: {type: Number},
    size: {type: String},
    pageSize: {type: Number, default: 10},
    options: { // 表格配置项
      type: Object,
      default: () => {
        return {
          // height: 400,
          stripe: false, // 斑马纹
          highlightCurrentRow: true, // 是否要高亮当前行
          border: false, // 是否有纵向边框
          fit: false, // 列的宽度是否自撑开
          size: 'medium', // Table 的尺寸
          maxHeight: 600, // Table 的最大高度。 
          loading:false,//是否需要等待效果
          lazy:false,// 是否需要懒加载
        }
      }
    },
  },
  setup(props, context) {
    const store = useStore()
    const {proxy} = getCurrentInstance()

    const state = reactive({
      isRowChange: false, // 表格列是否改变
      checkedValue: [], // 复选框已选数据
      tableDataValue: [],
      total: 0, // 表格数据总数
      mPageSize: props.pageSize,
      pageNum: 1,
    })    

/**复选框参数与配置 (START) */
    // 复选框选择项
    const checkColumns = computed(() => {return props.config.table.columns.filter(i => i.label)})
    // 复选框已选项 -model
    const checked = computed(() => {return proxy.checkColumns.map((i, index) =>{ return i.label})})
/**复选框参数与配置 (END) */

    onMounted(() => {
      getData()
      state.checkedValue = checked.value
    })
/**表格参数和配置 (START) */
    const tableConfig = computed(() => {return props.config.table}).value
    // 筛选后的表头
     const filterColumns = computed( () => {
      if(!state.isChange) return props.config.table.columns
      return props.config.table.columns.filter( i => !i.type &&  state.checkedValue.includes(i.label) || i.type)})
/**表格参数和配置 (END) */

/**每页展现条数选择项 */
    const pageSizeOpts = computed(() => {return [...new Set([10,20,30,40, proxy.pageSize])].sort((a, b) => a-b)})

    const getData = async () => {
      if(!props.action) return 
      props.options.loading = true
      const { data, err} = await store.dispatch(props.action, {pageNum: state.pageNum, pageSize: state.mPageSize, ...proxy.formObj.formData()})
      props.options.loading = false
      if (err) return ElMessage({showClose: true,message: err,type: 'error',center: true,duration: 3000})
      state.tableDataValue = data.records
      state.total = data.total
    }

// 表头筛选触发事件
    const handleColumnsChange = (value) => {
      state.isChange = true
      state.value = value
    }
// 单击行事件
    const clickRow = (row, column, event) => {
      let data = {row,column,event}
      context.emit('clickRow', data)
    }
// 双击行事件
    const dblclickRow = (row, column, event) => {
      let data = {row,column,event}
       context.emit('dblclickRow', data)
    }
// 右击行事件
    const contextmenu = (row, column, event) => {
      let data = {row,column,event}
       context.emit('contextmenu', data)
    }
// 头部列点击事件
    const headClick = (row, column, event) => {
      let data = {row,column,event}
       context.emit('headClick', data)
    }
// 头部列右击事件
    const headcontextmenu = (row, column, event) => {
      let data = {row,column,event}
       context.emit('headcontextmenu', data)
    }
// 勾选复选框事件
    const select = (row, column, event) => {
      let data = {row,column,event}
       context.emit('select', data)
    }
// 勾选全选事件
    const selectAll = (row, column, event) => {
      let data = {row,column,event}
       context.emit('selectAll', data)
    }
// 行改变事件
    const rowChange = (row, column, event) => {
      let data = {row,column,event}
       context.emit('rowChange', data)
    }
// 多行选中事件
    const handleSelectionChange = (row, column, event) => {
      let data = {row,column,event}
       context.emit('handleSelectionChange', data)
    }
// 页面展现条数事件
    const handleSizeChange = (pageSize) => {
      proxy.mPageSize = pageSize
      getData()
      console.log('pageSize :>> ', pageSize);
    }
// 页面跳转事件
    const handleCurrentChange = (pageNum) => {
      proxy.pageNum = pageNum
      getData()
      console.log('pageNum :>> ', pageNum);
    }
    const handleEdit = (index, row) => {
      console.log('scope', toRaw(row))
    }
    return {
      Filter,
      ...toRefs(state),
      tableConfig,
      checkColumns,
      filterColumns,
      pageSizeOpts,
      handleEdit,
      clickRow,
      dblclickRow,
      contextmenu,
      headClick,
      headcontextmenu,
      select,
      selectAll,
      rowChange,
      handleSelectionChange,
      handleColumnsChange,
      handleSizeChange,
      handleCurrentChange
    }
  }
}
</script>

E-expand.js

import { h,getCurrentInstance,defineComponent } from 'vue';
export default defineComponent({
  name: 'Expand',
    props: {
        row: Object,
        render: Function,
        index: Number,
        column: {
            type: Object,
            default: null
        }
    },
    // proxy: getCurrentInstance(),
    render() {
        return this.render(this.row)
    }
})

3.调用方法

引入组件

import {ATable} from '_c/table'

调用组件
html部分

<a-table action="business/getApplyEcectionList" :config="config" size="small" @row-change="rowChange">
    <template #header-l>
       <el-button type="primary" size="mini" @click="addApplyVisible = true" >新增</el-button>
     </template>
 </a-table>

js部分 – 定义数据

const state = reactive({
    config: {
       table: {
         columns: [
           {type: 'selection', minWidth: 40, },
           {label: '出差人', prop: 'name', minWidth: 100,align: 'center'},
           {label: '部门名称', prop: 'department', minWidth: 100,align: 'center'},
           {label: '项目名称', prop: 'project', minWidth: 140,align: 'center'},
           {label: '目的地', prop: 'destination', minWidth: 200,align: 'center'},
           {label: '出发时间', prop: 'startTime', minWidth: 180,align: 'center'},
           {label: '出差天数', prop: 'day', minWidth: 100,align: 'center'},
           {label: '出行工具', prop: 'TravelTool', minWidth: 100,align: 'center'},
           {label: '流程状态', prop: 'status', minWidth: 100,align: 'center',
             render: (row) =>
             <div>{row.status}</div>
           },
           {label: '操作栏', prop: 'action', minWidth: 120,align: 'center',
           render: () => 
             <div>
               <el-button type="text">详情</el-button>
               <el-button type="text">审批进度</el-button>
             </div>
           },
         ],
       },
     },
  })

实现的代码部分是上面部分。另外说说有些没解决的细节部分吧。(主要是太懒)

4.缺陷部分

1. 在对表格列进行显示隐藏操作时: 表格会出现抖动。
2. 在对表格列进行显示隐藏操作时: 表格列宽不会自适应的填满容器。

如果各位优秀的朋友们,有解决缺陷部分的思路或者对封装有新的想法,可以告诉我。

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
Vue基于Element UI Table二次封装可以通过创建一个自定义的组件来实现。以下是一个简单的示例,演示了如何封装一个基于Element UI Table的组件: ```vue <template> <el-table :data="tableData" :row-key="rowKey" :height="height"> <!-- 渲染表头 --> <el-table-column v-for="column in columns" :key="column.prop" :prop="column.prop" :label="column.label"> <!-- 自定义插槽 --> <template slot-scope="scope"> <slot :column="column" :scope="scope"></slot> </template> </el-table-column> </el-table> </template> <script> export default { name: 'CustomTable', props: { tableData: { type: Array, required: true }, columns: { type: Array, required: true }, rowKey: { type: String, required: true }, height: { type: String, default: 'auto' } } } </script> ``` 在这个示例中,我们创建了一个名为`CustomTable`的组件。它接受`tableData`、`columns`、`rowKey`和`height`作为props,分别表示表格数据、表格列配置、行数据的唯一标识以及表格的高度。 在模板中,我们使用`el-table`和`el-table-column`来渲染Element UI的表格。我们使用了`v-for`指令来循环渲染表格列,并通过`slot-scope`来传递数据给插槽。插槽可以在父组件中定义,并在插槽中使用自定义的组件来渲染表格单元格内容。 通过这种方式,我们可以在父组件中使用这个封装自定义表格组件,并通过插槽来定制表格的内容和样式。 希望这个简单的示例能帮助到你进行Vue基于Element UI Table二次封装。如果有任何问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值