7

在 Vue3 + Element Plus 中生成动态表格,动态修改表格,多级表头,合并单元格

 1 year ago
source link: https://kalacloud.com/blog/how-to-build-dynamic-table-in-vue-element-plus/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在 Vue3 + Element Plus 中生成动态表格,动态修改表格,多级表头,合并单元格

stone
前端工程师
最近更新 2022年06月12日

在 Vue3 + Element Plus 中生成动态表格,动态修改表格,多级表头,合并单元格

在 Vue 中,表格组件是使用频率及复杂度排名第一的组件,前端经常需要根据后台返回的数据动态渲染表格,比如动态表格如何生成,因为表格的列并不是固定的,在未知表格具体有哪些列的场景下,前端如何动态渲染表格数据。又或者需要把表格单元格进行合并处理,比如第一列是日期,需要把相同的日期进行合并,这样表格看起来会更加清晰。 本文手把手教你如何在 Vue3 + Element Plus 中创建表格、生成动态表格、创建动态多级表头、表格行合并、列合并等问题。

如果你正在搭建后台管理工具,又不想处理前端问题,推荐使用卡拉云 ,卡拉云是新一代低代码开发工具,可一键接入常见数据库及 API ,无需懂前端,仅需拖拽即可快速搭建属于你自己的后台管理工具,一周工作量缩减至一天,详见本文文末。

通过本文你可以学到

  • 如何在 Element Plus 中生成动态表格
  • 如何在 Element Plus 中动态修改表格
  • 如何在 Element Plus 中创建动态多级表头

先来展示个「动态修改表格」的最终效果图吧

Vue3 + Element Plus动态修改表格

Vue3 + Element Plus 配置环境

先使用 vue-cli 初始化应用,这里我们选择 vue3 的版本:

vue create kalacloud-vue3-element-plus-table
// OR
npx vue create kalacloud-vue3-element-plus-table

然后安装 UI 框架 Element Plus:

npm install element-plus --save
// OR
yarn add element-plus

安装完成后,在项目里导入 ElementPlus,修改 main.js 如下:

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'

const app = createApp(App)

app.use(ElementPlus)
app.mount('#app')

导入后,就可以启动项目了,执行以下命令:

npm run serve

看到以下界面说明项目成功启动了!后面就可以进入本教程的正式内容了。

kalacloud-卡拉云-初始化项目

Vue3 + Element Plus 生成动态表格

有一个场景是表格列并不是固定的,不能在前端写死,而是需要通过后端返回的数据进行动态渲染,比如后端返回了如下的表头数据:

tableHeader: {
  name: "姓名",
  birth: "生日",
  address: "地址",
  age: "年龄",
  phone: "电话",
}

这个对象中的 key 对应表格数据中的 propvalue 对应实际显示的 label,这样通过一个简单的对象,就可以连接表头和 表格body 之间的关系。然后还需要后端返回具体的表格数据:

tableData: [{
  name: '张三',
  date: '2016-05-02',
  address: '上海市普陀区金沙江路 1518 弄',
  age: 18,
  phone:"12345678910",
}, {
  date: '2016-05-04',
  name: '李四',
  address: '上海市普陀区金沙江路 1517 弄',
  age: 19,
  phone:"12345678911",
}, {
  date: '2016-05-01',
  name: '王五',
  address: '上海市普陀区金沙江路 1519 弄',
  age: 20,
  phone:"12345678912",
}, {
  date: '2016-05-03',
  name: '赵六',
  address: '上海市普陀区金沙江路 1516 弄',
  age: 21,
  phone:"12345678913",
}]

实现表格列动态渲染的功能,需要用到一个很关键的 vue 指令,那就是 v-forv-for 不仅可以遍历数据,也可以遍历对象:

<div v-for="(value, key) in object">
  {{ key }}: {{ value }}
</div>

这里我们就需要用到这个特性,来对 tableHeader 进行遍历,获取 keyvalue。基于以上讲解,现在我们具体实践一下如何实现表格列的动态渲染。在 components 目录中新建 DynamicTable.vue

<template>
  <div>
    <h2>Vue3 + Element plus 动态表格</h2>
    <el-table :data="tableData" style="width: 100%">
      <el-table-column
        :prop="index"
        :label="item"
        v-for="(item, index) in tableHeader"
        :key="index"
      >
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  name: "test",
  data() {
    return {
      tableHeader: {
        name: "姓名",
        birth: "生日",
        address: "地址",
        age: "年龄",
        phone: "电话",
      },
      tableData: [{
        name: '张三',
        address: '上海市普陀区金沙江路 1518 弄',
        birth: '2016-05-02',
        age: 18,
        phone: "12345678910",
      }, {
        name: '李四',
        birth: '2016-05-04',
        address: '上海市普陀区金沙江路 1517 弄',
        age: 19,
        phone: "12345678911",
      }, {
        name: '王五',
        birth: '2016-05-01',
        address: '上海市普陀区金沙江路 1519 弄',
        age: 20,
        phone: "12345678912",
      }, {
        name: '赵六',
        birth: '2016-05-03',
        address: '上海市普陀区金沙江路 1516 弄',
        age: 21,
        phone: "12345678913",
      }]
    }
  },
}
</script>

组件编写完成后,修改 App.vue,导入该组件即可:

<template>
  <DynamicTable />
</template>

<script>
import DynamicTable from './components/DynamicTable.vue'

export default {
  name: 'App',
  components: {
    DynamicTable
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

保存后页面会自动热更新,实现效果如下:

kalacloud-卡拉云-动态表格

这个只是比较基本的使用,如果某些列有一些定制需求,比如需要支持根据日期排序,这个时候可以对 tableHeader 进行改造,使 value 是一个对象,这样就可以携带更多的表头配置信息:

tableHeader: {
  name: {
    label: "姓名",
    sort: true,
  },
  birth: {
    label: "生日",
    sort: false,
  },
  address: {
    label: "地址",
    sort: false,
  },
  age: {
    label: "年龄",
    sort: true,
  },
  phone: {
    label: "电话",
    sort: false,
  }
},

然后再改造 el-table 如下:

<el-table-column
  :prop="index"
  :label="item.label"
  v-for="(item, index) in tableHeader"
  :sortable="item.sort"
  :key="index"
>

kalacloud-卡拉云-动态列排序

以上就实现了基于动态列的表头配置,这里的关键在于 tableHeader 的数据结构如何定义,可以把列信息都放在 tableHeader 中,然后再通过 v-for 循环列就可以渲染出对应的表格列。当然 tableHeader 也可以是一个数组,使用方法都是类似的,大家可以自己去尝试一下。

扩展阅读:《多款好用的 vue 表单设计器推荐测评

Vue3 + Element Plus 动态修改表格

基于以上的思路,我们还可以做的更多,比如动态添加指定行,指定列,或者删除指定行或者列等操作,都是使用相同的思路来实现。我们来具体实践一下,这里我们需要用到 @element-plus/icons-vue,先安装一下:

# NPM
npm install @element-plus/icons-vue
# Yarn
yarn add @element-plus/icons-vue

然后在 main.js 中导入:

import * as ElementPlusIconsVue from '@element-plus/icons-vue'
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}

components 目录下新建 DynamicModifyTable.vue

<template>
  <div>
    <h2>Vue3 + Element plus 动态修改表格</h2>
    <h3>「卡拉云 - 极速搭建企业内部工具,十倍提升开发效率」</h3>
    <el-table :data="tableData" style="width: 100%">
      <el-table-column
        :prop="item.prop"
        :label="item.label"
        v-for="(item, index) in tableHeader"
        :key="item.prop"
      >
        <template #default="scope">
          <div
            v-show="item.editable || scope.row.editable"
            class="editable-row"
          >
            <template v-if="item.type === 'input'">
              <el-input
                size="small"
                v-model="scope.row[item.prop]"
                :placeholder="`请输入${item.label}`"
                @change="handleEdit(scope.$index, scope.row)"
              />
            </template>
            <template v-if="item.type === 'date'">
              <el-date-picker
                v-model="scope.row[item.prop]"
                type="date"
                value-format="YYYY-MM-DD"
                :placeholder="`请输入${item.label}`"
                @change="handleEdit(scope.$index, scope.row)"
              />
            </template>
          </div>
          <div
            v-show="!item.editable && !scope.row.editable"
            class="editable-row"
          >
            <span class="editable-row-span">{{ scope.row[item.prop] }}</span>
            <el-popover
              placement="right"
              :width="120"
              trigger="hover"
              content="this is content, this is content, this is content"
            >
              <template #reference>
                <el-icon class="icon" :size="18">
                  <Edit />
                </el-icon>
              </template>
              <div class="menu-list">
                <div
                  class="menu-item"
                  @click="prepend(scope.$index)"
                >
                  上方插入一行
                </div>
                <div
                  class="menu-item divider"
                  @click="append(scope.$index)"
                >
                  下方插入一行
                </div>
                <div class="menu-item" @click="deleteCurrentColumn(index)">
                  删除当前列
                </div>
                <div class="menu-item" @click="insertBefore(index)">
                  前方插入一列
                </div>
                <div class="menu-item" @click="insertAfter(index)">
                  后方插入一列
                </div>
              </div>
            </el-popover>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="操作">
        <template #default="scope">
          <el-button
            v-show="!scope.row.editable"
            size="small"
            @click="scope.row.editable = true"
            >编辑</el-button
          >
          <el-button
            v-show="scope.row.editable"
            size="small"
            type="success"
            @click="scope.row.editable = false"
            >确定</el-button
          >
          <el-button
            size="small"
            type="danger"
            @click="handleDelete(scope.$index)"
            >删除</el-button
          >
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
const item = {
  name: '',
  birth: '',
  province: "",
  city: "",
  address: '',
  phone: "",
}
const header = {
  prop: "key",
  label: "自定义",
  editable: false,
  type: "input",
}
export default {
  name: "DynamicModifyTable",
  data() {
    return {
      tableHeader: [
        {
          prop: "name",
          label: "姓名",
          editable: false,
          type: "input",
        },
        {
          prop: "birth",
          label: "生日",
          editable: false,
          type: "date"
        },
        {
          prop: "phone",
          label: "电话",
          editable: false,
          type: "input"
        },
        {
          prop: "province",
          label: "省份",
          editable: false,
          type: "input"
        },
        {
          prop: "city",
          label: "市区",
          editable: false,
          type: "input"
        },
        {
          prop: "address",
          label: "详细地址",
          editable: false,
          type: "input"
        }
      ],
      tableData: [{
        name: '张三',
        province: "上海市",
        city: "普陀区",
        address: "金沙江路 1518 弄",
        birth: '2016-05-02',
        phone: "12345678910",
      }, {
        name: '李四',
        birth: '2016-05-04',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1517 弄',
        age: 19,
        phone: "12345678911",
      }, {
        name: '王五',
        birth: '2016-05-01',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1519 弄',
        phone: "12345678912",
      }, {
        name: '赵六',
        birth: '2016-05-03',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1516 弄',
        phone: "12345678913",
      }]
    }
  },
  methods: {
    handleEdit(row) {
      row.editable = true;
    },
    handleDelete(index) {
      this.tableData.splice(index, 1);
    },
    prepend(index) {
      item.editable = true
      this.tableData.splice(index, 0, item);
    },
    append(index) {
      item.editable = true
      this.tableData.splice(index + 1, 0, item);
    },
    deleteCurrentColumn(index) {
      this.tableHeader.splice(index, 1);
    },
    insertBefore(index) {
      header.editable = true;
      this.tableHeader.splice(index, 0, header);

Vue3 + Element Plus 创建动态多级表头

多级表头的实现比较简单,主要是通过 el-table-column 的嵌套来完成的,在 components 目录下新建 MultiHeaderTable.vue 文件:

<template>
  <div>
    <h2>Vue3 + Element plus 动态表格</h2>
    <el-table :data="tableData" style="width: 100%">
      <el-table-column
        :prop="item.prop"
        :label="item.label"
        v-for="(item, index) in tableHeader"
        :key="index"
      >
        <el-table-column
          :prop="child.prop"
          :label="child.label"
          v-for="(child, childIndex) in item.children"
          :key="childIndex"
        ></el-table-column>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  name: "MultiHeaderTable",
  data() {
    return {
      tableHeader: [
        {
          prop: "name",
          label: "姓名",
        },
        {
          prop: "birth",
          label: "生日",
        },
        {
          prop: "phone",
          label: "电话",
        },
        {
          label: "地址",
          children: [
            {
              prop: "province",
              label: "省份",
            },
            {
              prop: "city",
              label: "市区",
            },
            {
              prop: "address",
              label: "详细地址",
            }
          ]
        }
      ],
      tableData: [{
        name: '张三',
        province: "上海市",
        city: "普陀区",
        address: "金沙江路 1518 弄",
        birth: '2016-05-02',
        phone: "12345678910",
      }, {
        name: '李四',
        birth: '2016-05-04',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1517 弄',
        age: 19,
        phone: "12345678911",
      }, {
        name: '王五',
        birth: '2016-05-01',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1519 弄',
        phone: "12345678912",
      }, {
        name: '赵六',
        birth: '2016-05-03',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1516 弄',
        phone: "12345678913",
      }]
    }
  },
}
</script>

对于 tableHeader 的定义,我们通过 children 字段来指定当前列的二级表头,但是会发现效果并不是我们预期的那样:

kalacloud-卡拉云-错误演示动态多级表头

这是为什么呢?原来是因为 el-table-column 会检测内部是否还有 el-table-column,如果有的话,默认会显示内层的 el-table-column,但是在一级表头的情况下,内层 el-table-column 并没有值。所以我们需要简单修改一下代码,那就是通过 v-if="item.children" 来判断当前列是否有二级表头:

<template v-if="item.children">
  <el-table-column
    :prop="child.prop"
    :label="child.label"
    v-for="(child, childIndex) in item.children"
    :key="childIndex"
  ></el-table-column>
</template>

如果不这么做,那就只能渲染有二级表头的列,无法正常显示一级表头的数据, 最后的效果如下:

kalacloud-卡拉云-动态多级表头

扩展阅读:《12款最棒的 Vue ui 组件库框架 推荐测评

Vue3 + Element Plus 表格中单元格行合并

我们先来看下如何实现行合并,行合并或者是列合并,都需要用到 el-tablespan-method 这个方法,在官方的例子中,是通过固定返回 rowspancolspan 来实现行合并的:

const objectSpanMethod = ({
  row,
  column,
  rowIndex,    // 需要合并的开始行
  columnIndex, // 需要合并的列
}) => {
  if (columnIndex === 0) {
    if (rowIndex % 2 === 0) {
      return {
        rowspan: 2, //合并的行数
        colspan: 1, //合并的列数
      }
    } else {
      return {
        rowspan: 0,
        colspan: 0,
      }
    }
  }
}

但是在动态数据的场景下,这种方法就不适用了,因为前端的表格数据往往是后端通过接口返回的。比如我们有以下数据结构:

tableData: [{
  name: '张三',
  province: "上海市",
  city: "普陀区",
  address: "金沙江路 1518 弄",
  birth: '2016-05-02',
  phone: "12345678910",
}, {
  name: '李四',
  birth: '2016-05-02',
  province: "上海市",
  city: "普陀区",
  address: '金沙江路 1517 弄',
  age: 19,
  phone: "12345678911",
}, {
  name: '王五',
  birth: '2016-05-03',
  province: "上海市",
  city: "普陀区",
  address: '金沙江路 1519 弄',
  phone: "12345678912",
}, {
  name: '赵六',
  birth: '2016-05-04',
  province: "上海市",
  city: "普陀区",
  address: '金沙江路 1516 弄',
  phone: "12345678913",
}, {
  name: '孙七',
  birth: '2016-05-04',
  province: "上海市",
  city: "普陀区",
  address: '金沙江路 1516 弄',
  phone: "12345678913",
}, {
  name: '周八',
  birth: '2016-05-04',
  province: "上海市",
  city: "普陀区",
  address: '金沙江路 1516 弄',
  phone: "12345678913",
}, {
  name: '吴九',
  birth: '2016-05-06',
  province: "上海市",
  city: "普陀区",
  address: '金沙江路 1516 弄',
  phone: "12345678913",
}]

我们的需求是把相同 birth 进行合并。在 components 目录下新建 RowMergeTable.vue 文件:

<template>
  <div>
    <h2>Vue3 + Element plus 动态行合并表格</h2>
    <el-table
      :data="tableData"
      style="width: 100%"
      :span-method="objectSpanMethod"
      border
    >
      <el-table-column
        :prop="item.prop"
        :label="item.label"
        v-for="(item, index) in tableHeader"
        :key="index"
      ></el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  name: "RowMergeTable",
  data() {
    this.spanArr = [];
    return {
      tableHeader: [
        {
          prop: "birth",
          label: "生日",
        },
        {
          prop: "name",
          label: "姓名",
        },
        {
          prop: "phone",
          label: "电话",
        },
        {
          prop: "province",
          label: "省份",
        },
        {
          prop: "city",
          label: "市区",
        },
        {
          prop: "address",
          label: "详细地址",
        }
      ],
      tableData: [{
        name: '张三',
        province: "上海市",
        city: "普陀区",
        address: "金沙江路 1518 弄",
        birth: '2016-05-02',
        phone: "12345678910",
      }, {
        name: '李四',
        birth: '2016-05-02',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1517 弄',
        age: 19,
        phone: "12345678911",
      }, {
        name: '王五',
        birth: '2016-05-03',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1519 弄',
        phone: "12345678912",
      }, {
        name: '赵六',
        birth: '2016-05-04',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1520 弄',
        phone: "12345678913",
      }, {
        name: '孙七',
        birth: '2016-05-04',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1521 弄',
        phone: "12345678913",
      }, {
        name: '周八',
        birth: '2016-05-04',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1522 弄',
        phone: "12345678913",
      }, {
        name: '吴九',
        birth: '2016-05-06',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1523 弄',
        phone: "12345678913",
      }]
    }
  },
  created() {
    this.getSpanArr(this.tableData);
  },
  methods: {
    getSpanArr(data) {
      for (var i = 0; i < data.length; i++) {
        if (i === 0) {
          this.spanArr.push(1);
          this.pos = 0
        } else {
          if (data[i].birth === data[i - 1].birth) {
            this.spanArr[this.pos] += 1;
            this.spanArr.push(0);
          } else {
            this.spanArr.push(1);
            this.pos = i;
          }
        }
      }
    },
    objectSpanMethod({ rowIndex, columnIndex }) {
      if (columnIndex === 0) {
        const _row = this.spanArr[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return {
          rowspan: _row,
          colspan: _col
        }
      }
    }
  }
}
</script>

上面的例子就实现了行合并的功能:

kalacloud-卡拉云-动态行合并

因为表格的数据是动态的,所以我们需要事先通过计算,来得知哪些行是需要合并的,这里就是通过 getSpanArr 方法来实现的,全局维护了一个 spanArr 变量,用于记录每一行需要合并的数字,posspanArr 的索引,这样就可以根据索引来动态设置需要合并的行树。当 i === 0,说明是第一行数据,向 spanArr 数组中 push 1,当 i !== 0,此时就需要比较当前行与前一行数据的 birth 是否相等,如果相等,则利用索引,修改当前行需要合并的行数。

objectSpanMethod 方法,在 el-table 渲染每一行数据的时候都会执行,这样就可以通过 rowIndex 来获取每一行需要合并的行数信息,来实现行合并的功能。

那么如何实现多行合并?其实也是一样的思路,通过 spanMap 可以存储多个列的行合并信息。在 components 下新建 MultiRowMergeTable.vue:

<template>
  <div>
    <h2>Vue3 + Element plus 动态多行合并表格</h2>
    <el-table
      :data="tableData"
      style="width: 100%"
      :span-method="objectSpanMethod"
      border
    >
      <el-table-column
        :prop="item.prop"
        :label="item.label"
        v-for="(item, index) in tableHeader"
        :key="index"
      ></el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  name: "MultiRowMergeTable",
  data() {
    this.spanMap = {};
    this.mergedColumns = ["birth", "province", "city"]
    return {
      tableHeader: [
        {
          prop: "birth",
          label: "生日",
        },
        {
          prop: "name",
          label: "姓名",
        },
        {
          prop: "phone",
          label: "电话",
        },
        {
          prop: "province",
          label: "省份",
        },
        {
          prop: "city",
          label: "市区",
        },
        {
          prop: "address",
          label: "详细地址",
        }
      ],
      tableData: [{
        name: '张三',
        province: "上海市",
        city: "普陀区",
        address: "金沙江路 1518 弄",
        birth: '2016-05-02',
        phone: "12345678910",
      }, {
        name: '李四',
        birth: '2016-05-02',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1517 弄',
        age: 19,
        phone: "12345678911",
      }, {
        name: '王五',
        birth: '2016-05-03',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1519 弄',
        phone: "12345678912",
      }, {
        name: '赵六',
        birth: '2016-05-04',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1520 弄',
        phone: "12345678913",
      }, {
        name: '孙七',
        birth: '2016-05-04',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1521 弄',
        phone: "12345678913",
      }, {
        name: '周八',
        birth: '2016-05-04',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1522 弄',
        phone: "12345678913",
      }, {
        name: '吴九',
        birth: '2016-05-06',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1523 弄',
        phone: "12345678913",
      }]
    }
  },
  created() {
    this.getSpanArr(this.tableData);
  },
  methods: {
    getSpanArr(data) {
      for (var i = 0; i < data.length; i++) {
        if (i === 0) {
          this.mergedColumns.forEach(column => {
            this.spanMap[column] = {
              spanArr: [1],
              pos: 0
            }
          })
        } else {
          this.mergedColumns.forEach(column => {
            if (data[i][column] === data[i - 1][column]) {
              this.spanMap[column].spanArr[this.spanMap[column].pos] += 1;
              this.spanMap[column].spanArr.push(0)
            } else {
              this.spanMap[column].spanArr.push(1);
              this.spanMap[column].pos = i;
            }
          })
        }
      }
    },
    objectSpanMethod({ column, rowIndex }) {
      if (this.spanMap[column.property]) {
        const _row = this.spanMap[column.property].spanArr[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return {
          rowspan: _row,
          colspan: _col
        }
      }
    }
  }
}
</script>

实现效果如下:

kalacloud-卡拉云-动态多行合并

动态多行合并的需求往往更常见,需要把每一列中,相同的数据进行合并,都可以参照这个思路来实现。

扩展阅读:《Vue + Node.js 全栈开发实战教程 - 手把手教你搭建「文件上传」管理后台

Vue3 + Element Plus 表格中单元格列合并

接下来,我们来看下如何实现列的合并,其实思路是和行合并类似的,也需要用到 span-method 这个方法,唯一不同的在于,列合并需要处理被合并列的原始数据,否则被合并列的原始数据会填充到合并之后的表格里,这样说可能有点抽象,我们写来写一个例子,在 components 下新建 ColumnMergeTable.vue:

<template>
  <div>
    <h2>Vue3 + Element plus 动态表格列合并</h2>
    <el-table
      :data="tableData"
      style="width: 100%"
      :span-method="objectSpanMethod"
      border
    >
      <el-table-column
        :prop="item.prop"
        :label="item.label"
        v-for="(item, index) in tableHeader"
        :key="index"
      ></el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  name: "ColumnMergeTable",
  data() {
    return {
      tableHeader: [
        {
          prop: "birth",
          label: "生日",
        },
        {
          prop: "name",
          label: "姓名",
        },
        {
          prop: "phone",
          label: "电话",
        },
        {
          prop: "province",
          label: "省份",
        },
        {
          prop: "city",
          label: "市区",
        },
        {
          prop: "address",
          label: "详细地址",
        }
      ],
      tableData: [{
        name: '张三',
        province: "上海市",
        city: "普陀区",
        address: "金沙江路 1518 弄",
        birth: '2016-05-02',
        phone: "12345678910",
      }, {
        name: '李四',
        birth: '2016-05-02',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1517 弄',
        age: 19,
        phone: "12345678911",
      }, {
        name: '王五',
        birth: '2016-05-03',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1519 弄',
        phone: "12345678912",
      }, {
        name: '赵六',
        birth: '2016-05-04',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1520 弄',
        phone: "12345678913",
      }, {
        name: '孙七',
        birth: '2016-05-04',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1521 弄',
        phone: "12345678913",
      }, {
        name: '周八',
        birth: '2016-05-04',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1522 弄',
        phone: "12345678913",
      }, {
        name: '吴九',
        birth: '2016-05-06',
        province: "上海市",
        city: "普陀区",
        address: '金沙江路 1523 弄',
        phone: "12345678913",
      }]
    }
  },
  methods: {
    objectSpanMethod({ rowIndex, columnIndex }) {
      // 隐藏第二行或者第三行的列
      if (rowIndex === 1 || rowIndex === 2) {
        // 合并第二行
        if (columnIndex === 1) {
          // 从第二列开始
          return [1, 3]
          //或者返回如下形式也可以
          // return {
          //    rowspan: 1,
          //    colspan: 3
          //  }
          // 这里的 else if 即使用来处理被合并列的原始数据的情况,需要隐藏原始单元格
        } else if (columnIndex === 2 || columnIndex === 3) {
          return [0, 0]
        }
      }
    }
  }
}
</script>

可以看出来,列合并其实比行合并简单一些,返回一个数组更容易理解一些,数组的第一项表示合并的起始列,第二项表示合并的终止列,其区间的所有列都会合并成一列,被合并的列还需要通过 [0, 0] 来隐藏对应的单元格,这个是和行合并不同的地方。

扩展阅读:《Vue echarts 使用教程

Vue3 + Element Plus 动态表格源代码

本教程所写源代码可在我们的 github 上找到。

动态表格与卡拉云

本文详细讲解如何 Vue3 + Element Plus 中如何创建动态表格的问题。其实如果你根本不想处理复杂的前端问题,完全可以使用卡拉云来处理前端表格,卡拉云内置表格组件,直接鼠标拖拽即可生成,不仅可以处理动态表格,内容实时编辑以及表格中展示图片等功能,还有强大的过滤筛选、数据导出功能。

卡拉云内置表格

拖拽生成表格,接入数据源,5分钟生成后台工具

使用卡拉云,无需懂任何前端,仅需拖拽即可快速生成,一键连接后端数据源,极速开发后台管理工具。

下面是用卡拉云搭建的数据库 CURD 后台管理系统,只需拖拽组件,即可在10分钟内完成搭建。

卡拉云 SQL admin 后台管理系统

可直接分享给同事一起使用:https://my.kalacloud.com/apps/8z9z3yf9fy/published

卡拉云是新一代低代码开发平台,与 React 这类框架相比,卡拉云无需配置开发环境,直接注册即可开始搭建。开发者无需处理任何前端问题,简单拖拽即可生成图表、表格、表单、富文本等功能组件,一键接入数据库及 API,快速完成企业内部工具搭建,还可以分享给团队成员共享使用,数周的开发时间,缩短至 1 小时。

扩展阅读:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK