当我们需要在前端中展示一些表格内容时,我们往往使用Vue
的table
来实现
1. 原生态实现
<template>
<div>
<table class="no-gap-table">
<thead>
<tr>
<th class="styled-header" colspan="4">Column1</th>
<th class="styled-header" colspan="3">column2</th>
<th class="styled-header" colspan="2">Column3</th>
<th class="styled-header" rowspan="3">Column4</th>
<th class="styled-header" colspan="2">Column5</th>
</tr>
<tr>
<th class="styled-header" colspan="2">SubColumn1 aaaa</th>
<th class="styled-header" colspan="2">SubColumn1 bbbb</th>
<th class="styled-header" colspan="2">SubColumn2 cccc</th>
<th class="styled-header" colspan="1">SubColumn2 dddd</th>
<th class="styled-header" colspan="1">SubColumn3 eeee</th>
<th class="styled-header" colspan="1">SubColumn3 ffff</th>
<th class="styled-header" colspan="1" rowspan="2">SubColumn5 ffff</th>
<th class="styled-header" colspan="1" rowspan="2">SubColumn5 ffff</th>
</tr>
<tr>
<th class="styled-header">ChildColumn aaaa</th>
<th class="styled-header">ChildColumn bbbb</th>
<th class="styled-header">ChildColumn cccc</th>
<th class="styled-header">ChildColumn dddd</th>
<th class="styled-header">ChildColumn eeee</th>
<th class="styled-header">ChildColumn ffff</th>
<th class="styled-header">ChildColumn dddd</th>
<th class="styled-header">ChildColumn eeee</th>
<th class="styled-header">ChildColumn ffff</th>
</tr>
</thead>
<tbody>
<tr v-for="(item) in items" :key="item.id">
<td>{{ item.column1 }}</td>
<td>{{ item.column2_1 }}</td>
<td>{{ item.column2_2 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name:"MyTable",
props:['columnTreeInfo','tableDataSource'],
data() {
return {
data:{
items: [
{ id: 1, column1: 'Item 1', column2_1: 'Subitem 1', column2_2: 'Subitem 2', column3: 'Value 1' },
{ id: 2, column1: 'Item 2', column2_1: 'Subitem 1', column2_2: 'Subitem 2', column3: 'Value 2' },
]
}
};
},
methods:{
},
created(){
this.$refs['columnInfo'].appendChild(this.template)
},
beforeCreate(){
console.log(this);
}
};
</script>
<style scoped>
.no-gap-table {
border-collapse: collapse; /* Merge adjacent cell borders */
width: 100%; /* Set the table width to 100% */
}
.no-gap-table th,
.no-gap-table td {
border: 1px solid #000; /* Add a border around each cell */
padding: 0; /* Remove cell padding */
margin: 0; /* Remove cell margin */
}
.styled-header {
border: solid #000; /* Add a 2px solid black underline */
padding: 2 px; /* Add some padding for better visual appearance */
}
</style>
当前实现如下:
2. 动态递归封装组件
2.1. 层级递归实现
<template>
<div>
<table class="no-gap-table">
<MyTableChildRow :columns="headerColumns" />
<tbody>
<tr v-for="(item) in items" :key="item.id">
<td>{{ item.column1 }}</td>
<td>{{ item.column2_1 }}</td>
<td>{{ item.column2_2 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import MyTableChildRow from './MyTableChildRow.vue';
export default {
components: {
MyTableChildRow
},
data() {
return {
headerColumns: [
{
key:1,
children:[
{
label:"Column1",
colspan:1,
},
{
label:"Column2",
colspan:1,
},
{
label:"Column3",
colspan:1,
},
{
label:"Column4",
colspan:2,
}
]
},
{
key:2,
children:[
{
label:"Column1",
colspan:1,
},
{
label:"Column2",
colspan:1,
},
{
label:"Column3",
colspan:1,
},
{
label:"Column4",
colspan:1,
},
{
label:"Column5",
colspan:1,
}
]
},
{
key:3,
children:[
{
label:"Column1",
colspan:1,
},
{
label:"Column2",
colspan:1,
},
{
label:"Column3",
colspan:1,
},
{
label:"Column4",
colspan:1,
},
{
label:"Column5",
colspan:1,
}
]
},
{
key:4,
children:[
{
label:"Column1",
colspan:1,
},
{
label:"Column2",
colspan:1,
},
{
label:"Column3",
colspan:1,
},
{
label:"Column4",
colspan:1,
},
{
label:"Column5",
colspan:1,
}
]
},
],
items: [
{ id: 1, column1: 'Item 1', column2_1: 'Subitem 1', column2_2: 'Subitem 2', column3: 'Value 1' },
{ id: 2, column1: 'Item 2', column2_1: 'Subitem 1', column2_2: 'Subitem 2', column3: 'Value 2' },
]
};
}
};
</script>
<style scoped>
.no-gap-table {
border-collapse: collapse; /* Merge adjacent cell borders */
width: 100%; /* Set the table width to 100% */
}
.no-gap-table th,
.no-gap-table td {
border: 1px solid #000; /* Add a border around each cell */
padding: 0; /* Remove cell padding */
margin: 0; /* Remove cell margin */
}
</style>
<template>
<div>
<table class="no-gap-table">
<thead>
<MyTableChildCol :columns="headerColumns" />
</thead>
<tbody>
<tr v-for="(item) in items" :key="item.id">
<td>{{ item.column1 }}</td>
<td>{{ item.column2_1 }}</td>
<td>{{ item.column2_2 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
<td>{{ item.column3 }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import MyTableChildCol from './MyTableChildCol.vue';
export default {
components: {
MyTableChildCol
},
data() {
return {
headerColumns: [
{ key: 'header1', label: 'Header 1', colspan: 2 },
{
key: 'header2', label: 'Header 2', rowspan: 2,
children: [
{ key: 'subheader2_1', label: 'Subheader 2.1' },
{ key: 'subheader2_2', label: 'Subheader 2.2', colspan: 2,
children: [
{ key: 'subsubheader2_2_1', label: 'Sub-subheader 2.2.1' },
{ key: 'subsubheader2_2_2', label: 'Sub-subheader 2.2.2' }
]
}
]
},
{ key: 'header3', label: 'Header 3', colspan: 2 }
],
items: [
{ id: 1, column1: 'Item 1', column2_1: 'Subitem 1', column2_2: 'Subitem 2', column3: 'Value 1' },
{ id: 2, column1: 'Item 2', column2_1: 'Subitem 1', column2_2: 'Subitem 2', column3: 'Value 2' },
]
};
}
};
</script>
<style scoped>
.no-gap-table {
border-collapse: collapse; /* Merge adjacent cell borders */
width: 100%; /* Set the table width to 100% */
}
.no-gap-table th,
.no-gap-table td {
border: 1px solid #000; /* Add a border around each cell */
padding: 0; /* Remove cell padding */
margin: 0; /* Remove cell margin */
}
</style>
3. 开源好用的一些Vue table 组件汇总
3.1. Vue easytable
Vue Easytable 是一个基于Vue2的表格组件,支持单元格合并、单元格编辑、多表头固定、多列固定、列拖动、排序、自定义列、分页、单元格编辑、多选、条件过滤、footer 汇总等功能。
3.1.1. 功能
- 自适应,可以随着浏览器窗口改变自动适应
- 固定列,表头固定
- 支持列宽拖动
- 支持单个字段排序和多个字段排序
- 自定义列、自定义单元格样式
- loading效果、自定义loading 等
- 自带分页组件
- 单元格编辑
- 支持单元格合并 (colSpan and rowSpan)
- 支持 checkbox 多选功能
- footer 汇总功能
- 添加条件过滤功能
- 安装 Vue EasyTable:
首先,在你的 Vue 项目中安装 Vue EasyTable:
npm install vue-easytable --save
3.1.2. git地址和官方地址
- git地址:Happy-Coding-Clans/vue-easytable: A powerful data table based on vuejs. You can use it as data grid、Microsoft Excel or Google sheets. It supports virtual scroll、cell edit etc. (github.com)
- 官网地址:Table Component/ Data Grid / Data Table.Support Virtual Scroll,Column Fixed,Header Fixed,Header Grouping,Filter,Sort,Cell Ellipsis,Row Expand,Row Checkbox (gitee.io)
3.1.3. 内容介绍
- 官网首页效果图
- 复合表头效果以及代码
<template>
<ve-table border-y :columns="columns" :table-data="tableData" />
</template>
<script>
export default {
data() {
return {
columns: [
{
field: "col1",
key: "a",
title: "col1",
width: "10%"
},
{
title: "col2-col3",
children: [
{
field: "col2",
key: "b",
title: "col2",
width: 100,
},
{
field: "col3",
key: "c",
title: "col3",
width: 110,
},
],
},
{
title: "col4-col5-col6",
children: [
{
title: "col4-col5",
children: [
{
field: "col4",
key: "d",
title: "col4",
width: 130,
},
{
field: "col5",
key: "e",
title: "col5",
width: 140,
},
],
},
{
title: "col6",
field: "col6",
key: "f",
width: 140,
},
],
},
{
field: "col7",
key: "g",
title: "col7",
width: 150
},
{
field: "col8",
key: "h",
title: "col8",
width: 160
},
],
tableData: [],
};
},
methods: {
initTableData() {
let data = [];
for (let i = 0; i < 6; i++) {
data.push({
rowKey: i,
col1: i,
col2: i,
col3: i,
col4: i,
col5: i,
col6: i,
col7: i,
col8: i,
});
}
this.tableData = data;
},
},
created() {
this.initTableData();
},
};
</script>
- 单元格编辑
1、通过 `editOption`属性配置单元格编辑功能
2、通过 `columns` 对象设置`edit=true`允许编辑的列
<template>
<div>
<button class="button-demo" @click="startEditingCell(0,'name')">编辑单元格0-0</button>
<button class="button-demo" @click="startEditingCell(2,'hobby','')">
编辑并清空单元格2-2
</button>
<br />
<br />
<ve-table
ref="tableRef"
rowKeyFieldName="rowKey"
:max-height="300"
:fixed-header="true"
:columns="columns"
:table-data="tableData"
:editOption="editOption"
:row-style-option="rowStyleOption"
border-y
/>
</div>
</template>
<script>
export default {
data() {
return {
rowStyleOption: {
clickHighlight: false,
hoverHighlight: false,
},
// edit option 可控单元格编辑
editOption: {
// cell value change
cellValueChange: ({ row, column }) => {
console.log("cellValueChange row::", row);
console.log("cellValueChange column::", column);
},
},
columns: [
{
field: "",
key: "a",
title: "",
width: 50,
align: "center",
operationColumn: true,
renderBodyCell: ({ row, column, rowIndex }, h) => {
return ++rowIndex;
},
},
{
field: "name",
key: "name",
title: "Name",
align: "left",
width: "15%",
edit: true,
},
{
field: "date",
key: "date",
title: "Date",
align: "left",
width: "15%",
edit: true,
},
{
field: "hobby",
key: "hobby",
title: "Hobby",
align: "left",
width: "30%",
edit: true,
},
{
field: "address",
key: "address",
title: "Address",
align: "left",
width: "40%",
edit: true,
},
],
// table data
tableData: [
{
name: "John",
date: "1900-05-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Shanghai",
rowKey: 0,
},
{
name: "Dickerson",
date: "1910-06-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Beijing",
rowKey: 1,
},
{
name: "Larsen",
date: "2000-07-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Chongqing",
rowKey: 2,
},
{
name: "Geneva",
date: "2010-08-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Xiamen",
rowKey: 3,
},
{
name: "Jami",
date: "2020-09-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Shenzhen",
rowKey: 4,
},
],
};
},
methods: {
// start editing cell
startEditingCell(rowKey, colKey, defaultValue) {
this.$refs["tableRef"].startEditingCell({ rowKey, colKey, defaultValue });
},
},
};
</script>
- 自定义事件
<template>
<div>
打开F12 查看 console 信息
<ve-table
:columns="columns"
:table-data="tableData"
:event-custom-option="eventCustomOption"
/>
</div>
</template>
<script>
export default {
data() {
return {
eventCustomOption: {
bodyRowEvents: ({ row, rowIndex }) => {
return {
click: (event) => {
console.log("click::", row, rowIndex, event);
},
dblclick: (event) => {
console.log("dblclick::", row, rowIndex, event);
},
contextmenu: (event) => {
console.log("contextmenu::", row, rowIndex, event);
},
mouseenter: (event) => {
console.log("mouseenter::", row, rowIndex, event);
},
mouseleave: (event) => {
console.log("mouseleave::", row, rowIndex, event);
},
};
},
},
columns: [
{
field: "",
key: "a",
title: "",
width: 50,
align: "center",
renderBodyCell: ({ row, column, rowIndex }, h) => {
return ++rowIndex;
},
},
{
field: "name",
key: "b",
title: "Name",
width: 200,
align: "left",
},
{
field: "hobby",
key: "c",
title: "Hobby",
width: 300,
align: "left",
},
{
field: "address",
key: "d",
title: "Address",
width: "",
align: "left",
},
],
tableData: [
{
rowKey: 1001,
name: "John",
date: "1900-05-20",
hobby: "coding",
address: "No.1 Century Avenue, Shanghai",
},
{
rowKey: 1002,
name: "Dickerson",
date: "1910-06-20",
hobby: "coding",
address: "No.1 Century Avenue, Beijing",
},
{
rowKey: 1003,
name: "Larsen",
date: "2000-07-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Chongqing",
},
{
rowKey: 1004,
name: "Geneva",
date: "2010-08-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Xiamen",
},
{
rowKey: 1005,
name: "Jami",
date: "2020-09-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Shenzhen",
},
],
};
},
};
</script>
- 更多特性和API请前往官网文档查看
3.2. Vue Good Table
Vue Good Table是一款基于Vue.js的易于使用、高度可配置且灵活的表格组件,使得在Web应用中呈现大量数据非常容易。Vue Good Table允许您对表格进行排序、分页、筛选、编辑、导出、自定义列、自定义行、悬停和展开/收缩行等操作。
Vue Good Table使用简单,只需要导入并在Vue实例中注册即可:
3.2.1. 安装使用
npm i vue-good-table
3.2.2. git地址和官网地址
- git地址:xaksis/vue-good-table: An easy to use powerful data table for vuejs with advanced customizations including sorting, column filtering, pagination, grouping etc (github.com)
- 官网地址:vue-good-table (xaksis.github.io)
3.2.3. 内容介绍
- 文档内容,官网文档首页
- 暂未在goodtable中找到复合表头实现的样例,有样例或实现api留言评论唤醒笔者即可!
3.3. Vue vxe-table
一个基于 vue 的 PC 端表单/表格组件,支持增删改查、虚拟列表、虚拟树、懒加载、快捷菜单、数据校验、打印导出、表单渲染、数据分页、弹窗、自定义模板、渲染器、JSON 配置式为零代码而设计…
-
设计理念
- 面向现代浏览器,高效的简洁 API 设计
- 模块化表格、按需加载
- 为单行编辑表格而设计,支持增删改查及更多扩展,强大的功能的同时兼具性能
3.3.1 功能
- 基础表格
- 配置式表格
- 基础表单
- 配置式表单
- 斑马线条纹
- 多种边框
- 单元格样式
- 列宽拖动
- 最小/最大高度
- 自适应宽高
- 固定列
- 多级表头
- 表尾数据
- 高亮行或列
- 序号
- 单选框
- 复选框
- 下拉选项
- 开关
- 排序
- 多字段排序
- 筛选
- 合并单元格
- 合并表尾
- 导入/导出/打印
- 显示/隐藏列
- 加载中
- 格式化内容
- 自定义插槽 - 模板
- 快捷菜单
- 展开行
- 分页
- 工具栏
- 下拉容器
- 虚拟列表
- 虚拟树
- 增删改查
- 数据校验
- 数据代理
- 键盘导航
- 弹窗
- 渲染器
- 虚拟滚动
- 虚拟合并
- CSS 变量主题
- (pro) 单元格区域选取
- (pro) 单元格复制/粘贴
- (pro) 单元格查找和替换
3.3.2. 安装使用
npm install xe-utils vxe-table@next
3.3.3 git地址和官网地址
- git地址:x-extends/vxe-table: vxe-table vue 表单/表格解决方案 (github.com)
- 官网地址:vxe-table v4 (vxetable.cn)
3.3.4. 内容介绍
- 官网内容
- 复合表头的实现
<template>
<div>
<vxe-grid v-bind="gridOptions"></vxe-grid>
</div>
</template>
<script setup>
import { reactive } from 'vue'
const gridOptions = reactive({
border: true,
stripe: true,
height: 500,
columnConfig: {
resizable: true
},
columns: [
{ type: 'seq', width: 50 },
{
title: '基本信息',
children: [
{ field: 'name', title: 'Name' },
{
title: '其他信息',
children: [
{ field: 'nickname', title: 'Nickname' },
{ field: 'age', title: 'Age', sortable: true }
]
},
{ field: 'sex', title: 'Sex' }
]
},
{ field: 'address', title: 'Address', sortable: true, showOverflow: true }
],
data: [
{ id: 10001, name: 'Test1', nickname: 'T1', role: 'Develop', sex: 'Man', age: 28, address: 'Shenzhen' },
{ id: 10002, name: 'Test2', nickname: 'T2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
{ id: 10003, name: 'Test3', nickname: 'T3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
{ id: 10004, name: 'Test4', nickname: 'T4', role: 'Designer', sex: 'Women', age: 23, address: 'Shenzhen' },
{ id: 10005, name: 'Test5', nickname: 'T5', role: 'Develop', sex: 'Women', age: 30, address: 'Shanghai' },
{ id: 10006, name: 'Test6', nickname: 'T6', role: 'Designer', sex: 'Women', age: 21, address: 'Shenzhen' },
{ id: 10007, name: 'Test7', nickname: 'T7', role: 'Test', sex: 'Man', age: 29, address: 'Shenzhen' },
{ id: 10008, name: 'Test8', nickname: 'T8', role: 'Develop', sex: 'Man', age: 35, address: 'Shenzhen' }
]
})
</script>
3.4. Tabulator
Tabulator 是一个基于 JavaScript 的交互式数据表格库,它提供了丰富的功能和灵活性,可以用于在 Web 应用中展示和操作数据表格。Tabulator 允许你快速创建可排序、可筛选、可分页的表格,还支持自定义样式、模板、事件处理等。
一些 Tabulator 的特点和功能包括:
-
丰富的特性: Tabulator 提供了排序、筛选、分页、编辑、行选择、复制粘贴、拖放等一系列功能,使得数据表格更具交互性和可操作性。
-
自定义模板: 你可以自定义单元格内容的模板,以便在表格中显示自定义格式的数据。
-
可扩展的插件: Tabulator 允许你使用插件来扩展功能,如导出数据、打印表格等。
-
多种数据源: Tabulator 支持从本地数据、远程数据、Ajax 请求等多种数据源中获取数据。
-
适应不同设备: Tabulator 是响应式的,可以在不同的设备上展示适应性强的表格。
-
支持多种主题: Tabulator 提供多种内置主题,也支持自定义样式。
-
强大的 API: Tabulator 提供了丰富的 API,可以通过编程方式控制表格的行为和状态。
-
跨浏览器支持: Tabulator 支持各种现代浏览器,包括 Chrome、Firefox、Safari、Edge 等。
-
开源免费: Tabulator 是开源项目,可以免费使用和修改。
你可以访问官方网站和 GitHub 仓库以获取更多关于 Tabulator 的信息、文档和示例。
3.4.1. 安装使用
npm install tabulator-tables --save
3.4.2. git地址和官网地址
官方网站: http://tabulator.info/
GitHub 仓库: https://github.com/olifolkerd/tabulator