描述

在移动端没有hover事件,所以触发echarts的高亮事件只有点击事件,这个时候如果有页面滚动事件的时候,滚动的时候并不能隐藏tooltip。
在这里插入图片描述
这个时候页面滚动是不会隐藏的。
在这里插入图片描述

除此之外,如果页面同时多个图表,这个时候会出现多个tooltip,这个产品认为可能体验会比较不好,希望能够一个页面只高亮一个图表。

方案

需要做到跨图表状态管理,很明显选择使用vuex来存储状态是比较方便。所以这里使用vuex来存储图表直接是否存在高亮的属性。

同时为了引入方便,这里使用mixin来专门处理这个属性值的变化。

代码

vuex

在vuex中为了方便修改值,写了一个Mutation和属性值设置

export default {
	state:{
		hideAllToolTip: false,
	},
	changeHideTooltip(state,payload){
		state.hideAllToolTip = payload
	}
}

mixin:hideAllTooltip

import {
  mapState,
  mapMutations,
} from 'vuex';

let hasBinded = false;
let bindedId = '';

export const hideAllToolTip = {
  computed: {
    ...mapState({
    // 使用大写 尽量避免命名冲突覆盖
      HIDE_ALL_TOOLTIP: (state) => state.hideAllToolTip,
    }),
  },
  mounted() {
    // 如果已经绑定了,则直接返回
    if (hasBinded) {
      return;
    }
    hasBinded = true;
    // eslint-disable-next-line no-underscore-dangle
    bindedId = this.__uid;
    // 绑定事件 - 捕获
    document.documentElement.addEventListener('touchstart', this.EVENT_CAPTURE, true);
    // 绑定事件 - 冒泡
  },
  methods: {
    ...mapMutations({
      CHANGEGLOBALSTATE: 'changeHideTooltip',
    }),
    EVENT_CAPTURE(event) {
      if (event.target.tagName.toUpperCase() === 'CANVAS') {
        // 判断一下
        if (this.HIDE_ALL_TOOLTIP !== false) {
          this.CHANGEGLOBALSTATE({
            hideAllToolTip: false,
          });
        }
        return;
      }
      // this.showToolTip = false;
      // clickId = '';
      if (this.HIDE_ALL_TOOLTIP !== true) {
        this.CHANGEGLOBALSTATE({
          hideAllToolTip: true,
        });
      }
    },
  },
  beforeDestroy() {
    // eslint-disable-next-line no-underscore-dangle
    if (bindedId === this.__uid) {
      // 解绑事件 - 捕获
      document.documentElement.removeEventListener('touchstart', this.EVENT_CAPTURE, true);
      // 重置变量
      hasBinded = false;
      bindedId = '';
    }
  },
};

export default {
  hideAllToolTip,
};

需要注意的是,这里的mixin的属性都使用大写,这样避免覆盖了引入的组件的方法和属性。

使用

只需要在对应的echart组件直接引入即可,通过监听HIDE_ALL_TOOLTIP状态进行设置tooltip的显示与否。

例子:一个简单的linechart

这里使用的是自己封装多一层的V-CHARTS组件,可以避免写重复的API,直接配置option即可。

<template>
 <v-chart ref='chart' class="chart" :options="options" :autoresize="true"></v-chart>
</template>
<script>
import { hideAllToolTip } from '@/mixins/hideAllToolTip';
export default {
	mixins: [hideAllToolTip],
	data(){
		return {
			option : {
			    tooltip:{
			        show:true,
			        trigger:'axis'
			    },
			    xAxis: {
			        type: 'category',
			        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
			    },
			    yAxis: {
			        type: 'value'
			    },
			    series: [{
			        data: [820, 932, 901, 934, 1290, 1330, 1320],
			        type: 'line'
			    }]
			};
		}
	},
	  watch: {
	    // 动态隐藏tooltip
	    HIDE_ALL_TOOLTIP(v) {
	      this.$refs.chart.mergeOptions({
	        tooltip: {
	          show: !v,
	        },
	      });
	    },
	  },
}
</script>

mergeOptions

这里是调用echart官方提供的动态设置option,支持merge合并模式。
如果直接去修改option的属性的,会出现重新渲染数据,导致图表都会重新闪烁或者出现初始化的动画。如果使用了dataZoom的话,还会导致滚动位置重置,这样体验会非常不好的,所以最好使用官方提供的修改option的api。
主要是封装了一层,方便使用。

V-CHART组件部分代码
export default {
	methods:{
		 // provide an explicit merge option method
	    mergeOptions(options, notMerge, lazyUpdate) {
	      if (this.manualUpdate) {
	        this.manualOptions = options;
	      }

	      if (!this.chart) {
	        this.init(options);
	      } else {
	    	// 调用echart方法
	        this.delegateMethod('setOption', options, notMerge, lazyUpdate);
	      }
	    },
	    delegateMethod(name, ...args) {
		    return this.chart[name](...args);
		 },
	}
}
Logo

前往低代码交流专区

更多推荐