美文网首页coding
Vue 表格 | 基于Element UI 的二次封装组件

Vue 表格 | 基于Element UI 的二次封装组件

作者: UShowJack | 来源:发表于2017-06-13 21:13 被阅读1154次

前言

由于项目的原因,几乎所有的页面都需要用到表格,但是表格的样式又有些许的差别。起初,项目启动的时候,选择使用饿了么的UI,便也懒得去设计其中的UI,基于它的组件封装table组件。希望以后有机会自己能封装独自的组件。

原因

直接上代码,你就可以知道为什么要封装组件。

<el-table 
           :data="userData"
           border
           tooltip-effect="dark"
           style="width: 100%"
           @selection-change="handleSelectionChange">
            <el-table-column
                    type="selection"
                    width="55">
            </el-table-column>
            <el-table-column
                    type="index"
                    width="80">
            </el-table-column>
            <el-table-column
                    :sortable=true
                    header-align="center"
                    prop="name"
                    label="姓名"
                    width="120">
            </el-table-column>
            <el-table-column
                    :sortable=true
                    header-align="center"
                    prop="pid"
                    label="证件号">
            </el-table-column>
            <el-table-column
                    :sortable=true
                    header-align="center"
                    prop="birth"
                    label="出生日期">
            </el-table-column>
            <el-table-column
                    :sortable=true
                    header-align="center"
                    prop="dutyname"
                    label="职务">
            </el-table-column>
            <el-table-column
                    :sortable=true
                    header-align="center"
                    prop="sex"
                    label="性别">
            </el-table-column>
            <el-table-column
                    :sortable=true
                    header-align="center"
                    fixed="right"
                    label="操作"
                    width="150">
                <template scope="scope">
                    <el-button @click="detailMore(scope.$index, scope.row)" 
                               type="text" 
                               size="small">
                        查看详情
                    </el-button>
                    <el-button
                            @click.native.prevent="deleteRow(scope.$index, userData)"
                            type="text"
                            size="small">
                        删除
                    </el-button>
                </template>
            </el-table-column>
        </el-table>

这样的代码可以说非常的长。在一个页面里怎么说也要有80行的代码量。而且当很多个页面需要复用的时候,你就必须去不断的改它的label属性还有方法,非常的繁琐。
于是,封装table组件,势在必行。

起始

封装组件从文件夹开始:

├── components
    ├── index.js
    ├── vue
       ├── table.vue
    ├── utils
       ├── utils.js

为了方便引用,建立了一个index.js:

import TmTable from "./vue/table.vue";
export default UTable;

为了方便引用和路径的维护,首先在build文件夹下的webpack.base.conf.js对路径进行修改。

 resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
        'domain$':  path.resolve(__dirname, '../src/api/domain.js'),
        'api':  path.resolve(__dirname, '../src/api'),
        'utils':  path.resolve(__dirname, '../src/utils'),
        'components':  path.resolve(__dirname, '../src/components'),
    }
  }

这样就可以在vue文件中对组件进行这样引用,就可以使用了。

import TmTable from 'components/newTable'

封装思路

做好了准备工作,我们就可以进去vue文件中开始封装了。

拿到一个表格,首先思考,这个表格能做什么?
在本项目中,需要有选择,序号,数据,操作。表头上还有可能需要有排序的功能。

<template>
    <el-table>
        <!--选择-->
        <!--序号-->
        <!--数据源-->
        <!--操作-->
    </el-table>
</template>

首先呢,先把选择和排序加上,这两个比较简单。只需要通过props属性来判断是否需要该列。由于是一次性生成就完事了。所以在这里选择用v-if

<template>
    <el-table>
        <!--选择-->
        <el-table-column
                v-if="hasSelection"
                type="selection"
                width="55">
        </el-table-column>
        <!--序号-->
        <el-table-column
                v-if="hasIndex"
                type="index"
                width="55">
        </el-table-column>
    </el-table>
</template>
export default {
        name: 'tm-table',
        props: {
            //是否可以选择
            hasSelection: {
                type: Boolean,
                default: function () {
                    return false
                }
            },
            //是否有序列项
            hasIndex: {
                type: Boolean,
                default: function () {
                    return false
                }
            }
    }

搞定!好了接下来就是将数据传入表格里。这里就涉及到两点。饿了么UI是通过label来控制表头的,在通过prop控制数据流的。而且由于项目的需要,有些数据本身就不会被展现出来。

于是我通过参数columns来控制列的行为,再通过参数dataSource存储数据源。
以下是数据格式:

columns: [
                    {
                        hasSort: false,  //<Boolean> 是否排序
                        isShow: true,  //<Boolean> 是否展示
                        prop: 'name',   //<String>  对应属性名
                        label: '姓名',  //<String>   表头标签
                    },
                    {
                        hasSort: false,  //<Boolean> 是否排序
                        isShow: true,  //<Boolean> 是否展示
                        prop: 'date',   //<String>  对应属性名
                        label: '日期',  //<String>   表头标签
                    },
                    {
                        hasSort: true,  //<Boolean> 是否排序
                        isShow: true,  //<Boolean> 是否展示
                        prop: 'org',   //<String>  对应属性名
                        label: '单位',  //<String>   表头标签
                    },
                    {
                        hasSort: true,  //<Boolean> 是否排序
                        isShow: true,  //<Boolean> 是否展示
                        prop: 'id',    //<String>  对应属性名
                        label: '身份证', //<String>   表头标签
                    }],
 dataSource: [
                    {
                        name: '隔壁',
                        id: '123456',
                        org: '隔壁济源',
                        date: '2017-12-12',
                        sex: '男'
                    },
                    {
                        name: '老王',
                        id: '456789',
                        org: '地府',
                        date: '2017-11-12'
                    },
                ]

具体怎么控制,看注释就一目了然。
好了,那么怎么写数据部分呢?

        <!--数据源-->
        <el-table-column v-for="(column, index) in columns"
                         v-if="column.isShow"
                         header-align="center"
                         :sortable="column.hasSort"
                         :key="column.prop"
                         :prop="column.prop"
                         :label="column.label">
        </el-table-column>

是不是很简单。接下来就是一个问题。怎么写操作部分?这就要谢谢前段时间看的一些关于slot的文章,当时是好奇,为什么饿了么UI可以使用<template scope="scope">这么来写(详情可以查看 Table 表格):

<el-table-column label="操作">
      <template scope="scope">
        <el-button
          size="small"
          @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
        <el-button
          size="small"
          type="danger"
          @click="handleDelete(scope.$index, scope.row)">删除</el-button>
      </template>
    </el-table-column>

后来才查到可以使用slot来做,于是我就这样构思,如果我需要操作列的时候就直接往上加,如果不需要的话,我就直接忽略。slot不就刚好满足我的需求吗?再来它还有一个好处,也是很重要的一点,那就是可以在父组件上绑定事件到操作的按钮。

于是只要在要加操作列的地方添加一行:

<!--操作-->
<slot name="handle-column">
</slot>

这样就占好位置了。完美!
好了,在看看呢。各个列的功能已经被我们实现了,最后只要把数据绑定到列上面去就可以了。

 <el-table :data="dataSource"  >
 </el-table>

但是仔细想想,貌似漏了一个东西。如果,你有多选的话,那数据在子组件。父组件有没有办法获取到选择的行。这么办?简单啊!用vm.$emit

<el-table border
          :data="dataSource"
          @selection-change="handleSelectionChange">
 </el-table>
methods: {
            //将选中的行发送到父组件
            handleSelectionChange(val) {
                const selectionArr = [];
                val.forEach(function (el) {
                    selectionArr.push(el);
                });
                this.$emit('emitSelection', selectionArr);
            },
        }

到这里,整个思路就完成了。

完整代码

吸取$川的建议,在此处就不贴源码。直接上GitHub的地址:table组件源码

虽然看起来代码量还是很大,实际上光html的代码行数也就20+,比起原来的70行那是少了大约2/3的量。如果不需要操作列的话,那几乎10行就可以搞定一个列表,而且几乎不需要修改代码的复制黏贴才是我的终极目标。

还请多多指教。

阅读原文请点击:原文链接

相关文章

网友评论

  • 油腻的前端大叔:可配置性太差 使用的话肯定要踩坑,推荐一个大家试试看:https://www.npmjs.com/package/el-search-table-pagination
  • 我穿过你的世界:请问,在组件中如何使用的能具体的写一下吗?
  • 00158cfe76ed:你好,在封装的表格里,如果接口中状态返回0或者1,分别对应启用或者禁用,怎么将状态字段对应的文字显示到列表中呢?
  • 晴天u:感觉缺少了点可配置性,比如说,我想控制其中一列的宽、align 什么的都不行。
  • 8720a39494f1:请教下,如果我想做一个表格,其中有一列是播放录音的,后台给的数据是个url,audio怎么插到表格中呢?src又该怎么从数据中绑定url呢
    8720a39494f1:@UShowJack 多谢
    UShowJack:@0胖头鱼0 用列自定义模板,获取scope.row获取你的数据,绑定到radio上
  • 65856ab314f9:你好 你的组件怎么写自定义标签呢
    冷豆浆:@RicardoMLu_dec3 直接注册组件来用,标签名自定义
    UShowJack:@RicardoMLu_dec3 你的意思是?

本文标题:Vue 表格 | 基于Element UI 的二次封装组件

本文链接:https://www.haomeiwen.com/subject/ufrjqxtx.html