# 使用指南
agel-table 面向 Vue 2 + Element UI 2 项目。它将表格配置集中到一个对象中,并在 Element UI 表格上增加分页请求、操作列、列配置、合并、自适应高度和虚拟滚动能力。
# 环境要求
- Vue 2.x
- Element UI 2.x
请先在宿主项目中安装并注册 Element UI。agel-table 不会替应用加载 Element UI 样式。
npm install agel-table
# 注册组件
在应用入口全局注册一次即可。传入的第二个参数是所有表格共享的默认配置;页面级配置优先于默认值。
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import agelTable from 'agel-table'
Vue.use(ElementUI)
Vue.use(agelTable, {
table: {
border: true
},
page: {
height: 45,
pageSizes: [10, 20, 50, 100],
layout: 'total, sizes, prev, pager, next, jumper'
},
menu: {
width: 140
}
})
Vue.use(agelTable, options) 会注册 <agel-table>,无需再手动调用 Vue.component。全局选项只提供默认值;例如 page.enable 仍需在某个表格上显式开启。
# 创建本地数据表格
v-model 绑定一个响应式对象。表格属性、列定义和数据都放在这个对象中。
<template>
<agel-table v-model="table" />
</template>
<script>
export default {
data() {
return {
table: {
height: 320,
columns: [
{ prop: 'name', label: '姓名', minWidth: 120 },
{ prop: 'department', label: '部门', width: 160 }
],
data: [
{ name: '张三', department: '生产部' },
{ name: '李四', department: '安全部' }
]
}
}
}
}
</script>
table.data 变化时,表格会响应更新。需要直接调用 Element UI 的表格方法时,使用 table.getRef() 获取内部 el-table 实例。
# 接入服务端数据和分页
在 table.page.enable 开启分页,并用三参数形式定义 request(query, done, fail)。分页或服务端排序变化时,组件会用最新查询参数调用 request;调用 done 回填当前页数据和总数。
下面的示例用定时器模拟服务端响应:
<template>
<div>
<el-input v-model="table.query.keyword" placeholder="姓名" />
<el-button @click="search">查询</el-button>
<agel-table v-model="table" />
</div>
</template>
<script>
export default {
data() {
return {
table: {
height: 360,
query: { keyword: '' },
page: { enable: true, pageSize: 10 },
columns: [
{ prop: 'name', label: '姓名', sortable: 'custom' },
{ prop: 'department', label: '部门' }
],
request: (query, done, fail) => {
setTimeout(() => {
const allRows = Array.from({ length: 37 }, (_, index) => ({
name: '员工 ' + (index + 1),
department: index % 2 === 0 ? '生产部' : '安全部'
}))
const filteredRows = allRows.filter((row) => row.name.includes(query.keyword))
const sortedRows = query.orderColumn === 'name'
? filteredRows.slice().sort((left, right) => {
const result = left.name.localeCompare(right.name)
return query.order === 'descending' ? -result : result
})
: filteredRows
const start = (query.currentPage - 1) * query.pageSize
done({
data: sortedRows.slice(start, start + query.pageSize),
total: sortedRows.length
})
}, 200)
}
}
}
},
mounted() {
this.table.getData()
},
methods: {
search() {
this.table.getData({ currentPage: 1 })
}
}
}
</script>
默认查询字段为 currentPage、pageSize、orderColumn 和 order,可以通过 queryProps 映射到后端字段。分页组件负责展示页码和触发查询,不会在浏览器端自动切分完整数据;使用分页时,request 应返回当前页数据。
done 接收数组,或 { data, total }。失败时调用 fail(error);异步请求的拒绝也会结束 loading。table.getData() 仅在使用三参数请求代理时注入。请求协议和映射详情见 API 参考。
# 自定义单元格和表头
字符串形式的 slotColumn / slotHeader 对应 <agel-table> 上的具名作用域插槽:
<agel-table v-model="table">
<template slot="status" slot-scope="{ row }">
<el-tag :type="row.status === '正常' ? 'success' : 'warning'">
{{ row.status }}
</el-tag>
</template>
</agel-table>
columns: [
{ prop: 'status', label: '状态', slotColumn: 'status' }
]
也可以直接传入渲染函数:slotColumn(h, scope) 和 slotHeader(h, scope)。完整示例包含展开行、自定义插槽和 render 函数:
查看示例源码
<template>
<agel-table v-model="table">
<template v-slot:dateHeader>
<el-tag>模板自定义列-表头</el-tag>
</template>
<template v-slot:date="props">
<el-input v-model="props.row.date"></el-input>
</template>
<template v-slot:expand="props">
<div style="text-align:center">{{props.row.date}}=>template展开行内容</div>
</template>
<template v-slot:append>
<p slot="append" style="text-align:center">最后一行 slot append...</p>
</template>
</agel-table>
</template>
<script>
export default {
data() {
return {
table: {
border: true,
columns: [
{
label: "展开行",
type: "expand",
width: 80,
slotColumn: "expand",
},
{
minWidth: 200,
slotColumn: (h, { row }) => {
return <el-tag>{row.name}</el-tag>;
},
slotHeader: () => {
return <el-tag>render函数自定义列-表头</el-tag>;
},
},
{
minWidth: 200,
slotColumn: "date",
slotHeader: "dateHeader",
},
],
data: [
{ date: "2016-05-02", name: "王小虎", address: "上海市" },
{ date: "2016-05-04", name: "王小虎", address: "上海市" },
],
},
};
},
};
</script># 扩展能力示例
# 动态列显隐与嵌套表头
列支持 Element UI 的常用列属性,以及 display、children 等 agel-table 扩展项。display 可为布尔值或返回布尔值的函数。
# 操作列
设置 menu.enable 后,可以配置编辑、删除回调和自定义操作内容。菜单列默认追加到末尾,也可通过 insertIndex 指定插入位置。
查看请求代理与操作列示例源码
<template>
<div class="demo">
<p><code v-show="queryString">{{queryString}}</code></p>
<p>
<el-input v-model="table.query.name" style="width:100px;margin-right:10px;"></el-input>
<el-button icon="el-icon-search" @click="onSearch">查询</el-button>
</p>
<agel-table v-model="table"></agel-table>
</div>
</template>
<script>
export default {
data() {
return {
table: {
border: true,
data: [],
height:300,
// 该对象放置table 对象的查询参数,默认有 currentPage,pageSize,orderColumn,order
query: { name: "小虎" },
// 默认排序列
defaultSort: { prop: "date", order: "descending" },
// 分页组件在此配置,建议配置在全局,页面可省略
page: {
enable: true,
currentPage: 1,
pageSize: 5,
pageSizes: [5, 10, 15, 20],
},
// 菜单列配置
menu: {
enable: true,
fixed: "right",
onEdit: ({ row }) => {
this.$message.info("编辑", row.date);
},
onDel: ({ row }) => {
this.$message.info("删除", row.date);
},
},
// 表格列配置
columns: [
{ label: "日期", prop: "date", width: 200, sortable: "custom" },
{ label: "姓名", prop: "name", width: 200 },
{ label: "地址", prop: "address", minWidth: 300 },
],
// 接口函数
request: (query, done, err) => {
// query == this.table.query
this.getHttpData(query)
.then((res) => done({ data: res.data, total: res.total }))
.catch(err);
},
},
};
},
computed: {
queryString() {
return JSON.stringify(this.table.query);
},
},
// table.getData 只能在 mounted 生命周期之后调用
mounted() {
this.table.getData();
},
methods: {
onSearch() {
// 传递参数可 重置 分页 为 1
this.table.getData({ currentPage: 1 });
},
getHttpData(query) {
// 模拟一个 http 请求
return new Promise((reslove) => {
setTimeout(() => {
let data = [];
for (let i = 0; i < query.pageSize; i++) {
let index = (query.currentPage - 1) * query.pageSize + (i + 1);
data.push({
date: "2016-05-02",
name: "王小虎" + index,
address: "上海市" + index,
});
}
reslove({ data: data, total: 100 });
}, 1000);
});
},
},
};
</script># 合并单元格
merge.auto 会按相同字段值自动合并;也可以仅在指定列上设置 merge: true。横向合并使用 direction: 'horizontal'。
# 自适应高度
设置 resize.enable 后,表格会根据参照元素和底部偏移量计算可用高度。可将 relative 设为 CSS 选择器或 DOM 元素;省略时使用表格容器的 offsetParent。
# 虚拟滚动
将 virtual 配置为 { enable: true, rowHeight: 32 } 开启固定行高虚拟滚动。rowHeight 以像素为单位,必须与实际行布局保持一致。
支持固定列、序号列、选择列、客户端排序、数据替换、行定位和容器尺寸变化。虚拟模式下不支持树形/懒加载、表格筛选、展开行、单元格合并或可变行高;不要使用会改变行高的单元格内容或样式。
示例默认加载 1 万行,并提供 1 万和 10 万行快捷加载;输入框不设置固定行数上限。组件不会按 1000 行截断传入的 data,实际可加载规模取决于浏览器内存和数据对象大小。
查看示例源码
<template>
<div class="demo">
<el-row style="margin-bottom:10px; display:flex; flex-wrap:wrap; align-items:center; gap:8px">
<el-input-number v-model="number" :min="1" :step="100" placeholder="数据条数"></el-input-number>
<el-button @click="setData()">加载指定行数</el-button>
<el-button @click="setData(10000)">加载 1 万行</el-button>
<el-button @click="setData(100000)">加载 10 万行</el-button>
<el-input-number v-model="rowIndex" :min="1" :max="Math.max(table.data.length, 1)" placeholder="指定跳转行数"></el-input-number>
<el-button @click="jump">跳转到指定行数</el-button>
</el-row>
<agel-table v-model="table"></agel-table>
</div>
</template>
<script>
export default {
data() {
return {
number: 10000,
rowIndex: 100,
table: {
border: true,
height: 200,
virtual: { enable: true, rowHeight: 32 },
columns: [
{
type: "selection",
width: 60,
align: "center",
selectable: (row, index) => {
// console.log(index)
return index > 2;
},
},
{ label: "#", type: "index", width: 50, align: "center" },
{ label: "姓名", prop: "name", width: 200 },
{ label: "随机数", prop: "address", minWidth: 100, sortable: true },
],
data: [],
},
};
},
mounted() {
this.setData();
},
methods: {
setData(count = this.number) {
this.number = count
let data = [];
for (let i = 0; i < count; i++) {
data.push({
name: "王小虎" + (i + 1) + "号",
address: Math.random() * 100,
});
}
this.table.data = data;
},
jump() {
const row = this.table.data[this.rowIndex - 1]
if (row) this.table.virtualScrollToRow(row)
},
},
};
</script>
更多限制和滚动定位方法见 API 参考。