AG Grid 手册
# 版本升级
每次升级前先查阅 AG 官方的 Changelog,看有没有重大更新,以及废弃的 API。
访问这种格式的 URL https://ag-grid.com/changelog/?fixVersion=28.0.0
可以查看某个版本详细的更新说明(也可以在右上角下拉切换版本号)。
# 升级 v28
查阅 Release Notes 可以看到有一条重要的更新:
AG-6948 -
@ag-grid-community/all-modules
and@ag-grid-enterprise/all-modules
have been removed. If using@ag-grid-community/all-modules
you should switch to use Packages instead. If you want to use individual modules for a small package size, use Modules.
大意是从 v28 开始,不再支持 /all-modules
的用法,而且 @ag-grid-community/all-modules
的 npm 官方页面也显示“This package has been deprecated”。
因此,从 v28 开始,必须采用 AG 所谓的 Packages 写法。
可能涉及的改动如下:
修改
package.json
中的包名:"dependencies": { "ag-grid-community": "~28.1.1", "ag-grid-enterprise": "~28.1.1", "ag-grid-vue": "~28.1.1", },
复制代码修改
import
语句中的包名,同时,原先的 modules 写法需要弃用@ag-grid-enterprise
=>ag-grid-enterprise
@ag-grid-community
=>ag-grid-community
@ag-grid-community/vue
=>ag-grid-vue
// 修改 vue 包名 import { AgGridVue } from '@ag-grid-community/vue' // 改成 => import { AgGridVue } from 'ag-grid-vue' // 移除后面的 modules,直接从包名导入 import { AllModules } from '@ag-grid-enterprise/all-modules' // 改成 => import { AllModules } from 'ag-grid-enterprise' import { LicenseManager } from '@ag-grid-enterprise/core' // 同理,改成 => import { LicenseManager } from 'ag-grid-enterprise' import { ClientSideRowModelModule } from '@ag-grid-community/client-side-row-model' // 同理,改成 => import { ClientSideRowModelModule } from 'ag-grid-community'
复制代码
# 主题定制
自 v28 版本开始,AG 在主题中引入了 CSS 变量,实现快速修改默认的样式。
详细内容可以参考文档:
# 主题文件引入
主题的引入有多种方式,按推荐顺序进行介绍。
# 使用 @cndinfo/cube-design-web
组件库
如果有使用我们的 @cndinfo/cube-design-web
组件库,它已经内置了 ag 的 balham
主题,不需要重复引入。直接引入组件库即可:
import cubeDesignWeb from '@cndinfo/cube-design-web'
Vue.use(cubeDesignWeb)
复制代码
# CDN 方式引入
在项目的 index.html
中使用 CDN 链接引入:
<link rel="stylesheet" href="https://front-end-huawei-cdn.devops.cndinfo.com/npm/ag-grid-community@28.1.1/styles/ag-grid.min.css" />
<link rel="stylesheet" href="https://front-end-huawei-cdn.devops.cndinfo.com/npm/ag-grid-community@28.1.1/styles/ag-theme-balham.min.css" />
复制代码
这种方式可以保证 CSS 文件加载顺序早于 JS。
# main.js
中导入
在 main.js
开头导入 npm 包中的样式文件:
// main.js
import 'ag-grid-community/styles/ag-grid.css'
import 'ag-grid-community/styles/ag-theme-balham.css'
复制代码
这种方式可以也保证 CSS 的加载顺序早于 grid 组件。
# 在 Sass 文件中导入
在 Sass 中引用一共有三种方式:
- 引用 CDN 文件
@import 'https://front-end-huawei-cdn.devops.cndinfo.com/npm/ag-grid-community@28.1.1/styles/ag-grid.min.css';
@import 'https://front-end-huawei-cdn.devops.cndinfo.com/npm/ag-grid-community@28.1.1/styles/ag-theme-balham.min.css';
复制代码
- 引用本地 CSS 文件
@import '~ag-grid-community/styles/ag-grid.css';
@import '~ag-grid-community/styles/ag-theme-balham.css';
复制代码
- 引用本地 Sass 文件 如果倾向使用 Sass 的特性,也可以使用 Sass 的方式:Sass Styling API。
/* ag-grid.scss */
@use "~ag-grid-community/styles" as ag;
@include ag.grid-styles((
theme: alpine
));
复制代码
需要注意:包含上述代码的 .scss
文件必须在 main.js
开头导入。
如果不在开头导入,会导致 ag CSS 中和 grid 尺寸相关(例如 --ag-row-height
, --ag-header-height
)的变量无法生效。
原因是 ag 在渲染 grid 的过程中,针对尺寸相关会生成行内样式(inline style),行内样式优先级是最高的,无法被其他方式覆盖。
官方文档对此也有提醒:
Firstly, the grid will attempt to measure the size of an element. This works when styles have loaded, but will not work if the grid initialises before the theme loads.
# 修改样式
在对应的主题中对 CSS 变量进行重新赋值。
.ag-theme-balham {
--ag-data-color: red;
--ag-checkbox-border-radius: 4px;
--ag-header-height: 100px;
--ag-row-height: 40px;
--ag-list-item-height: 40px;
--ag-font-size: 22px;
}
复制代码
完整的变量清单参考: CSS Variable Reference
如果自定义的没有生效,可以按下面的步骤来排查:
- 多添加几个变量,看是否有任一变量生效,如果都没生效,可能是样式 CSS 主题文件没有引入成功,重新根据文档检查
- 部分变量生效,部分变量未生效:检查未生效变量定义的样式是否被通过
class
定义的样式覆盖了 - 尺寸相关的变量未生效:按上述文档排查主题样式文件的引用方式,是否早于 ag-grid 初始化
# 保存用户表头操作
本例文档根据引用 page-mixins.js
文件改造
# page-mixins.js
文件改造
export const GridPageMixin = {
data() {
return {
...
columnDefsItems: {} // 接口返回用户操作对象
}
},
methods: {
/**
* ag-grid api返回的平铺数据转换成同父级map(),考虑多行表头
* @param {*} a 数组数据
* @param {*} key 判断相同父级字段
*/
arrMap(a, key) {
var map = a.reduce((all, m) => {
let list = all.get(m[key])
if (!list) {
list = []
all.set(m[key], list)
}
list.push(m)
return all
}, new Map())
return map
}
},
/**
* 将原始表头数据columnDefs匹配接口返回的用户操作数据columnDefsItems(index: 顺序, hide: 隐藏, width: 宽度 , sort: 排序)
* @param {*} arr 原始表头数据columnDefs
* @param {*} ref 当前表头数组所属表头的ref值
* @param {*} parent arr为子级时,所属的父级元素
* @param {*} child 是否为子级
*/
setColumnDefs(arr, ref, parent, child = false) {
arr.filter((item, index) => {
item.index = child ? this.columnDefsItems[ref]?.[parent.field]?.children?.[item.field]?.index : this.columnDefsItems[ref]?.[item.field]?.index
item.hide = child ? this.columnDefsItems[ref]?.[parent.field]?.children?.[item.field]?.hide : this.columnDefsItems[ref]?.[item.field]?.hide || false
item.width = child ? this.columnDefsItems[ref]?.[parent.field]?.children?.[item.field]?.width : this.columnDefsItems[ref]?.[item.field]?.width || item.width
item.sort = child ? this.columnDefsItems[ref]?.[parent.field]?.children?.[item.field]?.sort : this.columnDefsItems[ref]?.[item.field]?.sort || item.sort
if (item.children) {
item.children = this.setColumnDefs(item.children, ref, item, true)
}
})
arr.sort((a, b) => a.index < b.index ? -1 : a.index > b.index ? 1 : 0)
return arr
},
/**
* 页面刷新获得该路由下用户保存的操作数据,并使用setColumnDefs api将重置后的数据渲染到表头
* @param {*} columnDefs 原始表头数据
* @param {*} ref 当前表头数组所属表头的ref值
*/
getParaminfoPageCode(columnDefs, ref) {
[api接口](this.$route.name).then(res => {
if (res?.data?.sParamValue) {
const data = JSON.parse(res.data.sParamValue)
this.columnDefsItems = data
columnDefs = this.setColumnDefs(columnDefs, ref)
}
this.$refs[ref]?.gridOptions.api.setColumnDefs(columnDefs)
})
},
/**
* 操作保存接口
* @param {*} data 保存数据, sPageCode:页面路由this.$route.name, sParamValue:用户操作数据
*/
getParaminfoSave(data) {
paraminfoSave(data)
},
/**
* 针对多个列表未使用initDefaultGrid()方法的列表,修改使用setDefaultColumnDefs()
* @param {*} ref 该列表的ref值
*/
setDefaultColumnDefs(ref) {
const gridOptions = {
// ag=grid 25版本由applyColumnDefOrder控制实现按顺序渲染,26版本后支持列表自动按顺序渲染
applyColumnDefOrder: true,
// 列表隐藏/显示触发的api
onColumnVisible: params => {
params.source === 'toolPanelUi' && this.setColumnDefsItems(params, this.columnDefsItems, ref)
},
// 列表拖拽触发的api
onDragStopped: params => {
this.setColumnDefsItems(params, this.columnDefsItems, ref)
},
// 列表排序触发的api
onSortChanged: params => {
this.setColumnDefsItems(params, this.columnDefsItems, ref)
},
// 开启列面板
sideBar: {
toolPanels: [{
id: 'columns',
domLayout: 'autoHeight',
labelDefault: 'Columns',
labelKey: 'columns',
iconKey: 'columns',
toolPanel: 'agColumnsToolPanel',
toolPanelParams: {
suppressRowGroups: true,
suppressValues: true,
suppressPivots: true,
suppressPivotMode: true,
suppressColumnFilter: true,
suppressColumnSelectAll: true,
suppressColumnExpandAll: true
}
}]
}
}
// 渲染原始表头数据columnDefs后,调用接口获得用户操作数据进行第二次渲染
this.$nextTick(() => {
ref && this.getParaminfoPageCode(this[ref].columnDefs, ref, false)
})
return gridOptions
},
initDefaultGrid(ops) {
...,
const ref = options.ref
// 如果存在ref,则调用接口进行匹配用户操作数据进行渲染
ref && this.getParaminfoPageCode(columnDefs, ref)
const gridOptions = {
// ag=grid 25版本由applyColumnDefOrder控制实现按顺序渲染,26版本后支持列表自动按顺序渲染
applyColumnDefOrder: true,
// 列表隐藏/显示触发的api
onColumnVisible: params => {
params.source === 'toolPanelUi' && this.setColumnDefsItems(params, this.columnDefsItems, ref)
},
// 列表拖拽触发的api
onDragStopped: params => {
this.setColumnDefsItems(params, this.columnDefsItems, ref)
},
// 列表排序触发的api
onSortChanged: params => {
this.setColumnDefsItems(params, this.columnDefsItems, ref)
},
sideBar: {
toolPanels: [{
id: 'columns',
domLayout: 'autoHeight',
labelDefault: 'Columns',
labelKey: 'columns',
iconKey: 'columns',
toolPanel: 'agColumnsToolPanel',
toolPanelParams: {
suppressRowGroups: true,
suppressValues: true,
suppressPivots: true,
suppressPivotMode: true,
suppressColumnFilter: true,
suppressColumnSelectAll: true,
suppressColumnExpandAll: true
}
}]
},
}
// 如果不存在ref,则使用原始表头数据进行渲染
!ref && (gridOptions.columnDefs = columnDefs)
...
}
}
复制代码
# 项目页面改造
# ag-grid-vue
新增 ref
属性
<ag-grid-vue
ref="ksGridOptions"
:suppress-copy-rows-to-clipboard="true"
class="ag-theme-balham grid-class border-none"
:row-drag-managed="true"
:grid-options="ksGridOptions"
:row-data="ksGridData"
:modules="aGGridAllModules"
/>
复制代码
# grid-options
对象新增 ref
属性
多列表重置后的表头数据可根据ref渲染到指定列表
- 页面表格使用
initDefaultGrid()
方法时
<ag-grid-vue
ref="ksGridOptions"
:suppress-copy-rows-to-clipboard="true"
class="ag-theme-balham grid-class border-none"
:row-drag-managed="true"
:grid-options="ksGridOptions"
:row-data="ksGridData"
:modules="aGGridAllModules"
/>
export default {
data() {
return {
khGridOptions: {
ref: 'ksGridOptions', // 传入对应的列表ref值
...
}
}
}
}
复制代码
- 页面表格未使用
initDefaultGrid()
时
<ag-grid-vue
ref="ksGridOptions"
:suppress-copy-rows-to-clipboard="true"
class="ag-theme-balham grid-class border-none"
:row-drag-managed="true"
:grid-options="ksGridOptions"
:row-data="ksGridData"
:modules="aGGridAllModules"
/>
export default {
data() {
return {
ksGridOptions: {
...
...this.setDefaultColumnDefs('ksGridOptions') // 引入混入方法setDefaultColumnDefs(),并传入列表ref值
}
}
}
}
复制代码
# suppressColumnsToolPanel
属性配置指定表头不出现在列面板上
const gridOptions = {
ref: 'gridOptions',
columnDefs: [
{
field: 'checkout',
headerName: '',
minWidth: 40,
suppressColumnsToolPanel: true,
maxWidth: 40,
checkboxSelection: true,
headerCheckboxSelection: true,
'pinned': 'left'
}
]
}
复制代码
# field
属性不可为空
一级表头,多级表头都不可为空,同一级表头
field
不可重复
// false
// 表头父级 field 为空
const gridOptions = {
ref: 'gridOptions',
columnDefs: [
{
field: '',
headerName: '调拨日期',
marryChildren: true,
children: [
{
headerName: '',
field: 'sAllotDate'
}
]
}
]
}
// false
// 表头子级 field 为空
const gridOptions = {
ref: 'gridOptions',
columnDefs: [
{
field: 'sAllotDate',
headerName: '调拨日期',
marryChildren: true,
children: [
{
headerName: '',
field: ''
}
]
}
]
}
// false
// 同级 field 重复
const gridOptions = {
ref: 'gridOptions',
columnDefs: [
{
field: 'sAllotDate',
headerName: '调拨日期',
marryChildren: true,
children: [
{
headerName: '',
field: ''
}
]
},
{
field: 'sAllotDate',
headerName: '送达日期',
marryChildren: true,
children: [
{
headerName: '',
field: ''
}
]
}
]
}
// false
// 同级 field 重复
const gridOptions = {
ref: 'gridOptions',
columnDefs: [
{
field: 'sAllotDate',
headerName: '调拨日期',
marryChildren: true,
children: [
{
headerName: '仓库',
field: 'vWarehouseInName'
},
{
headerName: '公司',
field: 'vWarehouseInName'
}
]
}
]
}
// true
const gridOptions = {
ref: 'gridOptions',
columnDefs: [
{
field: 'sAllotDate',
headerName: '调拨日期',
marryChildren: true,
children: [
{
headerName: '',
field: 'sAllotDate'
}
]
}
]
}
// true
const gridOptions = {
ref: 'gridOptions',
columnDefs: [
{
field: 'sAllotDate',
headerName: '调拨日期',
marryChildren: true,
children: [
{
headerName: '公司',
field: 'vCompanyInName'
},
{
headerName: '仓库',
field: 'vWarehouseInName'
}
]
}
]
}
复制代码
# 多级表头,父级新增 marryChildren
属性控制子级表头禁止移除父级
const gridOptions = {
ref: 'gridOptions',
columnDefs: [
{
field: 'sAllotDate',
headerName: '调拨日期',
marryChildren: true,
children: [
{
headerName: '',
field: 'sAllotDate'
}
]
},
{
headerName: '移出',
field: 'vWarehouseName',
marryChildren: true,
children: [
{
field: 'vWarehouseName',
headerName: '仓库'
},
{
field: 'sExpectStockDate',
headerName: '预计出仓日期'
}
]
}
]
}
复制代码