ag-Grid在Vue2项目下使用的简单总结

前言:作为一个刚入行没多久的菜鸟前端,之前一直使用的是ElementUI和iView提供的表格,但是某些场景下这两个框架提供的表格组件并不能很好的满足需求(当然,也可能是本人能力有限)。而ag-grid给我的感觉是相当惊喜的,上手了一周多的时间,用到的功能也只有冰山一角,但是已经能体会到这个组件的强大了,印证了官网的标语(The Best JavaScript Grid in the World)。这篇文章旨在记录分享下自己的使用过程,也希望能给刚接触这个组件的朋友一些参考。


引入

1.使用组件的第一步当然是引入啦

<!-- npm版 -->
npm install ag-grid-community ag-grid-vue --save-dev
<!--如果引入后运行项目报错,可以按照报错提示安装对应依赖,我个人是下面两个都需要安装-->
npm install --save vue-property-decorator 
npm install --save vue-class-component

<!-- yarn版 -->
yarn add ag-grid-community ag-grid-vue -D

yarn add vue-property-decorator 
yarn add vue-class-component

2.引入样式文件,放在main.js中全局引入

import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-balham.css";

3.关于自定义主题样式,水平有限暂时没有弄明白官方的用法(等我弄明白了就来把这块补上),目前是引入CSS文件,使用类名覆盖

<!--main.js中引入自己新建的css文件-->
import "@assets/scss/ag-grid.scss";

使用

1.简单demo

<template>
    <ag-grid-vue
        style="height:500px;width:100%"
        class="ag-theme-balham"
        :columnDefs="columnDefs"
        :rowData="rowData"
        :gridOptions="gridOptions"
        @grid-ready="onGridReady"
      ></ag-grid-vue>
      <!--ag-theme-balham这个类名是组件提供的默认主题-->
</template>
<script>
    export default {
        data(){
            gridApi: {}, //表格方法
            columnApi: {}, //列方法
            gridOptions: {}, //ag-grid配置项
            rowData:[],//表格中填充的数据
            columnDefs:[//列配置,更多配置可以查询官网
                {
                    headerName: "类型",
                    field: "type",
                    width: 160
                },
                {
                    headerName: "开始时间",
                    field: "beginTime",
                    width: 240
                },
                {
                    headerName: "渠道",
                    field: "channelName",
                    width: 200
                }
            ]
        },
        beforeMount(){
            this.gridOptions = {
                  //表格配置项
                  rowHeight: 40,
                  headerHeight: 40,
                };
        },
        method:{
            /**
             * @description: 表格准备就绪 挂载属性及api
             * @param {Object} params - 表格实例
             * @return {*}
             */
            onGridReady(params) {
              this.gridApi = params.api;
              this.columnApi = params.columnApi;
              // 这时就可以通过gridApi调用ag-grid的传统方法了
              this.gridApi.sizeColumnsToFit();
              
              <!-- 可以将params打印出来会让你对表格有个更直观的理解 -->
            },
        }
    }
</script>

2.布局尺寸

ag-grid支持直接使用样式定义尺寸,也支持自动高度,需要注意的是自动高度下不支持设置最大高度,更多的布局方式请移步文档

<!--如果是初始化就设为自动高度,可以直接通过配置项设置-->
beforeMount(){
    this.gridOptions = {
          //表格配置项
          domLayout:'autoHeight'
        };
},
<!--如果是页面交互需要在特定场景下自动高度,可以通过提供的api来设置-->
this.gridApi.setDomLayout("autoHeight")

3.缩放

窗口尺寸变化后需要调用sizeColumnsToFit这个方法让表格调整大小,建议使用mixin混入公共代码或者将表格封装为组件,省的每次在使用表格时都要写一遍

window.addEventListener("resize",()=>{
    this.gridOptions.api.sizeColumnsToFit()
})

4.自定义表格内容

单纯的文字过滤可以使用valueGetter这个属性,这里就不多介绍了。而很多时候表格不单单只是单纯的字段展示,也会有一些点击交互之类的,所以我们需要去定义我们想要的内容,ag-grid提供了cellRenderer以及cellRendererFrameWork两个属性,我用的是后者,以下代码基于最开始的简单demo,demo中无关代码已省略

<script>
    import Vue from "vue" //这里需要引入Vue
    let renderType = Vue.extend({ //创建一个新的实例作为组件使用
        <!--在这个组件中可以直接使用params这个变量-->
        <!--params为ag-grid封装好的节点对象,里面包含有相关信息-->
        template:`<div @click="sayHello">{{params.data.type}}</div>`
        methods:{
            sayHello(){
                console.log(this.params)//打印出来你就知道是啥了
                
                this.params.context.componentParent.sayHi()//调用父组件中的方法
                //this.params.context.componentParent指向的就是父组件
            }
        }
    })
    export default {
        data(){
            columnDefs:[//列配置,更多配置可以查询官网
                {
                    headerName: "类型",
                    field: "type",
                    width: 160,
                    cellRendererFrameWork:renderType //!!声明使用的组件!!
                },
                {
                    headerName: "开始时间",
                    field: "beginTime",
                    width: 240
                },
                {
                    headerName: "渠道",
                    field: "channelName",
                    width: 200
                }
            ]
        },
        beforeMount(){
            this.gridOptions = {
                context: { componentParent: this },//通过这个属性建立了上下文引用
                //说人话就是可以在自己声明的组件里调用到父组件的方法和属性了
                    
            }
        }
        methods:{
            sayHi(){
                console.log('我是父组件里的方法')
            }
        }
        
    }
</script>

5.tooltip提示

依然基于demo,省去无关代码

<template>
    <ag-grid-vue
        style="height:500px;width:100%"
        class="ag-theme-balham"
        :columnDefs="columnDefs"
        :rowData="rowData"
        :gridOptions="gridOptions"
        @grid-ready="onGridReady"
        :tooltipShowDelay="500" //tooltip延迟时间 单位ms
        :frameworkComponents="frameworkComponents" //声明表格要用到的组件
     ></ag-grid-vue>
</template>
<script>
    let tooltipValueGetter = function(params) {
      return { value: params.value };//params为节点信息
    };
    export default{
        components:{
            renderTooltip: {
              template: `<div :style="{display:params.value.value?'block':'none',color:'#333'}" class="ag-tooltip">{{params.value.value}}</div>`
            }
        },
        data(){
            return{
                columnDefs:[//列配置,更多配置可以查询官网
                    {
                        headerName: "类型",
                        field: "type",
                        width: 160,
                        tooltipComponent: "renderTooltip", //声明使用的组件
                        tooltipValueGetter: tooltipValueGetter //声明tooltip中使用的字段
                    },
                    {
                        headerName: "开始时间",
                        field: "beginTime",
                        width: 240
                    },
                    {
                        headerName: "渠道",
                        field: "channelName",
                        width: 200
                    }
                ],
                frameworkComponents:{},
            }
        },
        beforeMount(){
            this.frameworkComponents = { renderTooltip: "renderTooltip" }; //声明使用到的组件,组件本身需要写在components中
        }
    }
</script>

关于frameworkComponents我的理解是先从components中收集好需要的组件,然后提供给每一列去自由选择在这里插入图片描述

6.实现类似element表格固定列的阴影效果

当内容过长且单侧或两侧固定时,表格会提供滚动条,但是ag-grid并没有提供类似element表格的交互效果,只是在固定列(左/右)侧提供了两条实线作为边界,所以我根据element表格的阴影效果逻辑,简单粗暴的通过dom对ag-grid进行了一点改动。下图为element表格的效果。
在这里插入图片描述

当有固定列时,ag-grid会将其他列放入一个容器,对比容器宽度和计算其他列的总宽度,就可以知道当前容器内是否出现滚动条,再通过监听容器的scroll事件去判断当前的滚动情况从而控制阴影的显示。

温馨提示:觉得下面代码太长不想看的可以根据tip中的内容对代码进行改动后直接复制粘贴

tip:以下代码为单页面多个表格的情况,所以代码中表格的columnDefs属性绑定的值是一个二维数组并且使用querySelectorAll选择器。如果页面上只有一个表格,将columnDefs属性绑定的值改为一维数组,然后使用querySelector,最后将下面代码中的‘[i]’全部删除即可。tableResize方法请放在window的resize事件中执行。

<template>
    <ag-grid-vue
        style="height:500px;width:100%"
        class="ag-theme-balham"
        :columnDefs="columnDefs[0]" //二维数组
        :rowData="rowData"
        :gridOptions="gridOptions"
        @grid-ready="onGridReady"
      ></ag-grid-vue>
</template>


tableResize() {
      
      let wrap = document.querySelectorAll(".ag-center-cols-viewport");//容器
      let left = document.querySelectorAll(".ag-pinned-left-cols-container");//左侧固定列节点
      let right = document.querySelectorAll(".ag-pinned-right-cols-container");//右侧固定列节点
      let leftHeader = document.querySelectorAll(".ag-pinned-left-header");//左侧固定列表头节点
      let rightHeader = document.querySelectorAll(".ag-pinned-right-header");//右侧固定列表头节点
      if (
        wrap &&
        left &&
        right &&
        leftHeader &&
        rightHeader 
      ) {
        /*
        动态设置中间可滚动区的阴影效果
      */
        wrap.forEach((n, i) => {
          if (Array.isArray(this.columnDefs[i])) {
            let containerWidth = 0;
            this.columnDefs[i].forEach(item => { //计算出非固定列的宽度总和
              if (!item.pinned) { //固定列会有pinned这个属性
                if (item.width) {
                  containerWidth += item.width;
                } else if (item.minWidth) {
                  containerWidth += item.minWidth;
                }
              }
            });
            
            let handleFunction = () => {
              if (wrap[i].offsetWidth >= containerWidth) {
                left[i].style.boxShadow = "none";
                right[i].style.boxShadow = "none";
                leftHeader[i].style.boxShadow = "none";
                rightHeader[i].style.boxShadow = "none";
              } else {
                if (wrap[i].scrollLeft == 0) {
                  right[i].style.boxShadow = "-3px 0px 4px 0px #bbbbbb";
                  rightHeader[i].style.boxShadow = "-3px 0px 4px 0px #bbbbbb";
                  right[i].style.zIndex = "10";
                  left[i].style.boxShadow = "none";
                  leftHeader[i].style.boxShadow = "none";
                } else if (
                  wrap[i].scrollLeft > 0 &&
                  wrap[i].scrollLeft < containerWidth - wrap[i].offsetWidth
                ) {
                  right[i].style.boxShadow = "-3px 0px 4px 0px #bbbbbb";
                  rightHeader[i].style.boxShadow = "-3px 0px 4px 0px #bbbbbb";
                  right[i].style.zIndex = "10";
                  left[i].style.boxShadow = "3px 0px 4px 0px #bbbbbb";
                  leftHeader[i].style.boxShadow = "3px 0px 4px 0px #bbbbbb";
                  left[i].style.zIndex = "10";
                } else if (
                  wrap[i].scrollLeft ==
                  containerWidth - wrap[i].offsetWidth
                ) {
                  left[i].style.boxShadow = "3px 0px 4px 0px #bbbbbb";
                  leftHeader[i].style.boxShadow = "3px 0px 4px 0px #bbbbbb";
                  left[i].style.zIndex = "10";
                  right[i].style.boxShadow = "none";
                  rightHeader[i].style.boxShadow = "none";
                }
              }
            };
            handleFunction(); //窗口尺寸变化
            wrap[i].onscroll = () => {
              handleFunction();
            };
          }
        });
      }
    }

总结

以上就是我一周以来上手ag-grid的一些拙见,通过这个表格的使用也促进了我对vue的理解,个人感觉是收获颇丰,这种获得知识的满足感大概就是学习的快乐吧。码字不易,如果觉得有帮助的可以点个赞,以上内容有错误或者不足的也欢迎各位指出,共同进步。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值