处理监听图表的函数,确保及时移除&生产环境不打印log
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user