找回密码
 立即注册

QQ登录

只需一步,快速开始

换日线

注册会员

8

主题

19

帖子

81

积分

注册会员

积分
81
换日线
注册会员   /  发表于:2024-2-2 09:58  /   查看:1284  /  回复:8
本帖最后由 Richard.Huang 于 2024-2-4 14:47 编辑

产品:SpreadJS

初始化数据全部展示
image.png798755187.png
而后通过第一个SpreadSheets中的ComboBox对下方的SpreadSheets中数据进行过滤,根据需求所有数据都应保留,因此我选用setRowVisible方法对被过滤的数据进行隐藏和显示的调用。
当我在下拉框选用月度后,即只过滤显示月度的数据,则当前过滤情况如下图:
image.png542825927.png
当我再次在下拉框选择季度过滤项,则会从13行开始展示,即将上一步月度数据所占最后一行的下一行开始展示,如下图:
image.png852533264.png
需要滚轮向上滚动才可以看见被筛选出的数据。
请问这种情况下如何让数据直接从被筛选出的第一条数据的起始行开始展示呢?

附加问题:
选择下拉框后设置存储过滤条件,然后根据过滤条件筛选每个表的数据。当点开下拉框选择条件后页面会卡顿(数据较多情况下,目前60条数据以略显卡顿),会在所有表格重新渲染结束后才会收起下拉框并改变下拉框的值,请问这种问题如何解决呢?

由于加密设置无法上传代码demo,我将代码拷贝下方, 项目为react项目:
入口App.js:

  1. import React from "react";
  2. import Header from './components/header'
  3. import Content from './components/content'
  4. import { useState } from "react";
  5. import { testData } from "./utils";

  6. function App() {

  7.   const [filterInfo, setFilterInfo] = useState({})
  8.   const [detailData, setDetailData] = useState(testData)

  9.   const handleFilter = (val) => {
  10.     setFilterInfo(val)
  11.     console.log(val);
  12.   }

  13.   return (
  14.     <div className="App">
  15.       <Header handleFilter={handleFilter} />
  16.       {
  17.         detailData?.map((item, index) => {
  18.           return <div key={index}>
  19.             <Content data={item} filterInfo={filterInfo} />
  20.           </div>
  21.         })
  22.       }
  23.     </div>
  24.   );
  25. }

  26. export default App;
复制代码

头部Header.js:
  1. import GC from "@grapecity/spread-sheets"
  2. import { SpreadSheets, Worksheet } from "@grapecity/spread-sheets-react"


  3. const Header = (props) => {
  4.     const { handleFilter } = props

  5.     const initSheet = (spread) => {
  6.         const sheet = spread.sheets[0]
  7.         sheet.setRowCount(1)
  8.         sheet.setColumnWidth(0, 110)
  9.         sheet.setRowHeight(0, 35)

  10.         let comBox = new GC.Spread.Sheets.CellTypes.ComboBox()
  11.         comBox.items([
  12.             {
  13.                 value: 'ALL',
  14.                 text: '全部'
  15.             },
  16.             {
  17.                 value: 'YEAR',
  18.                 text: '年度'
  19.             },
  20.             {
  21.                 value: 'SEASON',
  22.                 text: '季度'
  23.             },
  24.             {
  25.                 value: 'MONTH',
  26.                 text: '月度'
  27.             },
  28.         ])
  29.         comBox.editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.value)
  30.         sheet.getCell(0,0, GC.Spread.Sheets.SheetArea.viewport).cellType(comBox).value('ALL')

  31.         sheet.bind(GC.Spread.Sheets.Events.ValueChanged, (sender, args) => {
  32.             handleFilter({periodCode: args.newValue})
  33.         })
  34.     }

  35.     return <div>
  36.         <SpreadSheets hostStyle={{height: 80}} newTabVisible={false} workbookInitialized={(spread) => initSheet(spread)}>
  37.             <Worksheet></Worksheet>
  38.         </SpreadSheets>
  39.     </div>
  40. }

  41. export default Header  
复制代码

数据展示模块文件Content.js
  1. import GC from "@grapecity/spread-sheets"
  2. import { SpreadSheets, Worksheet } from "@grapecity/spread-sheets-react"
  3. import { useEffect } from "react"
  4. import { useState } from "react"


  5. const Content = (props) => {
  6.     const { data, filterInfo } = props

  7.     const [contentSheet, setContentSheet] = useState()

  8.     const initSheet = (spread) => {
  9.         const sheet = spread.sheets[0]
  10.         setContentSheet(sheet)
  11.         // sheet.setRowCount(1)
  12.         sheet.setColumnWidth(0, 110)
  13.         sheet.setDataSource(new GC.Spread.Sheets.Bindings.CellBindingSource(data))
  14.         let table = sheet.tables.add('table', 0, 0, 1, 5)
  15.         let column1 = new GC.Spread.Sheets.Tables.TableColumn(1, 'periodCode')
  16.         let column2 = new GC.Spread.Sheets.Tables.TableColumn(2, 'periodName')
  17.         table.autoGenerateColumns(false);
  18.         table.bindColumns([column1, column2])
  19.         table.bindingPath('dataSource')
  20.         table.showHeader(false)
  21.         sheet.deleteRows(0, 1)

  22.     }

  23.     const handleFilterData = () => {
  24.         // contentSheet.suspendPaint()
  25.         let dataSource = contentSheet.getDataSource().rT.dataSource
  26.         let tempData = []
  27.         dataSource.forEach((item, index) => {
  28.             if (filterInfo.periodCode !== 'ALL') {
  29.                 if (filterInfo.periodCode === item.periodCode) {
  30.                     if (item?.filter) {
  31.                         contentSheet.setRowVisible(index, true)
  32.                     }
  33.                     tempData.push({
  34.                         ...item,
  35.                         filter: false
  36.                     })
  37.                 } else {
  38.                     if (!item?.filter) {
  39.                         contentSheet.setRowVisible(index, false)
  40.                     }
  41.                     tempData.push({
  42.                         ...item,
  43.                         filter: true
  44.                     })
  45.                 }
  46.             } else {
  47.                 if (item?.filter) {
  48.                     contentSheet.setRowVisible(index, true)
  49.                 }
  50.                 tempData.push({
  51.                     ...item,
  52.                     filter: false
  53.                 })
  54.             }
  55.         });
  56.         contentSheet.setDataSource(new GC.Spread.Sheets.Bindings.CellBindingSource({
  57.             ...data,
  58.             dataSource: tempData
  59.         }))
  60.         contentSheet.resumePaint()
  61.     }

  62.     useEffect(() => {
  63.         if (Object.keys(filterInfo).length !== 0 && contentSheet) {
  64.             handleFilterData()
  65.         }
  66.     }, [filterInfo, contentSheet])

  67.     return <div>
  68.         <SpreadSheets hostStyle={{height: 300}} newTabVisible={false} workbookInitialized={(spread) => initSheet(spread)}>
  69.             <Worksheet></Worksheet>
  70.         </SpreadSheets>
  71.     </div>
  72. }

  73. export default Content
复制代码

数据文件util.js
  1. export const testData = [
  2.     {
  3.         level: 1,
  4.         dataSource: [
  5.             {
  6.                 periodCode: 'YEAR',
  7.                 periodName: '年度数据',
  8.                 id: 1,
  9.                 filter: false,
  10.             },
  11.             {
  12.                 periodCode: 'YEAR',
  13.                 periodName: '年度数据2',
  14.                 id: 2,
  15.                 filter: false,
  16.             },
  17.             {
  18.                 periodCode: 'YEAR',
  19.                 periodName: '年度数据3',
  20.                 id: 3,
  21.                 filter: false,
  22.             },
  23.             {
  24.                 periodCode: 'YEAR',
  25.                 periodName: '年度数据4',
  26.                 id: 4,
  27.                 filter: false,
  28.             },
  29.             {
  30.                 periodCode: 'SEASON',
  31.                 periodName: '季度数据',
  32.                 id: 5,
  33.                 filter: false,
  34.             },
  35.             {
  36.                 periodCode: 'SEASON',
  37.                 periodName: '季度数据2',
  38.                 id: 6,
  39.                 filter: false,
  40.             },
  41.             {
  42.                 periodCode: 'SEASON',
  43.                 periodName: '季度数据3',
  44.                 id: 7,
  45.                 filter: false,
  46.             },
  47.             {
  48.                 periodCode: 'SEASON',
  49.                 periodName: '季度数据4',
  50.                 id: 8,
  51.                 filter: false,
  52.             },
  53.             {
  54.                 periodCode: 'MONTH',
  55.                 periodName: '月度数据',
  56.                 id: 9,
  57.                 filter: false,
  58.             },
  59.             {
  60.                 periodCode: 'MONTH',
  61.                 periodName: '月度数据2',
  62.                 id: 10,
  63.                 filter: false,
  64.             },
  65.             {
  66.                 periodCode: 'MONTH',
  67.                 periodName: '月度数据3',
  68.                 id: 11,
  69.                 filter: false,
  70.             },
  71.             {
  72.                 periodCode: 'MONTH',
  73.                 periodName: '月度数据4',
  74.                 id: 12,
  75.                 filter: false,
  76.             }
  77.         ]
  78.     },
  79. ]
复制代码

如需多数据测试,可直接复制带level属性的那个对象,多复制几个即可复现卡顿问题

8 个回复

倒序浏览
Richard.HuangSpreadJS 开发认证
超级版主   /  发表于:2024-2-2 12:08:00
沙发
您好,您的两个问题我将分别进行回答:
1. 您可以通过contentSheet.showRow(0)方法将当前sheet滚动到最上面一行
2. 造成卡顿的原因是,您的handleFilter函数是一个同步函数,只有当您的三个contentSheet完成您自定义的筛选后,才会去更新您的header中的渲染,因此您可以发现卡顿,按照您目前的设计,如果您不期望卡顿,只能将handleFilter换成异步执行的操作,我注意到您之前还有一个帖子,跟这个问题很像应该是同一个问题(传送门:https://gcdn.grapecity.com.cn/showtopic-202520-1-1.html),附件是我按照这个思路实现的一个demo,您可以查看并根据您的业务实现相应调整后满足您的需求

利用数据绑定实现联动筛选.rar

2.52 KB, 下载次数: 89

回复 使用道具 举报
换日线
注册会员   /  发表于:2024-2-2 13:54:37
板凳
本帖最后由 换日线 于 2024-2-2 14:15 编辑
Richard.Huang 发表于 2024-2-2 12:08
您好,您的两个问题我将分别进行回答:
1. 您可以通过contentSheet.showRow(0)方法将当前sheet滚动到最上 ...

您好,非常感谢您的解答,您的方法我应用后能够解决大部分问题。
我目前扔存在一个问题是,如果在此基础上我不希望表格内容区域能够滚动,因此我的业务代码的初始化方法中使用了以下代码禁止滚动
  1. sheet.bind(GC.Spread.Sheets.Events.TopRowChanged, function (sender, args) {
  2. console.log(args)
  3. sheet.showRow(0)
  4. });
复制代码

但是设置了这个代码的话好像就会造成死循环导致内存溢出,请问这个有解决办法吗
回复 使用道具 举报
Richard.HuangSpreadJS 开发认证
超级版主   /  发表于:2024-2-2 15:19:42
地板
换日线 发表于 2024-2-2 13:54
您好,非常感谢您的解答,您的方法我应用后能够解决大部分问题。
我目前扔存在一个问题是,如果在此基础 ...

您好,您所面临的情况的原因是sheet.showRow这个方法如果造成页面滚动,也是会触发TopRowChanged这个事件的,对于您的需求来讲我想您可以在contentSheet.showRow(0)这个方法的前后先解绑TopRowChanaged事件滚动结束后再重新监听这个事件:
  1. contentSheet.unbind(GC.Spread.Sheets.Events.TopRowChanged);
  2. contentSheet.showRow(0);
  3. contentSheet.bind(
  4.   GC.Spread.Sheets.Events.TopRowChanged,
  5.   function (sender, args) {
  6.     console.log(args);
  7.     contentSheet.showRow(0);
  8.   }
  9. );
复制代码
回复 使用道具 举报
换日线
注册会员   /  发表于:2024-2-2 15:57:54
5#
Richard.Huang 发表于 2024-2-2 15:19
您好,您所面临的情况的原因是sheet.showRow这个方法如果造成页面滚动,也是会触发TopRowChanged这个事件 ...

image.png246925658.png

使用此方法只要切换了过滤条件后,只要在表格中触发了滚动滚轮,便会页面卡死,内存溢出,似乎有点问题
回复 使用道具 举报
Richard.HuangSpreadJS 开发认证
超级版主   /  发表于:2024-2-2 17:55:38
6#
换日线 发表于 2024-2-2 15:57
使用此方法只要切换了过滤条件后,只要在表格中触发了滚动滚轮,便会页面卡死,内存溢出,似乎有点问 ...

经过测试发现,是因为当筛选结束后非隐藏行最小的行索引大于0时,showRow(0)会将当前页面发生滚动,但是因为无法滚动到索引为0处,于是又触发TopRowChanged事件,从而变成了循环,这里我们应该将showRow(0)改成showRow(topRowIndex),这里的topRowIndex为拉到最上面看到的行号,以下是修改后的代码示例
  1. contentSheet.unbind(GC.Spread.Sheets.Events.TopRowChanged);
  2. contentSheet.showRow(0);
  3. //获取目前视窗最上面的行索引
  4. let topRowIndex = contentSheet.getViewportTopRow(1);
  5. contentSheet.bind(
  6.     GC.Spread.Sheets.Events.TopRowChanged,
  7.     function (sender, args) {
  8.         console.log(args);
  9.         contentSheet.showRow(topRowIndex);
  10.     }
  11. );
复制代码
回复 使用道具 举报
换日线
注册会员   /  发表于:2024-2-5 15:40:18
7#
本帖最后由 换日线 于 2024-2-5 15:57 编辑
Richard.Huang 发表于 2024-2-2 17:55
经过测试发现,是因为当筛选结束后非隐藏行最小的行索引大于0时,showRow(0)会将当前页面发生滚动,但是 ...

按照代码中的结构,遍历数据渲染多个SpreadSheets表,在每个表中插入table表以供数据渲染,但是当数据有两万条时,加载会非常卡顿,请问有什么解决办法吗?并且渲染样式后,卡顿会至少翻一倍。
回复 使用道具 举报
Richard.HuangSpreadJS 开发认证
超级版主   /  发表于:2024-2-5 18:20:07
8#
换日线 发表于 2024-2-5 15:40
按照代码中的结构,遍历数据渲染多个SpreadSheets表,在每个表中插入table表以供数据渲染,但是当数据有 ...

因为您的逻辑是遍历每条数据并根据筛选情况去每一行的隐藏和展示,我想我们可以采取另一种方式来解决您的需求,采用筛选同步的方式,附件是我测试的demo,2w行数据没有明显卡顿

三表联动筛选.html

8.01 KB, 下载次数: 75

回复 使用道具 举报
Richard.HuangSpreadJS 开发认证
超级版主   /  发表于:2024-2-19 16:07:29
9#
您好,由于您长时间未回帖,本贴就先作结帖处理了,后续如果有其他新的问题,欢迎继续发新帖询问
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 立即注册
返回顶部