美文网首页
vue☞SlickGrid小试牛刀

vue☞SlickGrid小试牛刀

作者: 小学生的博客 | 来源:发表于2018-09-12 14:27 被阅读396次

场景:项目中需要加载上万条表格数据,服务端查询耗时几分钟,再加上浏览器渲染几分钟,对于一般配置的电脑来说完全扛不住,不是崩溃就是卡死。
表格使用的是elementUI 的table组件,对于一般需求还是没什么大问题的,但是这次不行。

解决方案:
①分页,分批次加载,(首先得服务端支持分页,另外得根据实际项目需求。都不满足,PASS)
②伪分页,监听table的滚动,滚动到底部在进行加载渲染。(数据是一次获取的,el-table监听比较麻烦,伪分页意义不大,PASS)
③在查询issue时,发现有个道友说道,希望elementUI团队引入slickGrid设计原理,来处理大数据渲染卡顿问题。

发现新大陆, SlickGrid
(请认准 6pac 是这哥们的https://github.com/6pac/SlickGrid

测试上万条数据渲染速率,还可以


上万条数据飕飕的

如何在vue项目中使用slickgrid???
以下进入正题,项目下载下来,example中例子挺多,基本可以满足需求。那就引入项目用用

如何在自己的vue项目中运行,首先必须先引入jquery,因为他的好多方法都依赖jquery。如何引入?网上一大堆教程可以参考。

  • cnpm install jquery --save
  • webpack.base,conf,js中修改如下:
 resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
      'jquery': path.resolve(__dirname, '../node_modules/jquery/src/jquery')   // 增加这一行
    }
  },
  • main.js 中添加
import 'jquery'

ok 引入成功

如何使用slick,引入js就行了,
demo.vue中添加

<template>
  <div class="dc-collectquery">
    <el-button @click="search"  size="mini"><i class="el-icon-search"></i>查询</el-button>
    <div style="width:100%;">
      <div id="myGrid" style="width:100%;height:500px;"></div>
    </div>
  </div>
</template>

<script>
  import '../assets/slick/jquery-3.1.0'
  import '../assets/slick/jquery-ui-1.9.2'
  import '../assets/slick/jquery.event.drag-2.3.0.js'
  import '../assets/slick/slick.core.js'
  import '../assets/slick/slick.dataview.js'
  import '../assets/slick/slick.grid.js'
  import Mock from 'mockjs'

  export default {
    name: "demo",
    data() {
      return {
      }
    },
    methods: {
      // 查询数据
      search() {
        this.handleTable()
      },
      // 处理表数据
      handleTable() {
        var grid;
        var data = [];
        var options = {
          enableCellNavigation: true,
          enableColumnReorder: false
        };
        var columns = [
          {id: "index", name: "序号", field: "index"},
          {id: "bizCode", name: "编号", field: "bizCode"},
          {id: "bizName", name: "名称", field: "bizName" ,width:260},
        ];

        // 引入mock 创建伪数据
        var Random = Mock.Random
        let list = Mock.mock({
          'data|20-50': [
            {
              'bizCode|+1': Random.integer(1000000, 9999999),
              bizName: Random.city(),
            },{
              'bizCode|+1': Random.integer(1000000, 9999999),
              bizName: Random.city(),
            },{
              'bizCode|+1': Random.integer(1000000, 9999999),
              bizName: Random.city(),
            },
          ]
        })

        data = list.data
        data.forEach((item, index) => {
          item.index = index + 1
          item.id = item.bizCode
        })

        grid = new Slick.Grid("#myGrid", data, columns, options);
      },

    }
  }
</script>

<style lang="less">
  @import "../assets/slick/jquery-ui-1.11.3.custom.css";
  @import "../assets/slick/slick.grid.css";
  @import "../assets/slick/examples.css";

  .slick-preheader-panel {
    .ui-state-default {
      width: 100%;
      overflow: hidden;
      border-left: 0px !important;
      border-bottom: 0px !important;
    }
  }
  .slick-header-columns {
    border-bottom: 0px !important;
    text-align: center;    // 实现标题居中
  }
</style>
demo效果图
需求一:合并单元格,标题居中

修改如下

   // 处理表数据
      handleTable() {
        var dataView;
        var grid;
        var data = [];
        var options = {
          enableCellNavigation: true,
          enableColumnReorder: false,
          createPreHeaderPanel: true,
          showPreHeaderPanel: true,
          preHeaderPanelHeight: 23,
          explicitInitialization: true
        };
        var columns = [
          {id: "index", name: "序号", field: "index"},
          {id: "bizCode", name: "编号", field: "bizCode"},
          {id: "bizName", name: "名称", field: "bizName" ,width:260},
          {id: 'beginQty', field: 'beginQty', name: '数量', columnGroup: "库存"},
          {id: 'beginUnTaxAmount', field: 'beginUnTaxAmount', name: '无税金额', columnGroup: "库存"},
          {id: 'beginTaxAmount', field: 'beginTaxAmount', name: '含税金额', columnGroup: "库存"},
        ];

        var Random = Mock.Random

        let list = Mock.mock({
          'data|20-50': [
            {
              'bizCode|+1': Random.integer(1000000, 9999999),
              bizName: Random.city(),
              beginQty: Random.integer(5, 10),
              beginUnTaxAmount: Random.float(1000, 9999).toFixed(2),
              beginTaxAmount: Random.float(1000, 9999).toFixed(2),
            },{
              'bizCode|+1': Random.integer(1000000, 9999999),
              bizName: Random.city(),
              beginQty: Random.integer(5, 10),
              beginUnTaxAmount: Random.float(1000, 9999).toFixed(2),
              beginTaxAmount: Random.float(1000, 9999).toFixed(2),
            },{
              'bizCode|+1': Random.integer(1000000, 9999999),
              bizName: Random.city(),
              beginQty: Random.integer(5, 10),
              beginUnTaxAmount: Random.float(1000, 9999).toFixed(2),
              beginTaxAmount: Random.float(1000, 9999).toFixed(2),
            },
          ]
        })

        data = list.data
        data.forEach((item, index) => {
          item.index = index + 1
          item.id = item.bizCode
        })

        function CreateAddlHeaderRow() {
          var $preHeaderPanel = $(grid.getPreHeaderPanel())
            .empty()
            .addClass("slick-header-columns")
            .css('left', '-1000px')
            .width(grid.getHeadersWidth());
          $preHeaderPanel.parent().addClass("slick-header");

          var headerColumnWidthDiff = grid.getHeaderColumnWidthDiff();
          var m, header, lastColumnGroup = '', widthTotal = 0;

          for (var i = 0; i < columns.length; i++) {
            m = columns[i];
            if (lastColumnGroup === m.columnGroup && i > 0) {
              widthTotal += m.width;
              header.width(widthTotal - headerColumnWidthDiff)
            } else {
              widthTotal = m.width;
              header = $("<div class='ui-state-default slick-header-column' />")
                .html("<span class='slick-column-name'>" + (m.columnGroup || '') + "</span>")
                .width(m.width - headerColumnWidthDiff)
                .appendTo($preHeaderPanel);
            }
            lastColumnGroup = m.columnGroup;
          }
        }

        dataView = new Slick.Data.DataView();

        grid = new Slick.Grid("#myGrid", dataView, columns, options);

        dataView.onRowCountChanged.subscribe(function (e, args) {
          grid.updateRowCount();
          grid.render();
        });

        dataView.onRowsChanged.subscribe(function (e, args) {
          grid.invalidateRows(args.rows);
          grid.render();
        });

        grid.init();

        grid.onColumnsResized.subscribe(function (e, args) {
          CreateAddlHeaderRow();
        });
        CreateAddlHeaderRow();
        // Initialise data
        dataView.beginUpdate();
        dataView.setItems(data);
        dataView.endUpdate();
      },
     ......
  // 这个可以控制  合并的单元格居中,或者是下面的标题都居中
  .slick-preheader-panel {       // 注掉这行 实现单元格居中
    .slick-header-columns {
      border-bottom: 0px !important;
      text-align: center;
    }
  }
效果图
需求二:添加合计,修改合计样式
......
        function CreateAddlHeaderRow() {
           .....
        }
        //------------------------添加如下-----------------------
        function TotalsDataProvider(data, columns) {
          var totals = {};
          var totalsMetadata = {
            // Style the totals row differently.
            cssClasses: "totals",
            columns: {}
          };

          // Make the totals not editable.
          for (var i = 0; i < columns.length; i++) {
            totalsMetadata.columns[i] = {editor: null};
          }

          this.getLength = function () {
            return data.length + 1;
          };

          this.getItem = function (index) {
            return (index < data.length) ? data[index] : totals;
          };

          this.updateTotals = function () {
            let self = this

            var columnIdx = columns.length;
            while (columnIdx--) {
              var columnId = columns[columnIdx].id;
              var total = 0;
              var i = data.length;
              while (i--) {
                total += (parseFloat(data[i][columnId]) || 0);
              }
              totals[columnId] = "" + total.toFixed(2);
            }
            totals['index'] = ''
            totals['bizCode'] = ''
            totals['bizName'] = '合计'
            console.log(totals)
            localStorage.setItem('dcTotals', JSON.stringify(totals))
          };

          this.getItemMetadata = function (index) {
            return (index != data.length) ? null : totalsMetadata;
          };
          this.updateTotals();
        }

        let dataProvider = new TotalsDataProvider(data, columns);
        dataView = new Slick.Data.DataView();
        grid = new Slick.Grid("#myGrid", dataProvider, columns, options);
        //-----------------------------------------------
        dataView.onRowCountChanged.subscribe(function (e, args) {
          ......
        });
......
      .totals {       //  修改合计样式
        font-weight: 700;
        color: blue;
      }

效果图
需求三:部分列 右对齐
  // 增加过滤
  columns.forEach(item => {
          if (item.name == '数量' || item.name == '无税金额' || item.name == '含税金额') {
            item.formatter = function cpuUtilizationFormatter(row, cell, value, columnDef, dataContext) {
              return "<span class='cell-float'>" + value + "</span>";
            }
          }
        })
......
       .cell-float {
          float: right;
        }
效果图
需求四:实现单元格的复制(复制表格数据)

需要引入plugins,并实现方法

        grid.setSelectionModel(new Slick.CellSelectionModel());
        grid.registerPlugin(new Slick.CellExternalCopyManager({}));

实例如下

<template>
  <div class="dc-collectquery">
    <el-button @click="search"  size="mini"><i class="el-icon-search"></i>查询</el-button>
    <div style="width:100%;">
      <div id="myGrid" style="width:100%;height:500px;"></div>
    </div>
  </div>
</template>

<script>
  import '../assets/slick/jquery-3.1.0'
  import '../assets/slick/jquery-ui-1.9.2'
  import '../assets/slick/jquery.event.drag-2.3.0.js'
  import '../assets/slick/slick.core.js'
  import '../assets/slick/slick.dataview.js'
  import '../assets/slick/slick.grid.js'

  //需要下面四个plugins
  import '../assets/plugins/slick.cellrangedecorator'
  import '../assets/plugins/slick.cellrangeselector'
  import '../assets/plugins/slick.cellexternalcopymanager.js'
  import '../assets/plugins/slick.cellselectionmodel.js'

  import Mock from 'mockjs'
  export default {
    name: "demo",
    data() {
      return {
      }
    },
    methods: {
      // 查询数据
      search() {
        this.handleTable()
      },
      // 处理表数据
      handleTable() {
        var grid;
        var data = [];
        var options = {
          enableCellNavigation: true,
          enableColumnReorder: false
        };
        var columns = [
          {id: "index", name: "序号", field: "index"},
          {id: "bizCode", name: "编号", field: "bizCode"},
          {id: "bizName", name: "名称", field: "bizName" ,width:260},
        ];

        // 引入mock 创建伪数据
        var Random = Mock.Random
        let list = Mock.mock({
          'data|20-50': [
            {
              'bizCode|+1': Random.integer(1000000, 9999999),
              bizName: Random.city(),
            },{
              'bizCode|+1': Random.integer(1000000, 9999999),
              bizName: Random.city(),
            },{
              'bizCode|+1': Random.integer(1000000, 9999999),
              bizName: Random.city(),
            },
          ]
        })

        data = list.data
        data.forEach((item, index) => {
          item.index = index + 1
          item.id = item.bizCode
        })

        grid = new Slick.Grid("#myGrid", data, columns, options);

        // 要想实现复制,重要的是这两个方法
        grid.setSelectionModel(new Slick.CellSelectionModel());
        grid.registerPlugin(new Slick.CellExternalCopyManager({}));
      },
    }
  }
</script>

<style lang="less">
  @import "../assets/slick/jquery-ui-1.11.3.custom.css";
  @import "../assets/slick/slick.grid.css";
  @import "../assets/slick/examples.css";

  .slick-preheader-panel {
    .ui-state-default {
      width: 100%;
      overflow: hidden;
      border-left: 0px !important;
      border-bottom: 0px !important;
    }
  }
  .slick-header-columns {
    border-bottom: 0px !important;
    text-align: center;    // 实现标题居中
  }
</style>

ok,暂时只用到这些东西。

番外篇

为了使用SlickGrid而引入jquery等众多依赖,虽然无需大的改动,就能达到解决问题的目的,但是这样并不是个睿智之举。
项目比较急,没去深入研究。至于如何剥离jquery,纯净版的vue☞SlickGrid 有待各位大神自己改造了。

项目中还涉及到导出excel,上万条数据的时候可能会慢点(导出过90M的excel)。如何导出excel,网上一大堆,可以参考
vue2 项目开发使用到的东东
前端导出excel☞js-xlsx实现合并单元格
Vue2.0---将页面中表格数据导出excel

相关文章

  • vue☞SlickGrid小试牛刀

    场景:项目中需要加载上万条表格数据,服务端查询耗时几分钟,再加上浏览器渲染几分钟,对于一般配置的电脑来说完全扛不住...

  • Vue第一篇!

    小试牛刀编写我们vue第一个简单的例子 接下来我们认识一下vue指令: v-if v-else: 等同于我们js里...

  • 2018/04/10

    小试牛刀。

  • 水粉画

    小试牛刀

  • 谁表白

    小试牛刀

  • 看看

    小试牛刀

  • 水彩画处女作

    闲在家中,小试牛刀

  • 水彩画处女作

    闲在家中,小试牛刀

  • 男神。

    各种几何形,眼睛快瞎了。?‍♀️ Photoshop 小试牛刀~?

  • 2017-07-25

    小试牛刀一下这个软件,似乎没那么漂亮。

网友评论

      本文标题:vue☞SlickGrid小试牛刀

      本文链接:https://www.haomeiwen.com/subject/numvgftx.html