基于element-ui进行二次封装的表格组件

  • 基于element-ui进行二次封装的表格组件已关闭评论
  • 268 次浏览
  • A+
所属分类:Web前端
<!-- * @description 表格组件 * @fileName TableList.vue * @authorQ * @date 2021/05/15 15:13:45 --> <template>   <div class="table-container">     <el-table       v-if="showTable"       ref="filterTable"       :span-method="spanName?objectSpanMethod:null"       :data="data"       :show-summary="showSummary.show ? showSummary.show : null"       :summary-method="showSummary.show ? summaryMethod : null"       :sum-text="showSummary.sumText ? showSummary.sumText : null"       @filter-change="handleFilterChange"       :border="border"       :stripe="stripe"       empty-text="暂无数据"       style="width: 100%"       :show-header="showHeader"       :tooltip-effect="tooltipTheme"       @selection-change="handleSelectionChange"     >       <!-- 选择框列 -->       <el-table-column         v-if="selection"         type="selection"         :align="'center'"       ></el-table-column>       <!-- 排序列 -->       <el-table-column         v-if="indexShow"         width="100"         label="序号"         :align="'center'"       >         <template slot-scope="scope">           <div>             <span>{{ scope.$index + 1 }}</span>           </div>         </template>       </el-table-column>        <template v-for="(item, index) in columns">         <!-- 特殊列处理 -->         <template v-if="item.render">           <!-- visible 是否显示该列 -->           <el-table-column             v-if="item.visible"             :filters="item.filters ? item.filters : null"             :column-key="item.prop"             :key="index"             :prop="item.prop ? item.prop : null"             :align="item.align ? item.align : null"             :fixed="item.fixed ? item.fixed : null"             :label="item.label ? item.label : null"             :show-overflow-tooltip="item.tooltip"             :class-name="className"             :sortable="item.sortable ? item.sortable : false"             :width="item.width ? item.width : null"           >             <!-- 多级表头 -->             <template v-if="item.children && item.children.length > 0">               <div v-for="(item1, index1) in item.children" :key="index1">                 <el-table-column                   :key="index1"                   :filters="item.filters ? item.filters : null"                   :column-key="item.prop"                   :prop="item1.prop ? item1.prop : null"                   :align="item1.align ? item1.align : null"                   :fixed="item1.fixed ? item1.fixed : null"                   :label="item1.label ? item1.label : null"                   :show-overflow-tooltip="item1.tooltip"                   :class-name="className"                   :sortable="item1.sortable ? item1.sortable : false"                   :width="item1.width ? item1.width : null"                 >                   <exSlot                     :render="item1.render"                     :row="scope.row"                     :index1="scope.$index"                     :column="item1"                   />                 </el-table-column>               </div>             </template>             <!-- 不是多级表头 -->             <template slot-scope="scope">               <exSlot                 :render="item.render"                 :row="scope.row"                 :index="scope.$index"                 :column="item"               />             </template>           </el-table-column>         </template>          <!-- 正常列 -->         <template v-else>           <!-- visible 是否显示该列 -->           <el-table-column             v-if="item.visible"             :key="index"             :column-key="item.prop"             :filters="item.filters ? item.filters : null"             :prop="item.prop ? item.prop : null"             :align="item.align ? item.align : null"             :fixed="item.fixed ? item.fixed : null"             :label="item.label ? item.label : null"             :class-name="className"             :show-overflow-tooltip="item.tooltip"             :sortable="item.sortable ? item.sortable : false"             :width="item.width ? item.width : null"           >             <!-- 多级表头 -->             <template v-if="item.children && item.children.length > 0">               <template v-for="(item1, index1) in item.children">                 <el-table-column                   :prop="item1.prop ? item1.prop : null"                   :column-key="item.prop"                   :filters="item.filters ? item.filters : null"                   :align="item1.align ? item1.align : null"                   :fixed="item1.fixed ? item1.fixed : null"                   :label="item1.label ? item1.label : null"                   :show-overflow-tooltip="item1.tooltip"                   :class-name="className"                   :sortable="item1.sortable ? item1.sortable : false"                   :width="item1.width ? item1.width : null"                 >                   <template slot-scope="scope">                     <span v-html="formatter(scope.row[item1.prop])"></span>                   </template>                 </el-table-column>               </template>             </template>             <template slot-scope="scope">               <!-- 字典处理 -->               <template v-if="item.dict">                 <!-- 判断原始数据是否有效,有效转为字典数据,无效则转为--占位符 -->                 <span                   v-if="!scope.row[item.prop]"                   v-html="formatter(scope.row[item.prop])"                 ></span>                 <dict-tag                   v-else                   :options="dict.type[item.prop]"                   :value="scope.row[item.prop]"                 />               </template>               <!-- 时间格式化 -->               <span v-else-if="item.time">{{                 parseTime(scope.row[item.prop], "{y}-{m}-{d}")               }}</span>               <!-- 不做处理 -->               <span v-else v-html="formatter(scope.row[item.prop])"></span>             </template>           </el-table-column>         </template>       </template>        <!-- 操作列 -->       <el-table-column         v-if="isEdit === true"         label="操作"         :align="'center'"         width="200"         :fixed="fixed"       >         <template slot-scope="scope">           <slot name="editSlot">             <template>               <el-button type="primary" @click="editClick(scope.row)"                 >编辑</el-button               >               <el-button type="danger" @click="deleteClick(scope.row)"                 >删除</el-button               >             </template>           </slot>         </template>       </el-table-column>     </el-table>     <el-pagination       :style="{ float: `${paginationPosition}` }"       v-if="pagination"       :background="background"       :current-page.sync="currentPage"       :page-size.sync="currentSize"       :layout="layout"       :page-sizes="pageSizes"       :total="total"       @size-change="handleSizeChange"       @current-change="handleCurrentChange"     />   </div> </template>  <script> // 自定义内容的组件 var exSlot = {   functional: true,   props: {     row: Object,     render: Function,     index: Number,     column: {       type: Object,       default: null,     },   },   // render 函数   render: (h, context) => {     const params = {       row: context.props.row,       index: context.props.index,     };     if (context.props.columns) params.columns = context.props.columns;     return context.props.render(h, params);   }, }; export default {   name: "TableList",   components: { exSlot },   props: {     data: {       type: Array,       default: () => [],     },     update: {       type: Number,       default: () => null,     },      // 是否显示合计列     showSummary: {       type: Object,       default: () => {         return {           show: false,           sumText: "总计",         };       },     },     // 需要通过那个字段属性进行比较合并     spanName: {       type: String,       default: () => {         return null;       },     },     // 需要合并数组     spanColumnArr:{       type:Array,       default:()=>{         return [0]       }     },     tooltipTheme: {       type: String,       default: "dark",     },     // 是否显示表头     showHeader: {       type: Boolean,       default: true,     },     // 是否添加排序列     indexShow: {       type: Boolean,       default: true,     },     showTable: {       type: Boolean,       default: true,     },     // 是否显示选择框列     selection: {       type: Boolean,       default: false,     },     // 字段名     columns: {       type: Array,       default: () => [],     },     // 是否含有边框     border: {       type: Boolean,       default: false,     },      // 是否显示斑马条纹     stripe: {       type: Boolean,       default: false,     },     // 是否是可以编辑的表格     isEdit: {       type: Boolean,       default: false,     },     // 是否固定右侧一列,只对右侧操作栏起作用     fixed: {       type: String,       default: "right",     },      // 是否显示分页     pagination: {       type: Boolean,       default: false,     },     // 分页的位置     paginationPosition: {       type: String,       default: "center",     },     total: {       required: false,       type: Number,     },     page: {       type: Number,       default: 1, // 默认第一页     },     limit: {       type: Number,       default: 10, // 默认每页20条     },     pageSizes: {       type: Array,       // default: [10, 20, 30, 50]       default: function () {         return [1, 2, 3, 5]; // 默认显示可选的每页多少条数据       },     },     layout: {       type: String,       default: "total, sizes, prev, pager, next, jumper",     },     background: {       type: Boolean,       default: true,     },     autoScroll: {       type: Boolean,       default: true,     },     hidden: {       type: Boolean,       default: false,     },     className: {       type: String,       default: "",     },     render: {       type: Function,       default: function () {},     },   },   data() {     return {       cloneColumns: [],       spanArr: [], // 跨行数组       pos: null, // 跨行数组     };   },   computed: {     // 当前页多少条数据并且赋值给父组件     currentPage: {       get() {         return this.page;       },       set(val) {         this.$emit("update:page", val);       },     },     // 改变当前页几条数据得值赋值给父组件     currentSize: {       get() {         return this.limit;       },       set(val) {         this.$emit("update:limit", val);       },     },   },   created() {     this.cloneColumns = JSON.parse(JSON.stringify(this.columns));   },   watch: {     columns(value) {},   },   mounted() {     if (this.spanName) {       this.getSpanArr(this.data);     }   },    methods: {      // 合同单元格直接传入:spanName="id或者其他字段属性名"     getSpanArr(data) {       for (let i = 0; i < data.length; i++) {         if (i === 0) {           this.spanArr.push(1);           this.pos = 0;         } else {           // 判断当前的元素和上一个元素是否相同           // name 需要通过哪个字段来进行比较合并           if (data[i][this.spanName] === data[i - 1][this.spanName]) {             this.spanArr[this.pos] += 1;             this.spanArr.push(0);           } else {             this.spanArr.push(1);             this.pos = i;           }         }       }     },    // 合并     objectSpanMethod({ row, column, rowIndex, columnIndex }) {       if (this.spanColumnArr.includes(columnIndex)) {         const _row = this.spanArr[rowIndex];         const _col = _row > 0 ? 1 : 0;         return {           rowspan: _row,           colspan: _col,         };       }     },      // 自定义合计行     summaryMethod(params) {       const { columns, data } = params;       const sums = [];       columns.forEach((column, index) => {         if (index === 0) {           sums[index] = "总计";           return;         }         const values = data.map((item) => item[column.property]);         let num = 0;         for (let i = 0; i < values.length; i++) {           if (values[i]) {             num += Number(values[i]);             sums[index] = num;           } else {             if (isNaN(values[i])) {             } else {               num += Number(values[i]);               sums[index] = num;             }           }         }         if (column.property === "lv1Time" || column.property === "lv2Time") {           if (values.filter(Boolean).length === 0) {             sums[index] = "";           } else {             let num = 0;             for (let i = 0; i < values.length; i++) {               if (values[i]) {                 num += Number(values[i]);                 sums[index] = num;               } else {                 if (isNaN(values[i])) {                 } else {                   num += Number(values[i]);                   sums[index] = num;                 }               }             }           }         }       });       let arr = [];       sums.map((i, index) => {         if (index === 0) {           arr.push(i);         } else {           if (!isNaN(i)) {             arr.push(i);           } else {             arr.push("");           }         }       });       return arr;     },     handleFilterChange(filters) {       if (filters.length > 0) {         this.$refs.filterTable.clearSelection();         this.$refs.filterTable.toggleRowSelection(filters.pop());       } else {         this.columns.map((item) => {           // 判断当前是那一列进行了筛选           if (item.prop === Object.keys(filters)[0]) {             item.filterValues = filters;           }         });          this.$emit("filtersParams", this.columns);       }     },     // 当前行当前列数据是否有效,无效的话,返回--占位符     formatter(row) {       if (row) {         return isNaN(parseFloat(row)) && isFinite(row)           ? '<span class="isNaN">--</span>'           : row;       } else {         return '<span class="isNaN">--</span>';       }     },     /**      * @param {*}      * @return {*}      * @author: Q      * @Date: 2021-09-01 11:56:37      * @description: 已选的数据项      */     handleSelectionChange(val) {       this.$emit("selectVal", val);     },     handleSizeChange(val) {       this.pageSize = val;       this.$emit("pagination", { pageIndex: this.page, pageSize: val });     },     handleCurrentChange(val) {       this.$emit("pagination", { pageIndex: val, pageSize: this.limit });     },     // 修改按钮的点击事件     editClick(val) {       this.$emit("edit", val);     },     // 删除按钮点击事件     deleteClick(val) {       this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {         confirmButtonText: "确定",         cancelButtonText: "取消",         type: "warning",       })         .then(() => {           this.$emit("del", val);         })         .catch(() => {           this.$message({             type: "info",             message: "已取消删除",           });         });     },   }, }; </script>  <style lang="scss"> .table-container {   text-align: center;   .el-pagination {     margin-left: 0 !important;     margin-top: 0 !important;     background: #fff !important;     height: 112px;     line-height: 112px;     display: flex;     justify-content: center;     align-items: center;     ul {       display: flex;       justify-content: space-around;       align-items: center;       li {         border-radius: 6px !important;         color: #666666 !important;       }       .active {         color: #fff !important;         background: #1677ffff !important;       }     }     button {       border-radius: 6px !important;       color: #666666 !important;     }   } } .table-container.el-table {   margin-top: 20px; }  .table-container .el-pagination {   margin-top: 20px;   margin-left: 20px; } .isNaN {   color: red; } </style>