基于element-ui封装table,如何为指定列传递 formatter 函数?

想要基于element-uitable封装一个表格组件,因为后台管理很多菜单的首页几乎一个样,我想在调用的时候传递tabColumnstableData等关键属性即可:

封装表格my-table.vue如下:

<template>
    <div>
        <div class="btns-area">
            <el-button-group>
                <slot name="btnsArea"></slot>
                <el-dropdown :hide-on-click='false'>
                    <el-button type="default">
                        显示隐藏列 <span v-show="hiddenColumnTotal > 0">({{ hiddenColumnTotal }})</span><i class="el-icon-arrow-down el-icon--right"></i>
                    </el-button>
                    <el-dropdown-menu slot="dropdown">
                        <el-dropdown-item v-for="head in headers" :key="head.key">
                            <el-switch v-model="head.isShow" :active-text="head.label"></el-switch><span></span>
                        </el-dropdown-item>
                    </el-dropdown-menu>
                </el-dropdown>
            </el-button-group>
        </div>
        <el-table 
            ref="myTable"
            :data="tabDatas"
            highlight-current-row
            @row-click='handleRowClick'
            @selection-change='handleSelectionChange'
            >
            <el-table-column type="selection" width="55" v-if="multable"></el-table-column>
            <!-- 用户自定义需要显示的列 -->
            <el-table-column v-for="c in columns" 
                :key="c.attr.prop" 
                v-bind="c.attr"
                >
                <template slot-scope="scope">
                    <slot v-if="c.slot" :name="c.attr.prop" :row='scope.row'></slot>
                    <span v-else>{{ scope.row[c.attr.prop] }}</span>
                </template>
            </el-table-column>
        </el-table>
    </div>
</template>

<script>
export default {
    name: 'my-table',
    props: {
        tabColumns: {
            type: Array,
            required: true,
            validator: (cols) => {
                return cols.length >= 1 //表格至少需要1列
            }
        },
        tabDatas: Array,
        multable: { //是否多选
            type: Boolean,
            default: true
        }
    },
    computed: {
        columns() {
            return this.headers.filter(h => h.isShow);
        },
        hiddenColumnTotal() {
            return this.headers.filter(h => !h.isShow).length;
        }
    },
    created() {
        this.headers = JSON.parse(JSON.stringify(this.tabColumns));
        this.headers = this.headers.map((c) => {
            if(c.isShow === undefined){
                this.$set(c, 'isShow', true)
            }
            return c;
        });
    },
    data() {
        return {
            headers: [],
        }
    },
    methods: {
        //单击行
        handleRowClick(row) {
            this.$refs.myTable.toggleRowSelection(row);
        },
        handleSelectionChange(selection) {
            this.$emit('rowSelectionChanged', selection);
        },     
    }
}
</script>

<style scoped>
.btns-area{
    text-align: right;
}
</style>

调用方代码如下(某个列表页):

<template>
    <div>
        <my-table 
            :tab-columns='tabColumns' 
            :tab-datas='tabDatas'
            @rowSelectionChanged='rowSelected'
        >   
            <!-- 表格批量操作区域 -->
            <template slot="btnsArea">
                <el-button type="primary">编辑</el-button>
                <el-button type="danger">删除</el-button>
            </template>
            <!-- 通过slot自定义列:参数,当前行 -->
            <template slot='gender' slot-scope="scope">
                <el-tag v-if="scope.row.gender == 1" type="success">男</el-tag>
                <el-tag v-if="scope.row.gender == 0" type="info">女</el-tag>
            </template>

        </my-table>
        
    </div>
</template>

<script>
import MyTable from '../../components/my-table'

export default {
    name: 'nest-components-demo',
    data() {
        return {
            tabColumns: [
                {
                    attr: {prop: 'userId', label: '用户编号'}
                },
                {
                    attr: {prop: 'username', label: '用户名'},
                    isShow: false
                },
                {
                    attr: {prop: 'gender', label: '性别'},
                    slot: true
                },
                {
                    attr: {prop: 'age', label: '年龄', formatter: this.formatterUsername},
                },
            ],
            tabDatas: [
                {userId: '1', username: 'qingyun', gender: '1', age: 31},
                {userId: '2', username: 'aaaaaaaa', gender: '0', age: 21},
                {userId: '3', username: 'bbbbbbb', gender: '1', age: 25},
                {userId: '4', username: 'cccccccc', gender: '0', age: 27},
            ],
            checkedRows: [],//选中的行
        }
    },
    methods: {
        //监听选中的行
        rowSelected(rows) {
            this.checkedRows = rows;
            console.log(this.checkedRows.map(r => r.userId));
        },
        preview(row) {
            console.log(JSON.stringify(row));
        },
        formatterUsername(row, column) {
            console.log('xxxxxxxxxxxxx');
            return 'xxx';
        }
    },
    components: {
        MyTable,
    }
}
</script>

my-table.vue组件属性说明:

  1. tabColumns需要显示的列。有三个属性(后续会扩展出更多);

    1. key: 字段名;
    2. label:显示的字符;
    3. slot=true:表示该列需要自定义,通过slot-scope可以得到整行数据;
  2. tabDatas表格需要显示的数据;

可以看到,在调用封装好的组件my-table的时候还是比较简单的,列通过labelkey显示对应的表头和数据;也可以通过设置列属性slot=true来自定义要显示的样子。

问题:我希望通过设置tabColumns列属性的时候,可以新增一个formatter属性(参考第二段代码中对属性age的设置),Function类型,就像 element-ui 默认使用方式一样(参考),用来格式化比较简单的字符串(虽然通过设置slot=true完全可以做到),

阅读 10.3k
3 个回答

可以使用:attr,:listeners等将你的组件变为高级组件。

<el-table-column v-for="c,index in columns" 
    :key="index" 
    v-bind='c.attr'
    v-on='c.listeners'
    >
    <template slot-scope="scope">
        <slot v-if="c.slot" :name="c.key" :row='scope.row'></slot>
        <span v-else>{{ scope.row[c.key] }}</span>
    </template>
</el-table-column>
columns:[{
    attr:{
        key: 'userId', 
        label: '用户编号',
        formatter: ()=>{
            //xxx
        }
    }
}]

大概就是这个意思,你再根据你的需求习惯来写。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏