处理监听图表的函数,确保及时移除&生产环境不打印log

This commit is contained in:
2026-04-22 11:07:10 +08:00
parent 845e5a8af3
commit cfcb4f5068
117 changed files with 6781 additions and 5767 deletions

View File

@@ -1,187 +1,194 @@
<template>
<div style="width: 100%; height: 210px;position: relative;">
<div style='font-size: 16px;position: absolute;left: 20px;top:10px'>
万元
</div>
<div style='font-size: 16px;position: absolute;right: 20px;top:10px'>
<span>完成率:<span style='color: #0B58FF;'>{{detailData.completeRate}}%</span></span>
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:detailData.flag>0?'#30B590':'#FF9423'}" >{{detailData.diff}}</span></span>
</div>
<div :ref="refName" id="coreLineChart" style="width: 100%; height: 210px;"></div>
</div>
</template>
<script>
import * as echarts from 'echarts';
export default {
components: {},
data() {
return {
myChart: null
};
},
props: {
refName: {
type: String,
default: 'verticalBarChart',
},
detailData: {
type: Object,
default: () => ({
completeRate: 0,
diff: 0,
real: 0,
target: 0,
thb: 0,
flag: 0
}),
}
},
mounted() {
this.$nextTick(() => this.updateChart());
},
watch: {
detailData: {
handler() {
this.updateChart();
},
deep: true,
immediate: true
}
},
methods: {
updateChart() {
const chartDom = this.$refs[this.refName];
if (!chartDom) {
console.error('图表容器未找到!');
return;
}
console.log('this.detailData', this.detailData);
// 修复优化实例销毁逻辑避免重复dispose
if (this.myChart) {
this.myChart.clear(); // 先清空,再重新渲染
} else {
this.myChart = echarts.init(chartDom);
}
// 解构数据,避免重复取值
const { diff, completeRate, real, target, flag } = this.detailData;
// 确保数值为数字类型
const realValue = Number(real) || 0;
const targetValue = Number(target) || 0;
const diffValue = Number(diff) || 0;
const rateValue = Number(completeRate) || 0;
const flagValue = Number(flag) || 0;
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: { backgroundColor: '#6a7985' }
}
},
grid: {
top: 40,
bottom: 15,
right: 80,
left: 10,
containLabel: true,
show: false
},
xAxis: {
type: 'value',
axisTick: { show: false },
min: 0,
splitNumber: 4,
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
axisLabel: { color: 'rgba(0, 0, 0, 0.45)', fontSize: 12, interval: 0, padding: [5, 0, 0, 0] }
},
yAxis: {
type: 'category',
axisLabel: { color: 'rgba(0, 0, 0, 0.75)', fontSize: 12, interval: 0, padding: [5, 0, 0, 0] },
axisLine: { show: true, lineStyle: { color: '#E5E6EB', width: 1, type: 'solid' } },
axisTick: { show: false },
data: ['实际', '预算']
},
series: [
{
type: 'bar',
barWidth: 24,
// 修复:拆分数据项,确保每个柱子的样式独立生效
data: [
// 实际值柱子核心绑定flag颜色
{
value: realValue,
label: {
show: true,
position: 'right',
fontSize: 14
},
// 修复flag颜色判断独立绑定到实际值柱子
itemStyle: {
color: flagValue === 1
? {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(174, 239, 224, 1)' },
{ offset: 1, color: 'rgba(118, 218, 190, 1)' }
]
}
: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(253, 209, 129, 1)' },
{ offset: 1, color: 'rgba(249, 164, 74, 1)' }
]
},
borderRadius: [4, 4, 0, 0]
}
},
// 预算值柱子(固定蓝色渐变)
{
value: targetValue,
label: {
show: true,
position: 'right',
fontSize: 14
},
itemStyle: {
color: {
type: 'linear',
x: 1, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: '#82CCFF' },
{ offset: 1, color: '#4B9DFF' }
]
},
borderRadius: [4, 4, 0, 0],
borderWidth: 0
}
}
]
}
]
};
this.myChart.setOption(option, true); // 新增true表示替换所有配置避免缓存
// 优化防抖resize避免频繁触发
const resizeHandler = () => {
this.myChart && this.myChart.resize();
};
window.removeEventListener('resize', resizeHandler); // 先移除再添加,避免重复绑定
window.addEventListener('resize', resizeHandler);
this.$once('hook:destroyed', () => {
window.removeEventListener('resize', resizeHandler);
this.myChart && this.myChart.dispose();
this.myChart = null;
});
}
},
};
</script>
<template>
<div style="width: 100%; height: 210px;position: relative;">
<div style='font-size: 16px;position: absolute;left: 20px;top:10px'>
万元
</div>
<div style='font-size: 16px;position: absolute;right: 20px;top:10px'>
<span>完成率:<span style='color: #0B58FF;'>{{detailData.completeRate}}%</span></span>
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:detailData.flag>0?'#30B590':'#FF9423'}" >{{detailData.diff}}</span></span>
</div>
<div :ref="refName" id="coreLineChart" style="width: 100%; height: 210px;"></div>
</div>
</template>
<script>
import * as echarts from 'echarts';
export default {
components: {},
data() {
return {
myChart: null,
resizeHandler: null // 窗口resize事件处理器
};
},
props: {
refName: {
type: String,
default: 'verticalBarChart',
},
detailData: {
type: Object,
default: () => ({
completeRate: 0,
diff: 0,
real: 0,
target: 0,
thb: 0,
flag: 0
}),
}
},
mounted() {
this.$nextTick(() => this.updateChart());
// 注册窗口resize事件使用稳定的引用以便后续移除
this.resizeHandler = () => {
if (this.myChart) {
this.myChart.resize();
}
};
window.addEventListener('resize', this.resizeHandler);
},
watch: {
detailData: {
handler() {
this.updateChart();
},
deep: true,
immediate: true
}
},
methods: {
updateChart() {
const chartDom = this.$refs[this.refName];
if (!chartDom) {
console.error('图表容器未找到!');
return;
}
console.log('this.detailData', this.detailData);
// 修复优化实例销毁逻辑避免重复dispose
if (this.myChart) {
this.myChart.clear(); // 先清空,再重新渲染
} else {
this.myChart = echarts.init(chartDom);
}
// 解构数据,避免重复取值
const { diff, completeRate, real, target, flag } = this.detailData;
// 确保数值为数字类型
const realValue = Number(real) || 0;
const targetValue = Number(target) || 0;
const diffValue = Number(diff) || 0;
const rateValue = Number(completeRate) || 0;
const flagValue = Number(flag) || 0;
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: { backgroundColor: '#6a7985' }
}
},
grid: {
top: 40,
bottom: 15,
right: 80,
left: 10,
containLabel: true,
show: false
},
xAxis: {
type: 'value',
axisTick: { show: false },
min: 0,
splitNumber: 4,
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
axisLabel: { color: 'rgba(0, 0, 0, 0.45)', fontSize: 12, interval: 0, padding: [5, 0, 0, 0] }
},
yAxis: {
type: 'category',
axisLabel: { color: 'rgba(0, 0, 0, 0.75)', fontSize: 12, interval: 0, padding: [5, 0, 0, 0] },
axisLine: { show: true, lineStyle: { color: '#E5E6EB', width: 1, type: 'solid' } },
axisTick: { show: false },
data: ['实际', '预算']
},
series: [
{
type: 'bar',
barWidth: 24,
// 修复:拆分数据项,确保每个柱子的样式独立生效
data: [
// 实际值柱子核心绑定flag颜色
{
value: realValue,
label: {
show: true,
position: 'right',
fontSize: 14
},
// 修复flag颜色判断独立绑定到实际值柱子
itemStyle: {
color: flagValue === 1
? {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(174, 239, 224, 1)' },
{ offset: 1, color: 'rgba(118, 218, 190, 1)' }
]
}
: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(253, 209, 129, 1)' },
{ offset: 1, color: 'rgba(249, 164, 74, 1)' }
]
},
borderRadius: [4, 4, 0, 0]
}
},
// 预算值柱子(固定蓝色渐变)
{
value: targetValue,
label: {
show: true,
position: 'right',
fontSize: 14
},
itemStyle: {
color: {
type: 'linear',
x: 1, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: '#82CCFF' },
{ offset: 1, color: '#4B9DFF' }
]
},
borderRadius: [4, 4, 0, 0],
borderWidth: 0
}
}
]
}
]
};
this.myChart.setOption(option, true); // 新增true表示替换所有配置避免缓存
}
},
beforeDestroy() {
// 移除窗口resize事件监听器
if (this.resizeHandler) {
window.removeEventListener('resize', this.resizeHandler);
this.resizeHandler = null;
}
// 销毁图表,避免内存泄漏
if (this.myChart) {
this.myChart.dispose();
this.myChart = null;
}
}
};
</script>