Live2d Test Env

echarts使用resize重新绘制图表时遇到的问题

需求: 外部输入一个echart数组,根据恒定的数组长度动态决定是否有滚动条存在,如果数组长超过恒定值则赋予滚动条,否则平滑展示

PS: 上级不许使用echart提供的滚动条,只好使用echart容器的父容器来实现

滚动原理

当子容器宽度大于父容器宽度且父容器设置了x或y轴overflow:auto时,会出现滚动条

前期准备

由于后端只给了一条数据,无法满足多种可能,因而自己写了一个循环多个的函数

/** 
 * @description: 拷贝数组项,适用于后台仅返回一条数据而我们需要多条数据
 * @param {*} arr  初始数组项,
 * @param {*} num  循环数,默认10
 * @return {*} newArr
 */ 
export const repeatArrayItem = (arr,num = 10) => {
  let newArr = []
  for (let index = 0; index < num; index++) {
    newArr.push(arr[0])
  }
  return newArr
}

外部使用:

 const a = repeatArrayItem(res.item)
 setTopData(a) //其中topData即为传入数组

准备工作完毕,接下来要写echart组件内部逻辑

需求实现

已知数组长度不确定,因而要动态设置父子容器样式(父容器ovwerlowX、子容器width)
jsx部分:

      <div style={{ overflowX  }}>
            <div ref={divRef} style={{
                height: "440px",
                width              
            }}  >
            </div>
        </div>

//  receiveEchartResource 为接收到的echart list

// 默认滚动
    const [overflowX, setOverflowX] = useState('auto')
    const [width, setWidth] = useState('140%')
    const isScroll = receiveEchartResource.length >= 18    //恒定值,作为是否滚动的依据
// 监听receiveEchartResource,变化则立即触发
 useEffect(()=>{
     setOverflowX( isScroll ? 'auto' : `hidden` )
     setWidth(  isScroll ? '140%' : '100%' )    
  },[receiveEchartResource])

本以为这样写就可以了,但是还不行,会有一个致命bug:外部父组件需要动态设置长度,假设恒定值为18,长度第一次大于小于18都可以展示,但是第二次如果是反状态则页面则不会渲染成功,或者挤到一起,或者展示不全且无滚动条,
起初以为是我的动态设置的样式有问题,直到看到window.resize函数里有echart.resize方法,突然想到应该是resize方法,然后尝试调用了一下,但是发现还是不行,后来感觉思路是对的,setState是异步,所以可能是resize方法提前于设置样式前就执行了,
所以就有了下面一步:

解决方案

原因:外部的动态传入list虽然生效,但是echart并没有办法改变自身容器,所以需要在监听到receiveEchartResource变化时重新resize一下

// 监听receiveEchartResource,变化则立即触发
let timer
 useEffect(()=>{
     setOverflowX( isScroll ? 'auto' : `hidden` )
     setWidth(  isScroll ? '140%' : '100%' )    
        // 判断外部传入数组是否有值,如果有则执行延时器
        if (receiveEchartResource.length > 0) {
            timer = setTimeout(() => {
                myChart?.resize()
            }, 100);
        }
        return (() => timer && clearTimeout(timer)) 
    
  },[receiveEchartResource])

原本没准备写判断传入数组,直接写定时器,但是码友说不判断就直接写入,会出现bug: 当网络延迟至大于500ms时,会出现无法渲染情况,所以就加了一层判断,并在销毁时清除timer。

ok,描述完毕,以上。

posted @ 2023-01-18 21:49  致爱丽丝  阅读(1237)  评论(0)    收藏  举报