BarChart.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. <template>
  2. <div ref="chartRef" :class="className" :style="{height:height,width:width}" />
  3. </template>
  4. <script setup>
  5. import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
  6. import * as echarts from 'echarts'
  7. const animationDuration = 6000
  8. const props = defineProps({
  9. className: {
  10. type: String,
  11. default: 'chart'
  12. },
  13. width: {
  14. type: String,
  15. default: '100%'
  16. },
  17. height: {
  18. type: String,
  19. default: '300px'
  20. }
  21. })
  22. const chartRef = ref(null)
  23. let chartInstance = null
  24. let resizeObserver = null
  25. let resizeTimer = null
  26. const handleResize = () => {
  27. if (resizeTimer) {
  28. clearTimeout(resizeTimer)
  29. }
  30. resizeTimer = setTimeout(() => {
  31. if (chartInstance) {
  32. try {
  33. chartInstance.resize()
  34. } catch (error) {
  35. console.error('图表重绘失败:', error)
  36. }
  37. }
  38. }, 200)
  39. }
  40. const initResizeListener = () => {
  41. // 监听窗口大小变化
  42. window.addEventListener('resize', handleResize)
  43. // 使用 ResizeObserver 监听容器自身大小变化
  44. if (typeof ResizeObserver !== 'undefined' && chartRef.value) {
  45. resizeObserver = new ResizeObserver((entries) => {
  46. handleResize()
  47. })
  48. resizeObserver.observe(chartRef.value)
  49. }
  50. }
  51. const removeResizeListener = () => {
  52. // 清理定时器
  53. if (resizeTimer) {
  54. clearTimeout(resizeTimer)
  55. resizeTimer = null
  56. }
  57. // 移除窗口监听
  58. window.removeEventListener('resize', handleResize)
  59. // 断开 ResizeObserver
  60. if (resizeObserver) {
  61. resizeObserver.disconnect()
  62. resizeObserver = null
  63. }
  64. }
  65. const initChart = () => {
  66. if (!chartRef.value) return
  67. if (chartInstance) {
  68. chartInstance.dispose()
  69. }
  70. chartInstance = echarts.init(chartRef.value, 'macarons')
  71. chartInstance.setOption({
  72. tooltip: {
  73. trigger: 'axis',
  74. axisPointer: {
  75. type: 'shadow'
  76. }
  77. },
  78. grid: {
  79. top: 10,
  80. left: '2%',
  81. right: '2%',
  82. bottom: '3%',
  83. containLabel: true
  84. },
  85. xAxis: [{
  86. type: 'category',
  87. data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
  88. axisTick: {
  89. alignWithLabel: true
  90. }
  91. }],
  92. yAxis: [{
  93. type: 'value',
  94. axisTick: {
  95. show: false
  96. }
  97. }],
  98. series: [{
  99. name: 'pageA',
  100. type: 'bar',
  101. stack: 'vistors',
  102. barWidth: '60%',
  103. data: [79, 52, 200, 334, 390, 330, 220],
  104. animationDuration
  105. }, {
  106. name: 'pageB',
  107. type: 'bar',
  108. stack: 'vistors',
  109. barWidth: '60%',
  110. data: [80, 52, 200, 334, 390, 330, 220],
  111. animationDuration
  112. }, {
  113. name: 'pageC',
  114. type: 'bar',
  115. stack: 'vistors',
  116. barWidth: '60%',
  117. data: [30, 52, 200, 334, 390, 330, 220],
  118. animationDuration
  119. }]
  120. })
  121. // 图表初始化后立即重绘一次,确保尺寸正确
  122. nextTick(() => {
  123. chartInstance.resize()
  124. })
  125. }
  126. onMounted(() => {
  127. nextTick(() => {
  128. initChart()
  129. initResizeListener()
  130. })
  131. })
  132. onBeforeUnmount(() => {
  133. removeResizeListener()
  134. if (chartInstance) {
  135. chartInstance.dispose()
  136. chartInstance = null
  137. }
  138. })
  139. // 暴露方法给父组件
  140. defineExpose({
  141. resizeChart: handleResize
  142. })
  143. </script>