Vue2 + ECharts 实战:动态一个关键词或动态多关键词筛选折线图,告别数据重叠难题

功能一、一次只能搜索一个图例

效果一:

代码:

复制代码
<template>
  <div class="chart-container">
    <input 
      v-model="searchKeyword"
      placeholder="输入关键词搜索图例"
      @input="handleSearch"
    />
    <!-- 确保 ref 名称正确且元素存在 -->
    <div ref="chart" style="width: 800px; height: 400px;"></div>
  </div>
</template>

<script>
// 正确引入 echarts
import * as echarts from 'echarts';

export default {
  data() {
    return {
      searchKeyword: '',
      chartInstance: null, // 存储图表实例
      option: {
        legend: {
          data: ['销售额', '成本', '利润'],
          selected: {} // 初始化 selected 对象
        },
        xAxis: { type: 'category', data: ['1月', '2月', '3月', '4月', '5月', '6月'] },
        yAxis: { type: 'value' },
        series: [
          { name: '销售额', type: 'line', data: [120, 200, 150, 80, 70, 110] },
          { name: '成本', type: 'line', data: [80, 120, 100, 60, 50, 90] },
          { name: '利润', type: 'line', data: [40, 80, 50, 20, 20, 20] }
        ]
      }
    };
  },
  mounted() {
    // 确保在 mounted 钩子中初始化图表
    this.initChart();
  },
  beforeDestroy() {
    // 销毁图表实例
    if (this.chartInstance) {
      this.chartInstance.dispose();
    }
  },
  methods: {
    initChart() {
      // 确保 DOM 元素已渲染
      if (this.$refs.chart) {
        // 初始化图表
        this.chartInstance = echarts.init(this.$refs.chart);
        // 设置默认选中所有图例
        this.option.legend.selected = this.option.legend.data.reduce((acc, name) => {
          acc[name] = true;
          return acc;
        }, {});
        // 渲染图表
        this.chartInstance.setOption(this.option);
      } else {
        console.error('DOM 元素未找到,请检查 ref="chart"');
      }
    },
    handleSearch() {
      const keyword = this.searchKeyword.trim().toLowerCase();
      const newSelected = this.option.legend.data.reduce((acc, name) => {
        acc[name] = name.toLowerCase().includes(keyword);
        return acc;
      }, {});
      // 更新图例显隐状态
      this.chartInstance.setOption({
        legend: { selected: newSelected }
      });
    }
  }
};
</script>

功能二、一次可以搜索多个图例,以英文逗号分隔

效果展示:

代码:

复制代码
<template>
  <div class="chart-container">
    <input 
      v-model="searchKeywords"
      placeholder="请输入图例名称,多个关键词以英文逗号分隔"
      class="search-input"
      @input="handleSearch"
    />
    <div ref="chart" class="chart"></div>
  </div>
</template>

<script>
import * as echarts from 'echarts';

export default {
  data() {
    return {
      searchKeywords: '',      // 搜索关键词(支持逗号分隔)
      chartInstance: null,     // ECharts 实例
      baseOption: {            // 图表基础配置
        legend: {
          data: ['北京销售额', '上海销售额', '广州成本', '深圳利润'],
          selected: {}
        },
        xAxis: { type: 'category', data: ['Q1', 'Q2', 'Q3', 'Q4'] },
        yAxis: { type: 'value' },
        series: [
          { name: '北京销售额', type: 'line', data: [120, 200, 150, 80] },
          { name: '上海销售额', type: 'line', data: [180, 240, 210, 160] },
          { name: '广州成本', type: 'line', data: [80, 100, 70, 50] },
          { name: '深圳利润', type: 'line', data: [40, 80, 60, 30] }
        ]
      }
    };
  },
  mounted() {
    this.initChart();
  },
  beforeDestroy() {
    if (this.chartInstance) {
      this.chartInstance.dispose();
    }
  },
  methods: {
    // 初始化图表
    initChart() {
      this.chartInstance = echarts.init(this.$refs.chart);
      // 默认全部显示
      const initialSelected = this.baseOption.legend.data.reduce((acc, name) => {
        acc[name] = true;
        return acc;
      }, {});
      this.baseOption.legend.selected = initialSelected;
      this.chartInstance.setOption(this.baseOption);
    },

    // 处理搜索输入(支持逗号分隔多个关键词)
    handleSearch() {
      // 分割关键词并处理格式
      const keywords = this.searchKeywords
        .split(',')
        .map(k => k.trim().toLowerCase())
        .filter(k => k !== '');

      // 生成新的 selected 对象(任一关键词匹配即显示)
      const newSelected = this.baseOption.legend.data.reduce((acc, name) => {
        const nameLower = name.toLowerCase();
        acc[name] = keywords.length === 0 || keywords.some(k => nameLower.includes(k));
        return acc;
      }, {});

      // 更新图表
      this.chartInstance.setOption({
        legend: { selected: newSelected }
      });
    }
  }
};
</script>

<style scoped>
.chart-container {
  width: 1000px;
  margin: 20px auto;
}
.search-input {
  width: 400px;
  padding: 8px 12px;
  margin-bottom: 15px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
}
.chart {
  width: 100%;
  height: 500px;
}
</style>
相关推荐
San3040 分钟前
JavaScript 底层探秘:从执行上下文看 `this` 的设计哲学与箭头函数的救赎
javascript·面试·ecmascript 6
黛色正浓41 分钟前
【React】极客园案例实践-项目搭建和登录模块
前端·react.js·rust
Healer9181 小时前
js请求的并发控制
前端
是你的小橘呀1 小时前
从 "渣男" 到 "深情男":Promise 如何让 JS 变得代码变得专一又靠谱
前端·javascript·html
baozj1 小时前
告别截断与卡顿:我的前端PDF导出优化实践
前端·javascript·vue.js
傲文博一1 小时前
为什么我的产品尽量不用「外置」动态链接库
前端·后端
Healer9181 小时前
Promise限制重复请求
前端
梵得儿SHI1 小时前
Vue 响应式原理深度解析:Vue2 vs Vue3 核心差异 + ref/reactive 实战指南
前端·javascript·vue.js·proxy·vue响应式系统原理·ref与reactive·vue响应式实践方案
chenyunjie1 小时前
我做了一个编辑国际化i18n json文件的命令行工具
前端