vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vxe-table 提供了强大的数据代理(Proxy)能力,只需配置好数据源和表单项,即可自动完成数据加载、分页、查询、重置等操作,从每个页面重复编写冗余代码中解放出来。本文将介绍如何通过 proxyConfig 配置 Ajax 查询接口、分页以及表单代理,并给出完整示例与注意事项。
功能概述
- 自动加载数据:通过 proxyConfig.ajax.query 配置查询接口,表格自动请求并渲染数据。
- 分页查询:只需添加 pagerConfig,接口返回分页信息,即可实现分页。
- 表单查询:通过 formConfig.items 配置查询表单,并启用 proxyConfig.form,即可自动收集表单条件并提交查询。
- 提交模式:默认提交为 reload 重新加载,可改为 query 只查询不清除条件。
- 默认值:通过 itemRender.defaultValue 为表单项设置默认值。
核心配置
配置查询接口
proxyConfig: {
ajax: {
query: ({ page, form }) => {
// page: 分页信息,form: 表单数据
return findPageList(page.pageSize, page.currentPage, form)
}
}
}
- query 函数接收一个对象,包含 page(分页参数)和 form(表单查询条件)。
- 返回 Promise,解析结果需包含 result(数据列表)和 page.total(总条数,分页时需要)。
启用分页
pagerConfig: {} // 开启分页,可配置 pageSize、pageSizes 等
- 分页查询与列表查询配置基本一致,区别在于:
- 需要添加 pagerConfig。
- 接口响应结果需包含分页信息,如 { result: [], page: { total: 100 } }
配置查询表单
formConfig: {
items: [
{ field: 'name', title: '名称', span: 8, itemRender: { name: 'VxeInput' } },
// ...
]
}
- items 数组定义表单项,field 对应查询字段,title 为标签,span 控制栅格宽度。
- itemRender 指定渲染组件,如 VxeInput、VxeSelect、VxeDatePicker 等。
- changeToSubmit: true 表示值改变后自动提交查询。
启用表单代理
proxyConfig: {
form: true, // 启用表单代理
formOptions: {
// submitMode: 'query' // 可选,默认 'reload'
}
}
- form: true 后,表单提交会自动触发 ajax.query。
- formOptions.submitMode:
- 'reload'(默认):提交后重新加载数据,并重置到第一页。
- 'query':只查询,不清除条件,不重置分页。
设置默认值
{ field: 'name', title: '名称', itemRender: { name: 'VxeInput', defaultValue: '默认值' } }
代码

<template>
<div>
<vxe-grid v-bind="gridOptions"></vxe-grid>
</div>
</template>
<script setup>
import { reactive } from 'vue'
const list = [
{ id: 10001, name: 'Test1', nickname: 'T1', role: 'Develop', sex: 'Man', age: 28, date: '', address: 'Shenzhen', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 10002, name: 'Test2', nickname: 'T2', role: 'Test', sex: 'Women', age: 22, date: '', address: 'Guangzhou', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 10003, name: 'Test3', nickname: 'T3', role: 'PM', sex: 'Man', age: 32, date: '', address: 'Shanghai', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 10004, name: 'Test4', nickname: 'T4', role: 'Designer', sex: 'Women', age: 23, date: '', address: 'test abc', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 10005, name: 'Test5', nickname: 'T5', role: 'Develop', sex: 'Women', age: 30, date: '', address: 'Shanghai', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 10006, name: 'Test6', nickname: 'T6', role: 'Designer', sex: 'Women', age: 21, date: '', address: 'Shenzhen', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 10007, name: 'Test7', nickname: 'T7', role: 'Test', sex: 'Man', age: 29, date: '', address: 'Shenzhen', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 10008, name: 'Test8', nickname: 'T8', role: 'Develop', sex: 'Man', age: 35, date: '', address: 'test abc', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 10009, name: 'Test9', nickname: 'T9', role: 'Develop', sex: 'Man', age: 35, date: '', address: 'Shenzhen', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100010, name: 'Test10', nickname: 'T10', role: 'Develop', sex: 'Man', age: 35, date: '', address: 'Guangzhou', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100011, name: 'Test11', nickname: 'T11', role: 'Develop', sex: 'Man', age: 49, date: '', address: 'Guangzhou', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100012, name: 'Test12', nickname: 'T12', role: 'Develop', sex: 'Women', age: 45, date: '', address: 'Shanghai', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100013, name: 'Test13', nickname: 'T13', role: 'Test', sex: 'Women', age: 35, date: '', address: 'Guangzhou', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100014, name: 'Test14', nickname: 'T14', role: 'Test', sex: 'Man', age: 29, date: '', address: 'Shanghai', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100015, name: 'Test15', nickname: 'T15', role: 'Develop', sex: 'Man', age: 39, date: '', address: 'Guangzhou', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100016, name: 'Test16', nickname: 'T16', role: 'Test', sex: 'Women', age: 35, date: '', address: 'Guangzhou', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100017, name: 'Test17', nickname: 'T17', role: 'Test', sex: 'Man', age: 39, date: '', address: 'Shanghai', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100018, name: 'Test18', nickname: 'T18', role: 'Develop', sex: 'Man', age: 44, date: '', address: 'Guangzhou', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100019, name: 'Test19', nickname: 'T19', role: 'Develop', sex: 'Man', age: 39, date: '', address: 'Guangzhou', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100020, name: 'Test20', nickname: 'T20', role: 'Test', sex: 'Women', age: 35, date: '', address: 'Guangzhou', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100021, name: 'Test21', nickname: 'T21', role: 'Test', sex: 'Man', age: 39, date: '', address: 'Shanghai', startDate: '2025-01-01', endDate: '2025-02-10' },
{ id: 100022, name: 'Test22', nickname: 'T22', role: 'Develop', sex: 'Man', age: 44, date: '', address: 'Guangzhou', startDate: '2025-01-01', endDate: '2025-02-10' }
]
// 模拟接口
const findPageList = (pageSize, currentPage, queryObj) => {
console.log(`调用查询接口 pageSize=${pageSize} currentPage=${currentPage}`, queryObj)
return new Promise((resolve) => {
setTimeout(() => {
resolve({
result: list.slice((currentPage - 1) * pageSize, currentPage * pageSize),
page: {
total: list.length
}
})
}, 100)
})
}
const gridOptions = reactive({
border: true,
height: 500,
pagerConfig: {},
formConfig: {
items: [
{ field: 'name', title: '名称', span: 8, itemRender: { name: 'VxeInput' } },
{
field: 'sex',
title: '性别',
span: 8,
itemRender: {
name: 'VxeSelect',
options: [
{ label: '女', value: 'Women' },
{ label: '男', value: 'Man' }
],
changeToSubmit: true
}
},
{ field: 'date', title: '日期', span: 8, itemRender: { name: 'VxeDatePicker', changeToSubmit: true } },
{ field: '_startAndEnd', title: '日期范围', span: 16, itemRender: { name: 'VxeDateRangePicker', changeToSubmit: true, startField: 'startDate', endField: 'endDate' } },
{
span: 24,
align: 'center',
itemRender: {
name: 'VxeButtonGroup',
options: [
{ type: 'submit', content: '搜索', status: 'primary' },
{ type: 'reset', content: '重置' }
]
}
}
]
},
proxyConfig: {
// 启用表单代理
form: true,
// formOptions: {
// // 代理表单提交模式,支持 reload 和 query,默认 reload,点击搜索时,默认自动清除条件;如果 query 则不清除
// submitMode: 'query'
// },
ajax: {
query: ({ page, form }) => {
return findPageList(page.pageSize, page.currentPage, form)
}
}
},
columns: [
{ type: 'seq', width: 70 },
{ field: 'name', title: 'Name' },
{ field: 'nickname', title: 'Nickname' },
{ field: 'role', title: 'Role', sortable: true },
{ field: 'sex', title: 'Sex', sortable: true },
{ field: 'date', title: 'Date' },
{ field: 'address', title: 'Address' }
]
})
</script>
相关说明
模拟分页接口
const findPageList = (pageSize, currentPage, queryObj) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
result: list.slice((currentPage - 1) * pageSize, currentPage * pageSize),
page: { total: list.length }
})
}, 100)
})
}
- 接收 pageSize、currentPage 和查询条件 queryObj。
- 返回 { result, page: { total } },其中 result 为当前页数据,page.total 为总条数。
- 实际项目中替换为真实 Ajax 请求即可。
分页查询与列表查询的区别
- 列表查询:只需 proxyConfig.ajax.query,返回 { result: [] } 即可。
- 分页查询:额外配置 pagerConfig,且接口返回需包含 page.total。
通过 proxyConfig 配置 Ajax 查询与表单代理,可以极大地简化表格数据加载与查询逻辑,减少重复代码。无论是简单的列表查询还是分页查询,只需少量配置即可完成,是 vxe-table 提升开发效率的重要特性。

浙公网安备 33010602011771号