123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- <template>
- <div ref="chartRef" class="line-chart" :style="{ width: width, height: height }"></div>
- </template>
- <script lang="ts" setup>
- import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue'
- import * as echarts from 'echarts'
- interface ChartDataItem {
- date: string
- value: number
- }
- interface Props {
- data: ChartDataItem[]
- width?: string
- height?: string
- title?: string
- color?: string
- showGrid?: boolean
- showTooltip?: boolean
- showLegend?: boolean
- smooth?: boolean
- areaStyle?: boolean
- }
- const props = withDefaults(defineProps<Props>(), {
- width: '100%',
- height: '270px',
- title: '',
- color: '#167AF0',
- showGrid: true,
- showTooltip: true,
- showLegend: false,
- smooth: false,
- areaStyle: false
- })
- const chartRef = ref<HTMLElement>()
- let chartInstance: echarts.ECharts | null = null
- // 初始化图表
- const initChart = () => {
- if (!chartRef.value) return
-
- chartInstance = echarts.init(chartRef.value)
- updateChart()
- }
- // 更新图表数据
- const updateChart = () => {
- if (!chartInstance) return
- const dates = props.data.map(item => item.date)
- const values = props.data.map(item => item.value)
- const option: echarts.EChartsOption = {
- tooltip: props.showTooltip ? {
- trigger: 'axis',
- backgroundColor: 'rgba(255, 255, 255, 0.95)',
- borderColor: '#E5E5E5',
- borderWidth: 1,
- textStyle: {
- color: '#333',
- fontSize: 12
- },
- axisPointer: {
- type: 'line',
- lineStyle: {
- color: props.color,
- width: 1,
- type: 'dashed'
- }
- },
- formatter: function(params: any) {
- const data = params[0]
- return `<div style="padding: 8px;">
- <div style="font-weight: 500; margin-bottom: 4px;">${data.name}</div>
- <div style="color: ${props.color}; font-size: 14px; font-weight: 500;">
- ${data.seriesName}: ${data.value}
- </div>
- </div>`
- }
- } : undefined,
- legend: props.showLegend ? {
- data: [props.title || '数据'],
- top: '40px',
- textStyle: {
- fontSize: 12,
- color: '#666'
- }
- } : undefined,
- grid: {
- left: '0%',
- right: '0%',
- bottom: '0%',
- top: '10px',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- boundaryGap: true,
- data: dates,
- axisLine: {
- lineStyle: {
- color: '#E5E5E5'
- }
- },
- axisTick: {
- show: false
- },
- axisLabel: {
- color: 'rgba(100, 100, 100, 1)',
- fontSize: 14
- },
- },
- yAxis: {
- type: 'value',
- axisLine: {
- show: false
- },
- axisTick: {
- show: false
- },
- axisLabel: {
- color: 'rgba(100, 100, 100, 1)',
- fontSize: 14,
- },
- splitLine: props.showGrid ? {
- lineStyle: {
- color: 'rgba(230, 230, 230, 1)',
- type: 'dashed'
- }
- } : {
- show: false
- }
- },
- series: [
- {
- name: props.title || '数据',
- type: 'line',
- data: values,
- smooth: props.smooth,
- symbol: 'circle',
- symbolSize: 8,
- lineStyle: {
- color: props.color,
- width: 2
- },
- itemStyle: {
- color: props.color,
- borderWidth: 2,
- borderColor: props.color,
- },
- emphasis: {
- itemStyle: {
- color: props.color,
- borderWidth: 2,
- borderColor: props.color,
- }
- }
- }
- ]
- }
- chartInstance.setOption(option)
- }
- // 监听数据变化
- watch(() => props.data, () => {
- nextTick(() => {
- updateChart()
- })
- }, { deep: true })
- // 监听窗口大小变化
- const handleResize = () => {
- if (chartInstance) {
- chartInstance.resize()
- }
- }
- onMounted(() => {
- initChart()
- window.addEventListener('resize', handleResize)
- })
- onUnmounted(() => {
- if (chartInstance) {
- chartInstance.dispose()
- chartInstance = null
- }
- window.removeEventListener('resize', handleResize)
- })
- // 暴露方法给父组件
- defineExpose({
- getChartInstance: () => chartInstance,
- resize: handleResize
- })
- </script>
- <style scoped lang="scss">
- .line-chart {
- display: block;
- box-sizing: border-box;
- }
- </style>
|