6

element-ui简单table封装

面对element-ui table 有好多可以复用,首先来学习下简单封装复用table写法,实现高效小前端,减少一下代码复用,提高效率完成table数据渲染复用;文章后面涉及到VUE3+element-plus写法

效果图大致(主题颜色是本人项目的修改过后)

image

1、首先创建一个table封装的组件

<template>
  <!-- 
    @param tableData 父组件传值
    @param loading [Boolean] 加载提示
    @param border [Boolean] table边框
  -->
  <el-table
      ref="table"
      :data="tableData"
      v-loading="loading"
      element-loading-text="Loading"
      :border="border"
      fit highlight-current-row
      tooltip-effect="dark"
      style="width:100%"
      @sort-change="handleSortChange"
      @selection-change="handleSelectionChange">
        <!-- 
          @name 展开查看详情
          @param tableLabel 父组件传值
          @param label [string] 名称
          @param render 配置格式化数据
         -->
        <el-table-column type="expand">
          <template slot-scope="scope">
            <el-form 
            class="table-expand" 
            >
              <el-form-item 
                v-for="(item,index) in tableLabel"
                :key="index"
                :label="item.label">
                <span v-if="item.render">
                  {{item.render(scope.row)}}
                </span>
                <span v-else>{{scope.row[item.param]}}</span>
              </el-form-item>
            </el-form>
          </template>
        </el-table-column>
        <!--
          @name 操作
          @param tableOption 父组件传值
          @param label [string] 名称
          @param width [string] 宽度
          @param options [array] 按钮数组
          @param type 按钮类型
          @param icon 按钮图标
          @param handleButton 按钮方法 
         -->
        <el-table-column 
          v-if="tableOption.label" 
          :width="tableOption.width" 
          :label="tableOption.label" 
          align="center" 
          class-name="small-padding fixed-width">
          <template slot-scope="scope">
            <el-button  
            v-for="(item,index) in tableOption.options" 
            :key="index" 
            :type="item.type" 
            :icon="item.icon" 
            @click="handleButton(item.methods,scope.row,scope.$index)" 
            size="mini">
              {{item.label}}
            </el-button>
          </template>
        </el-table-column>
        <!-- 
          @name 标题+表格数据显示
          @param tableLabel 父组件传值
          @param width 【string】宽度
          @param align 【string】对齐方式
          @param label [string] 名称
          @param sortable [Boolean] 排序
          @param render 配置格式化数据
        -->
        <div
          v-for="(item,index) in tableLabel" 
          :key="index">
          <el-table-column 
            v-if="item.show"
            :width="item.width ? item.width : ''" 
            :align="item.align" 
            :label="item.label" 
            :prop="item.param" 
            :sortable="item.sortable ? 'custom' : false">
            <template slot-scope="scope">
              <span v-if="item.render">
                {{item.render(scope.row)}}
              </span>
              <span v-else>{{scope.row[item.param]}}</span>
            </template>
          </el-table-column>
        </div>

    </el-table>
</template>

<script>
/**
 * @name 表格封装
 * @export TableElement
 * @param loading [Boolean] 配置加载提示
 * @param tableData [Array] 数据
 * @param tableMain [Array] 数据详情
 * @param tableLabel [Array] 配置表格头部
 * @param tableOption [Object] 操作按钮
 * @param border [Boolean] 配置边框
 */
  export default {
    props:{
    loading:{
      type:Boolean,
      default:false
    },
    tableData:{
      type:Array,
      default: () => {
        return []
      }
    },
    tableMain:{
      type:Array,
      default: () => {
        return []
      }
    },
    tableLabel:{
      type:Array,
      default: () => {
        return []
      }
    },
    tableOption:{
      type:Object,
      default: () => {
        return {}
      }
    },
    border:{
      type:Boolean,
      default: false
    }
  },
  components:{},
  methods: {
    // methods:按钮名称 row:同一行的数据 index:第几行(0开始)
    handleButton(methods,row,index){  // 按钮事件
      console.log(row)
      this.$emit('handleButton',{'methods':methods,'row':row})
    },
    handleSortChange(val){  // 排序
      this.$emit('handleSortChange',val)
    },
    handleSelectionChange(val){
      this.$emit('handleSelectionChange',val)
    }
  }
    
  }
</script>

<style lang="scss" scoped>
  .table-expand {
    font-size: 0;
    display: flex;
    flex-wrap: wrap;
  }
  .table-expand label {
    width: 90px;
    color: #99a9bf;
  }
  .table-expand .el-form-item {
    margin-right: 0;
    margin-bottom: 0;
    width: 50%;
  }
</style>

2、table 组件导入使用


<template>
  <div>
    <TableElement
      :loading="loading"
      :table-data="tableData"
      :table-label="tableLabel"
      :table-option="tableOption"
      @handleButton="handleButton"
      @handleSortChange="handleSortChange"
      @handleSelectionChange="handleSelectionChange"
    ></TableElement>
  </div>
</template>

<script>
import TableElement from "@/components/Table/index"; // 导入table组件,具体路径以自己为主
export default {
  data() {
    return {
      loading:false,
      border:true,
      tableData: [
        {
          usr:'yy',
          company:'hahahha',
          email:'find@allyum.com',
          registTime:'2019 8',
          status:'1'
        },
        {
          usr:'aa',
          company:'hahahha',
          email:'find@allyum.com',
          registTime:'2019 8',
          status:'1'
        },{
          usr:'c',
          company:'hahahha',
          email:'find@allyum.com',
          registTime:'2019 8',
          status:'1'
        },{
          usr:'b',
          company:'hahahha',
          email:'find@allyum.com',
          registTime:'2019 8',
          status:'1'
        }
      ],
      tableLabel: [
        { label: "用户名", param: "usr", align: "center", sortable: true,show:true },
        { label: "公司名称", param: "company", align: "center",show:false },
        { label: "办公邮箱", param: "email", align: "center", width: "200",show:true },
        { label: "注册时间",param: "registTime",lign: "center",show:true,ortable: true},
        { label: "审核状态",param: "status",align: "center",show:true,sortable: true,
          render: row => {
            if (row.status === 0) {
              return "未审核";
            } else if (row.status === 1) {
              return "审核通过";
            } else if (row.status === 2) {
              return "审核不通过";
            } else {
              return "禁用";
            }
          }
        }
      ],
      tableOption: {
        label: "操作",
        width: "200",
        options: [
          {
            label: "预览",
            type: "primary",
            icon: "el-icon-view",
            methods: "preview"
          },
          {
            label: "审核",
            type: "primary",
            icon: "el-icon-upload2",
            methods: "audit"
          }
        ]
      }
    };
  },
  methods:{
    handleButton(data) {
      switch(data.methods) {
        case 'preview':
          this.preview()
          break;
        case 'audit':
          console.log('audit')
          break;
      }
    },
    preview() {
      console.log('preview');
    },
    // 排序规则
    handleSortChange() {
      console.log('排序规则')
    },
    handleSelectionChange() {}

  },
  components: {
    TableElement
  }
};
</script>

<style lang="scss" scoped>
</style>

A、扩展“vue3 + element-plus”,table组件封装

<template>
  <div>
    <!-- 
    @param tableData 父组件传值
    @param loading [Boolean] 加载提示
    @param border [Boolean] table边框
  -->
    <el-table
      ref="table"
      :data="tableData"
      v-loading="loading"
      element-loading-text="Loading"
      :border="border"
      fit
      highlight-current-row
      tooltip-effect="dark"
      style="width: 100%"
      @sort-change="handleSortChange"
      @selection-change="handleSelectionChange"
    >
      <!-- 
          @name 展开查看详情
          @param tableLabel 父组件传值
          @param label [string] 名称
          @param render 配置格式化数据
         -->
      <el-table-column type="expand">
        <template #default="props">
          <el-form class="table-expand">
            <el-form-item
              v-for="(item, index) in tableLabel"
              :key="index"
              :label="item.label"
            >
              <span v-if="item.render">
                {{ item.render(props.row) }}
              </span>
              <span v-else>{{ props.row[item.param] }}</span>
            </el-form-item>
          </el-form>
        </template>
      </el-table-column>
      <!--
          @name 操作
          @param tableOption 父组件传值
          @param label [string] 名称
          @param width [string] 宽度
          @param options [array] 按钮数组
          @param type 按钮类型
          @param icon 按钮图标
          @param handleButton 按钮方法 
         -->
      <el-table-column
        v-if="tableOption.label"
        :width="tableOption.width"
        :label="tableOption.label"
        align="center"
        class-name="small-padding fixed-width"
      >
        <template #default="props">
          <el-button
            v-for="(item, index) in tableOption.options"
            :key="index"
            :type="item.type"
            :icon="item.icon"
            @click="handleButton(item.methods, props.row, props.$index)"
            size="mini"
          >
            {{ item.label }}
          </el-button>
        </template>
      </el-table-column>
      <!-- 
          @name 标题+表格数据显示
          @param tableLabel 父组件传值
          @param width 【string】宽度
          @param align 【string】对齐方式
          @param label [string] 名称
          @param sortable [Boolean] 排序
          @param render 配置格式化数据
        -->
      <div v-for="(item, index) in tableLabel" :key="index">
        <el-table-column
          v-if="item.show"
          :width="item.width ? item.width : ''"
          :align="item.align"
          :label="item.label"
          :prop="item.param"
          :sortable="item.sortable ? 'custom' : false"
        >
          <template #default="props">
            <span v-if="item.render">
              {{ item.render(props.row) }}
            </span>
            <span v-else>{{ props.row[item.param] }}</span>
          </template>
        </el-table-column>
      </div>
    </el-table>
  </div>
</template>

<script lang="ts">
/**
 * @name 表格封装
 * @export TableElement
 * @param loading [Boolean] 配置加载提示
 * @param tableData [Array] 数据
 * @param tableMain [Array] 数据详情
 * @param tableLabel [Array] 配置表格头部
 * @param tableOption [Object] 操作按钮
 * @param border [Boolean] 配置边框
 */
export default {
  props: {
    loading: {
      type: Boolean,
      default: false,
    },
    tableData: {
      type: Array,
      default: () => {
        return [];
      },
    },
    tableMain: {
      type: Array,
      default: () => {
        return [];
      },
    },
    tableLabel: {
      type: Array,
      default: () => {
        return [];
      },
    },
    tableOption: {
      type: Object,
      default: () => {
        return {};
      },
    },
    border: {
      type: Boolean,
      default: false,
    },
  },
  setup(props: any, { emit }: { emit: any }) {
    //  // methods:按钮名称 row:同一行的数据 index:第几行(0开始)
    const handleButton = (methods: string, row: any, index: number) => {
      emit("handleButton", { methods: methods, row: row });
    };
    const handleSortChange = (val: any) => {
      // 排序
      emit("handleSortChange", val);
    };
    const handleSelectionChange = (val: any) => {
      emit("handleSelectionChange", val);
    };
    return {
      handleButton,
      handleSortChange,
      handleSelectionChange,
    };
  },
};
</script>

<style lang="scss" scoped>
.table-expand {
  font-size: 0;
  display: flex;
  flex-wrap: wrap;
}

.table-expand label {
  width: 90px;
  color: #99a9bf;
}

.table-expand .el-form-item {
  margin-right: 0;
  margin-bottom: 0;
  width: 50%;
}
</style>

B、vue3 组件导入使用

<template lang="">
<div>
  {{loading}}
  <ELTable
  :loading="loading"
      :table-data="tableData"
      :table-label="tableLabel"
      :table-option="tableOption"
      ></ELTable>
</div>
</template>

<script lang="ts">
/**
 * @name 管理用户
 * */
import {
  defineComponent,
  reactive,
  ref
} from 'vue'
import ELTable from '@/components/table/table.vue'

interface costomerData {
  tableData: any;
  loading: boolean;
  tableLabel: any;
  tableOption: object;
  handleButton: (data: any) => void;
  handleSortChange: () => void;
  handleSelectionChange: () => void;
}
export default defineComponent({
  components: {
    ELTable
  },
  setup(): costomerData {
    const tableData = reactive([{
        usr: 'yy',
        company: 'hahahha',
        email: 'find@allyum.com',
        registTime: '2019 8',
        status: '1'
      },
      {
        usr: 'aa',
        company: 'hahahha',
        email: 'find@allyum.com',
        registTime: '2019 8',
        status: '1'
      }, {
        usr: 'c',
        company: 'hahahha',
        email: 'find@allyum.com',
        registTime: '2019 8',
        status: '1'
      }, {
        usr: 'b',
        company: 'hahahha',
        email: 'find@allyum.com',
        registTime: '2019 8',
        status: '1'
      }
    ])
    
    const tableLabel = reactive([
      { label: "用户名", param: "usr", align: "center", sortable: true,show:true },
        { label: "公司名称", param: "company", align: "center",show:false },
        { label: "办公邮箱", param: "email", align: "center", width: "200",show:true },
        { label: "注册时间",param: "registTime",lign: "center",show:true,ortable: true},
        { label: "审核状态",param: "status",align: "center",show:true,sortable: true,
          render: (row:any) => {
            if (row.status === 0) {
              return "未审核";
            } else if (row.status === 1) {
              return "审核通过";
            } else if (row.status === 2) {
              return "审核不通过";
            } else {
              return "禁用";
            }
          }
        }
    ])
    const loading = ref<boolean>(false); 
    const tableOption = reactive({
      label: "操作",
        width: "200",
        options: [
          {
            label: "预览",
            type: "primary",
            icon: "el-icon-view",
            methods: "preview"
          },
          {
            label: "审核",
            type: "primary",
            icon: "el-icon-upload2",
            methods: "audit"
          }
        ]
    })
    
    const handleButton = (data: any) => {
      switch (data.methods) {
        case "preview":
          preview(data.row);
          break;
        case "audit":
          console.log("audit");
          break;
      }
    };
    const preview = (row: any) => {
      console.log(row); // 获取到编辑的一行数据
    };
    // 排序规则
    const handleSortChange = () => {
      console.log("排序规则");
    };
    const handleSelectionChange = () => {};

    return {
      tableData,
      tableLabel,
      tableOption,
      loading,
      handleButton,
      handleSortChange,
      handleSelectionChange,
    }
  }
})
</script>

效果图大致(主题颜色是本人项目的修改过后)

image

总结

  1. 简单的学习封装,如果有更好建议可以在下面留言
  2. 上面的有写规则例如排序的还没完善,后面更新一些规则进去

hhemin
23 声望1 粉丝

无bug是梦想,年薪百万是理想