vue3+elementplus基于el-table-v2封装公用table组件

这篇具有很好参考价值的文章主要介绍了vue3+elementplus基于el-table-v2封装公用table组件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  1. 梳理出需要封装的功能

主要是针对表格进行封装,不包括查询表单和操作按钮。

梳理出系统中通用表格的功能项,即表格主体的所有功能,生成columns列头数据、生成data表体数据、拖拉列宽、分页、生成中文列名、自定义列宽width

vue3+elementplus基于el-table-v2封装公用table组件,前端,javascript,elementplus,Powered by 金山文档

效果如下:

vue3+elementplus基于el-table-v2封装公用table组件,前端,javascript,elementplus,Powered by 金山文档

2.封装表格(表格+分页)

<template>
    <slot></slot>
    <div class="table-v2">
        <el-auto-resizer always height="36">
            <!--行高 :row-height="36" -->
            <template #default="{ height, width }">
                <el-table-v2 :columns="columns" :scrollbar-always-on="true" :data="data" :width="width" :height="height"
                    :row-height="36" :row-key="data.id" fixed>
                </el-table-v2>
            </template>
        </el-auto-resizer>
        <!-- 分页 -->
        <div class="pagination" v-if="showPage">
            <el-pagination background class="pagination" layout="prev, pager, next" :current-page="pageNum" :total="total"
                :page-size="pageSize" @prev-click="prevClick" @next-click="nextClick" @current-change="currentChange" />
        </div>
    </div>
</template>

父级引用:

 <!-- 表格 -->
    <t-table-v2 @handle-pagenation="handlePagenation"></t-table-v2>

3.将生成列名和表体数据、复选框、操作按钮等方法封装成类

import { unref } from 'vue'
import { ElCheckbox, TableV2FixedDir } from 'element-plus'

export default class GenerateTableData {
    // options: {columns:...,data:...}
    constructor(data) {
        this.data = data;
        this.column = this.createColumnsData();
        this.rowData = this.createRowsData();
    }

    /**
     * 通过tableData生成 columnsData
     * @returns 
     */
    createColumnsData = () => {
        let columnsData = [];
        if (this.data.length > 0) columnsData = Object.keys(this.data[0]);
        return columnsData;
    }

    /**
     * 通过tableData生成 rowsData
     * @returns 
     */
    createRowsData = () => {
        let rowData = [];
        this.data.map(item => {
            rowData.push(Object.values(item));
        });
        return rowData;
    }

    /**
     * 函数设置width属性值
     * @param {*} columnIndex 
     */
    static calculateWidth = (columnIndex, columnWidth) => {
        let tempArr = [];
        if (typeof columnWidth === "number") {
            return columnWidth;
        } else if (typeof columnWidth === "object") {
            columnWidth.map((k, index) => {
                if (typeof k.columnsIndex === "object") {
                    k.columnsIndex.map(innerK => {
                        tempArr.push({ columnsIndex: innerK, width: k.width });
                    });
                } else {
                    tempArr.push(columnWidth[index]);
                }
            });
        }
        let width = 0;

        tempArr.map((k) => {
            switch (columnIndex) {
                case k.columnsIndex:
                    width = k.width;
                    break;
            }
        });

        return width;
    }

    /**
     * 将英文列名改为中文列名(id不显示)
     * @param {*} columnIndex 
     */
    static transferColumnName = (columnIndex, cnColumnNameArr) => {
        return cnColumnNameArr[columnIndex];
    }

    /**
     * 隐藏列
     * @param {*} columnIndex 
     */
    static handleHiddenColumns = (columnIndex, hiddenIndex) => {
        return hiddenIndex.includes(columnIndex);
    }

    /**
     * 生成列名: cnColumnNameArr有值则使用中文名,无值使用原this.column值
     * @param {*} columnsArr 
     */
    generateColumns(cnColumnNameArr, hiddenIndex, columnWidth) {
            console.log(cnColumnNameArr, this.column);
            if (cnColumnNameArr) this.column = cnColumnNameArr;
            return this.column.map((item, columnIndex) => {
                return {
                    key: `${item}`,
                    dataKey: `${item}`,
                    title: `${item}`,
                    // 通过函数设置width值
                    hidden: hiddenIndex.length > 0 ? GenerateTableData.handleHiddenColumns(columnIndex, hiddenIndex) : false,
                    width: GenerateTableData.calculateWidth(columnIndex, columnWidth),
                    align: 'center',
                };
            })
        }
        // 生成列表数据
    generateData = (columns) => {
        return this.rowData.map((item, rowIndex) => {
            return columns.reduce(
                (rowData, column, columnIndex) => {
                    // item数组下标columnIndex-1开始(id不显示),因为有checkbox复选框
                    rowData[column.dataKey] = item[columnIndex];
                    return item;
                },
                // 初始化元素为第一条数据(否则数据会获取不到id)tempDataArr[0]
                this.rowData[rowIndex]
            )
        })
    }

    /**
     * 增加全选列且操作全选/全不选 ; 增加操作按钮:修改,删除
     * @param {*} columns 
     */
    static customizeColumns = (columns, data, selectedId, cellRendererFunc) => {
        // 全选按钮:在数组头部添加
        columns.unshift({
            key: 'selection',
            dataKey: 'selection',
            title: 'selection',
            width: 30,
            cellRenderer: ({ rowData }) => {
                // 绑定数据的id,然后row-key才能使用id
                rowData.id = rowData[0];
                const onChange = (value) => {
                    rowData.checked = value

                    if (rowData.checked) {
                        selectedId.push(rowData[0]);
                    } else {
                        let idIndex = selectedId.findIndex(item => item === rowData[0]);
                        selectedId.splice(idIndex, 1);
                    }
                    console.log("selectedId.value------------", selectedId);
                    return rowData.checked;
                }
                return ( <
                    ElCheckbox onChange = { onChange }
                    modelValue = { rowData.checked }
                    indeterminate = { false }
                    />
                )
            },

            headerCellRenderer: () => {
                const _data = unref(data)
                const onChange = (value) =>
                    (data = _data.map((row) => {
                        row.checked = value;
                        // 全选id设置
                        if (row.checked) {
                            selectedId.push(row[0]);
                        } else {
                            selectedId = [];
                        }
                        return row;
                    }))
                    // 全选
                const allSelected = _data.every((row) => row.checked)
                    // 非全选
                const containsChecked = _data.some((row) => row.checked)
                return ( <
                    ElCheckbox onChange = { onChange }
                    modelValue = { allSelected }
                    indeterminate = { containsChecked && !allSelected }
                    />
                )
            },
        });

        // 操作按钮:在数组末尾添加
        cellRendererFunc && columns.push({
            key: 'operations',
            dataKey: 'operations',
            title: '操作',
            width: 300,
            align: 'center',
            // 编辑和删除操作:绑定当前id,使用的是JSX语法,方法调用onClick={ editResource } 传参:onClick={ (event)=>editResource(rowData[0]) }
            cellRenderer: ({ rowData }) => cellRendererFunc(rowData)
        });
    };

    /**
     * 固定列:可以用这个方法也可以用elementplus自带的(自带的感觉还方便一些)
     */
    fixedColumns = (columns, fixedColumnIndex) => {
        fixedColumnIndex.length > 0 && fixedColumnIndex.map(column => {
            // 不设置为TableV2FixedDir.LEFT这种形式,可以直接写true,默认left
            let tableV2Fixed = true;
            if (column.direction === "left") tableV2Fixed = TableV2FixedDir.LEFT;
            if (column.direction === "right") tableV2Fixed = TableV2FixedDir.RIGHT;
            columns[column.index].fixed = tableV2Fixed;
        });
    }
}

4.父类中调用类方法

// 数据所有列都一样,所以取第一条数据列名作为表头
    let cnColumnNameArr = ['编号', '资源名称', '资源类型', '提交原因', '上个投产版本', '投产版本', '提交人', 'SIT'
        , '提交时间', '状态', 'SIT部署时间', 'SIT测试完成时间', 'UAT部署时间', 'SIT部署完成', 'SIT已测试', 'UAT部署完成'];
    let hiddenIndex = [0,4];
    let columnWidth = [{columnsIndex:[0,4],width:0},
        {columnsIndex:1,width:146},
        {columnsIndex:2,width:80},
        {columnsIndex:3,width:300},
        {columnsIndex:5,width:76},
        {columnsIndex:[6,9],width:100},
        {columnsIndex:[8,10,11,12],width:160},
        {columnsIndex:[7,13,14,15],width:70},
        {columnsIndex:'default',width:58}];

        const generateTableData = new GenerateTableData(tableData.value);
        
        // 完全无值也需要显示列名, cnColumnNameArr此处必须有值:cnColumnNameArr或者false(英文列名)
        cnColumnNameArr = tableData.value.length === 0? cnColumnNameArr : cnColumnNameArr;//length如果不为0是设置为false就会显示英文列名
        columns.value = generateTableData.generateColumns(cnColumnNameArr,hiddenIndex,columnWidth);

        // 设置全选按钮和操作按钮
        data.value = code === 200 ? generateTableData.generateData(columns.value): [];

        GenerateTableData.customizeColumns(columns.value,data.value,selectedId.value,cellRenderer);
        if(code === 200){
           // 固定列
          columns.value[0].fixed = true
          columns.value[1].fixed = TableV2FixedDir.LEFT
          columns.value[2].fixed = TableV2FixedDir.LEFT
          columns.value[3].fixed = TableV2FixedDir.LEFT
        }

        resizeColumns(columns.value);

5.父子组件通信(provide/inject)

父组件:

// provide方式父子组件传值
provide('columns', computed(()=>columns.value));
provide('data', computed(()=>data.value));
// 分页
provide('showPage', computed(()=>true));
provide('pageNum', computed(()=>pageNum.value));
provide('total', computed(()=>total.value));
provide('pageSize', computed(()=>pageSize.value));
provide('pages', computed(()=>pages.value));
// 是否宽高自适应
provide('selfAdaption', computed(()=>true));
provide('cellRenderer', computed(()=>cellRenderer));

子组件:

// 是否显示分页组件
const showPage = inject('showPage',false);
const columns = inject('columns',[]);
const data = inject('data',[]);

const pageNum = inject('pageNum',1);
const pages = inject('pages',0);
const total = inject('total',0);
const pageSize = inject('pageSize',16);

// 是否宽高自适应
const selfAdaption = inject('selfAdaption',false);

6.分页

子组件:

const $emit = defineEmits(['handlePagenation']);
/**
 * 上一页:pageNum会自动-1
 */
const prevClick = () => {
    // pageNation分页组件限定,pageNum.value不可能为0;如果pageNum.value比1大就取pageNum.value,否则永远为1
    $emit('handlePagenation', Math.max(1, pageNum.value));
}

/**
 * 下一页:pageNum会自动+1
 */
const nextClick = () => {
    // 如果pageNum.value比pages小就取pageNum.value,否则永远为pages
    $emit('handlePagenation', Math.max(1, Math.min(pages.value, pageNum.value)));
}

/**
 * 点击特定页码(此方法会自动传入当前页码)
 * @param {*} currentPage 
 */
const currentChange = (currentPage) => {
    $emit('handlePagenation', currentPage);
}

父组件:

/**
 * 分页
 */
 const handlePagenation = (pageNumVal) =>{
  // pageNation分页组件限定,pageNum.value不可能为0;如果pageNum.value比1大就取pageNum.value,否则永远为1
  pageNum.value = pageNumVal;
  loadDataGrid();
}

7.问题:el-table-v2中数据失去响应性

vue3+elementplus基于el-table-v2封装公用table组件,前端,javascript,elementplus,Powered by 金山文档

以上,实现简单封装文章来源地址https://www.toymoban.com/news/detail-687446.html

到了这里,关于vue3+elementplus基于el-table-v2封装公用table组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • vue3 基于element plus对el-pagination进行二次封装

    在vue3项目中,如果每个列表页都敲一遍分页方法,显然是不合理的,那么,下面我将基于element plus对el-pagination进行二次封装,使用vue3语法糖格式,废话不多说,开干。

    2024年02月12日
    浏览(14)
  • vue3+elementPlus:前端自定义el-tree图标icon

    重点:template蒙版下svg和use,然后前端遍历添加key和value,取判断放图标 HTML结构:el-tree里面包裹template(关键点) 方法一:使用for循环 for循环数据,前端自定义tree图标第一种方法,后端key没有icon字段,自己添加 方法二: 使用map遍历 直接map遍历前端自定义tree图标 作者上一

    2024年02月15日
    浏览(9)
  • vue3+elementPlus:el-drawer新增修改弹窗复用

    在el-drawer的属性里设置:title属性,和重置函数 上一篇文章,  uniapp踩坑之项目:使用过滤器将时间格式化为特定格式_uniapp过滤器-CSDN博客 文章浏览阅读446次。uniapp踩坑之项目:使用过滤器将时间格式化为特定格式,利用filters过滤器对数据直接进行格式化,注意:与method、

    2024年02月03日
    浏览(10)
  • vue3,elementPlus和自己封装,点击 新增添加表单,删除表单,提交数据

    vue3,elementPlus和自己封装,点击 新增添加表单,删除表单,提交数据

    点击提交的打印效果 components/insertForm.vue 主文件引入 效果一样 *

    2024年02月16日
    浏览(11)
  • vue3+elementplus点击按钮使用el-image-viewer图片预览组件

    1.首先确保你是全局引入,不是全局的需要自主引入该组件 2..vue文件中定义组件 3. showsrcListref:[\\\'\\\']格式 4.点击按钮给showsrcListref赋值即可完成,同时将showImagePreview置为true

    2024年01月18日
    浏览(14)
  • Vue3+ElementPlus el-date-picker设置可选时间范围

    Vue3+ElementPlus el-date-picker设置可选时间范围

    需求: 选择年份,对应的日期范围选择器跟随年份变化,只可选当前年份 ElementPlus的el-data-picker没有picker-options属性,但是提供了default-value属性可以设置不可选的日期   这里我们定义一个方法disabledDateFun用来筛选符合要求的日期,接受一个date格式的对象作为参数,返回格式为

    2024年02月12日
    浏览(11)
  • Vue3使用ElementPlus中的el-upload手动上传并调用上传接口

    实体类 定义接口 上传文件并插入数据库数据

    2024年01月20日
    浏览(43)
  • 在Vue3+ElementPlus项目中使用具有懒加载的el-tree树形控件

    在Vue3+ElementPlus项目中使用具有懒加载的el-tree树形控件

    有时遇到一些需求就是在使用树形控件时,服务端并没有一次性返回所有数据,而是返回首层节点列表。然后点击展开首层节点中的某个节点,再去请求该节点的子节点列表,那么就得用上懒加载的机制了。在此以ElementPlus的树形控件为例,实现一个具有懒加载的树形控件的

    2024年02月06日
    浏览(14)
  • vue封装el-table表格组件

    vue封装el-table表格组件

    先上效果图: 本文包含了具名插槽、作用域插槽、jsx语法三种: Render.vue( 很重要,必须有 ): Table.vue 使用Table组件

    2024年02月20日
    浏览(11)
  • vue3使用ElementPlus的消息el-message样式不生效或者被遮盖(z-index)

    问题1:el-message自定义样式不生效 想改弹出框的位置时不生效,使用了el-message的自定义类的 custom-class 属性也不行。原因应该是加了scoped后使用到里面样式的dom会添加data-v-xxxx这种属性防止css污染,但是message生成的dom是没有添加data-v-xxx属性的,所以样式无效。 解决方式:j

    2024年02月08日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包