React项目🌹Echarts踩坑记录🌹
项目背景
最近在做一个react项目,在首页里面放置多个Echarts
图表,并支持下载(可支持导出图片或者表格),查看更多(点击图表上方的查看更多按钮,打开抽屉,显示全部数据,数据可能很多),截止到今天,差不多已经完成了页面的编写和接口调试。
在做需求的过程中,也遇到了与Echarts
相关的一些问题。这篇文章主要是记录这些问题。
主要遇到的问题,有以下四个:
- 查看更多,抽屉打开,
图表尺寸异常
- 切换页签,鼠标返回页面,
图表异常消失
- 在调试过程中,
接口重复调用
Echarts
图表导出功能
实现
抽屉尺寸异常
问题描述
首页里有一个小的图表,里面包含7个部门的柱状图数据,图表上方有一个查看更多按钮,点击按钮,打开一个抽屉,显示全部部门的数据,部门可能很多,100%高度可能会使得数据显示很拥挤,单个柱体最小是35px。
但是刚一进入,抽屉里面的图表很小很小,设置的高度100%和宽度100%没有生效。打开控制台,控制台报Echarts提醒:
echarts警告:Can't get DOM width or height. Please check dom.clientWidth and dom.
clientHeight. They should not be 0.For example,
you may need to call this in the callback of window.onload.
错误翻译:
无法获取dom的宽高(简单来说就这个几个字)
翻译:无法获取DOM的宽度或高度。请检查dom。clientWidth dom.clientHeight。它们不应该是0。
例如,你可能需要在window.onload的回调函数中调用它。
解决方案
这里通过在
useEffect()
中借助setTimeout()
来延迟加载。
一定要在DOM渲染结束后,再去加载
核心代码:
const [chartHeight, setChartHeight] = usestate('100%')
useEffect(() => {
const { lineData, yData } = echartsData
const chartHeightTime = setTimeout(() => {
//解决数据量过大时,全屏显示密集的问题
const rawHeight = allDepartmentRef.current?.getBoundingClientRect()?.height
if (rawHeight && yData?.length) {
const chartHeight = yData.length * 35
const height = chartHeight > rawHeight ? `${chartHeight}px` : '100%'
setChartHeight(height)
}
}, 50)
// 延时加载,避免获取不到元素的高与宽
const chartInitTime = setTimeout(() => {
// 在组件挂载或更新时,创建或更新图表
if (allDepartmentRef?.current) {
myChart.current = echarts.init(allDepartmentRef.current)
//配置图表选项
const options = updateOptions(lineData, yData)
// 使用指定的配置项和数据显示图表
myChart.current?.setOption(options)
window,addEventListener('resize', echartsResize, false)
}
}, 200)
return () => {
clearTimeout(chartHeightTime)
clearTimeout(chartInitTime)
}
},[echartsData])
<div ref={allDepartmentRef} style={{ width: '100%',height: chartHeight }}></div>
切换页签,Echarts图表消失
问题描述
那问题是什么原因引起的呢?排查了半天,在网上也找了好多方法,也没解决。
解决方案
最后使用了一个笨办法,既然切换页面,原页面不可视,再切换到首页页面,页面可视,那没有方法来进行监听这种情况呢,答案是有的:document.addEventListener('visibilitychange')
document.addEventListener('visibilitychange')
是一个事件监听器,它用于检测网页的可见性发生变化时触发的事件。
当用户离开当前页面,或者最小化当前窗口,或者切换到了其他标签页,这个事件会被触发。网页可以通过这个事件来实现一些特定的行为,比如自动暂停视频播放、减少后台网络请求等。
使用方法如下:
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
// 页面不可见时执行的代码
} else {
// 页面可见时执行的代码
}
});
在以上代码中,当页面状态发生变化时,回调函数里的代码会被执行。由于document.hidden
属性可以返回当前页面的可见性状态,因此我们可以根据该属性的值来判断页面是否可见,并执行相应的代码。
核心代码:
//重新进入页面标识,用于处理页面重新进入时,页面图表不显示的问题
const [isOnPage, setIsOnPage] = useState < boolean > (true)
useEffect(() => {
const handleVisibilityChange = () => {
if (document.visibilityState === 'visible') {
setIsOnPage(true)
} else if (document.visibilityState === 'hidden') {
setIsOnPage(false)
}
}
document.addEventListener('visibilitychange', handleVisibilityChange)
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange)
}
}, [])
// 组件使用
useEffect(() => {
...
if (isOnPage) {
setoptions(echartsoptions)
}
}, [isOnPage])
调用调用,重复请求
问题描述
在联调后台接口的时候,后台接口一直报重复请求的错误(项目中做了重复请求的拦截和错误提示),一个页面里面包含十几个图表,初始进入时,要调用十几个接口,这些接口都报了重复请求的错误。但是部署到测试环境就正常。
后面进行排查,也是没排查出来问题所在。最后请教了别人,才知道是因为:
React中StrictMode严格模式,会导致开发环境,接口会请求两次或多次( useEffect 请求多次)。
唉,还是学react不够深,以后要多多学习,积累经验。
解决方案
React 提供了
严格模式
,在严格模式
下开发时,它将会调用每个组件函数两次
。通过重复调用组件函数,严格模式有助于找到违反这些规则的组件。
问题定位了,那这个问题就很好解决了。直接不用StrictMode严格模式不就行了吗。
root.render(
// <React.StrictMoide>
<App />
// </React.StrictMoide>
)
图表下载
问题描述
图表中的下载是支持下载图表和表格的,但是Echarts图表原生带入的下载功能,只支持下载图片,是不支持下载表格的。
解决方案
这里我们可以利用定位,在图表上方放一个下载按钮,鼠标悬浮,会有下载格式选择,选择图片,调用Echarts自带的原生下载方法,选择表格,调用后台接口即可。
那怎么调用Echarts的原生下载图片功能呢。
实现代码:
import * as echarts from "echarts";
const exportEchart = (fileName: String, echartsRef: any) => {
const myChart: any = echarts.getInstanceByDom(echartsRef as any);
const url = myChart.getConnectedDataURL({
pixelRatio: 2, //导出的图片分辨率比率,默认是1
backgroundColor: "#fff", //图表背景色
excludeComponents: [
//保存图表时忽略的工具组件,默认忽略工具栏
"toolbox",
],
type: "png", //图片类型支持png和jpeg
});
const $a = document.createElement("a");
const type = "png";
$a.download = `${fileName}.${type}`
$a.target = "_blank";
$a.href = url;
// Chrome and Firefox
if (typeof MouseEvent === "function") {
const evt = new MouseEvent("click", {
view: window,
bubbles: true,
cancelable: false,
});
$a.dispatchEvent(evt);
}
// IE
else {
const html =
"" +
'<body style="margin:0;">' +
'<img src="' +
url +
'" style="max-width:100%;" title="' +
myChart.getOption().title[0].text +
'" />' +
"</body>";
const tab: any = window.open();
tab.document.write(html);
}
}
export default exportEchart
// 使用
exportEchart('用户所属部门', allDepartmentRef.current)
< div ref = { allDepartmentRef } style={{height:'100%', width:'100%'}}></>
转载自:https://juejin.cn/post/7374307181482213430