前言
在项目中,常常会遇到 ECharts 弹窗的需求。有些很简单,有些就比较刁钻了,非要你搞点花样来,才显得高级。最常见的是地图弹窗,但是今天不想举地图弹窗的例子,就拿简单的柱状图来举例吧,比较省事。
本文涉及到的 MyChart 组件请见我的上一篇文章 基于 ECharts 的二次封装
一、内置原始弹窗 tooltip
首先来一个小 Demo,实现弹窗效果,我们只需要在配置项里面设置 tooltip: { show : true } 即可。这么个小动作,就可以解决一般的业务需求。
1.代码落地
<template>
<div class="echartBar">
<MyChart :op="op" :height="'100%'" @chart-click="chartClick"></MyChart>
</div>
</template>
<script>
import MyChart from '@/components/MyChart.vue'
export default {
components: {
MyChart
},
data () {
return {}
},
computed: {
op () {
return {
// ◆内置弹窗
tooltip: {
show: true
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
type: 'bar',
barWidth: '60%',
data: [10, 52, 200, 334, 390, 330, 220],
itemStyle: {
color: '#5470c6'
}
}
]
}
}
},
methods: {
chartClick () {}
}
}
</script>
<style lang="less" scoped>
.echartBar {
width: 400px;
height: 300px;
}
</style>
2.弹窗效果展示
将鼠标悬浮在 Fri 柱条上,就出现原始弹窗内容啦。但是业务需求往往不一般,那我们如何修改弹窗的样式或内容呢?放心吧,ECharts 早就帮我们想好啦!
二、formatter 回调函数拼接弹窗
tooltip 里面还有一个 formatter 属性,支持字符串模板和回调函数两种形式,字符串模板这里就不研究了,我更热衷于使用回调函数,且功能更强大。
1.代码落地
<template>
<div class="echartBar">
<MyChart :op="op" :height="'100%'" @chart-click="chartClick"></MyChart>
</div>
</template>
<script>
import MyChart from '@/components/MyChart.vue'
export default {
components: {
MyChart
},
data () {
return {}
},
computed: {
op () {
return {
// ◆内置弹窗
// 1.拼接简易字符串
// 如果没有配置 trigger 和 trigger ,则 params 是对象
// tooltip: {
// formatter: (params) => {
// const tooltip = `${params.name}:${params.value}`
// return tooltip
// }
// },
// 2.拼接 HTML 模板
// 如果配置 trigger 和 trigger ,则 params 是数组
tooltip: {
trigger: 'axis', // 触发类型
axisPointer: { // 坐标指示器配置项
type: 'shadow'
},
backgroundColor: 'transparent', // 去掉原始弹窗的背景色
borderColor: 'transparent', // 去掉原始弹窗的边框
formatter: (params) => {
const tooltip =
`<div class="tooltip">
<div class="header">
<div class="riskColor ${this.getColor(params[0].value)}"></div>
<div class="riskRank">${this.getRiskRank(params[0].value)}风险</div>
</div>
<div class="body">${params[0].name}:${params[0].value}</div>
</div>`
return tooltip
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: 'Direct',
type: 'bar',
barWidth: '60%',
data: [10, 52, 200, 334, 390, 330, 220],
itemStyle: {
color: '#5470c6'
}
}
]
}
}
},
methods: {
chartClick () {},
getColor (value) {
let color = ''
if (value > 300) {
color = 'bgGreen'
} else if (value > 200) {
color = 'bgYellow'
} else {
color = 'bgRed'
}
return color
},
getRiskRank (value) {
let risk = '无'
if (value > 300) {
risk = '低'
} else if (value > 200) {
risk = '中'
} else {
risk = '高'
}
return risk
}
}
}
</script>
<style lang="less" scoped>
.echartBar {
width: 400px;
height: 300px;
/* 书写弹窗样式 */
/deep/.tooltip {
width: 100px;
height: 50px;
background-color: rgba(90,201,222,0.3);
border: 1px solid #ccc;
color: black;
padding: 10px;
border-radius: 10px;
.header {
display: flex;
align-items: center;
.riskColor {
width: 20px;
height: 20px;
border-radius: 50%;
margin-right: 5px;
&.bgGreen {
background-color: green;
}
&.bgYellow {
background-color: yellow;
}
&.bgRed {
background-color: red;
}
}
}
.body {
margin-top: 10px;
}
}
}
</style>
2.弹窗效果展示
还是很不错的吧!一下子高级感就出来了。但是这样拼接一个弹窗出来,真的忒麻烦了。有没有更好的方法呢?比如,可以写一个弹窗组件,把它引进来?有,但是得升级 ECharts5 版本才行。
三、以组件的形式 new 一个弹窗
注意:第三种方法,对 ECharts 的版本要求比较高,我用的是 "echarts": "^5.0.0"
1.代码落地
@/components/MyTooltip.vue
<template>
<div class="my-tooltip">
<div class="tip-header">
<div :class="['riskColor', getRiskColor(tipData.value)]"></div>
<div class="riskRank">{{ getRiskRank(tipData.value) }}风险</div>
</div>
<div class="tip-body">{{ tipData.name }}:{{ tipData.value }}</div>
</div>
</template>
<script>
export default {
name: 'Tooltip',
data () {
return {
tipData: {
name: '',
value: ''
}
}
},
methods: {
// 获取风险等级颜色
getRiskColor (value) {
let color = 'bgGreen'
if (value > 300) {
color = 'bgGreen'
} else if (value > 200) {
color = 'bgYellow'
} else {
color = 'bgRed'
}
return color
},
// 获取风险等级
getRiskRank (value) {
let risk = '无'
if (value > 300) {
risk = '低'
} else if (value > 200) {
risk = '中'
} else {
risk = '高'
}
return risk
},
getData (params) {
this.tipData = params
}
}
}
</script>
<style lang="less" scoped>
.my-tooltip {
width: 100px;
height: 50px;
background-color: rgba(115,143,213,0.3);
color: black;
padding: 10px;
border-radius: 10px;
.tip-header {
display: flex;
align-items: center;
.riskColor {
width: 20px;
height: 20px;
border-radius: 50%;
margin-right: 5px;
background-color: green;
color: blue;
&.bgGreen {
background-color: green;
}
&.bgYellow {
background-color: yellow;
}
&.bgRed {
background-color: red;
}
}
}
.tip-body {
margin-top: 10px;
}
}
</style>
App.vue
<template>
<div class="echartBar">
<MyChart :op="op" :height="'100%'" @chart-click="chartClick"></MyChart>
</div>
</template>
<script>
import MyChart from '@/components/MyChart.vue'
import MyTooltip from '@/components/MyTooltip.vue'
import Vue from 'vue'
const MyTooltips = Vue.extend(MyTooltip)
export default {
components: {
MyChart
},
computed: {
op () {
return {
// 内置弹窗
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
backgroundColor: 'transparent',
borderColor: 'transparent', // 设置颜色无效
formatter: (params) => {
const com = new MyTooltips()
// com.getData({ name: params.name, value: params.value })
com.getData({ name: params[0].name, value: params[0].value })
com.$mount()
// return com.$el.innerHTML // 用 innerHtml 会有问题,打印下就知道了
return com.$el
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: 'Direct',
type: 'bar',
barWidth: '60%',
data: [10, 52, 200, 334, 390, 330, 220],
itemStyle: {
color: '#5470c6'
}
}
]
}
}
},
methods: {
chartClick () {}
}
}
</script>
<style lang="less" scoped>
.echartBar {
width: 400px;
height: 300px;
}
</style>
2.弹窗效果展示
也可以实现吧!但是这个边框的颜色咋没生效嘞......这可能是一个 bug 吧,不知道哪位大佬能解决。
后语
下面讲讲我在第三种方法踩的坑:
1、不知道为啥, ECharts5 版本弹窗的原始边框颜色改不掉,所以就算你在 tooltip 里面设置 backgroundColor: 'transparent',最外层也始终有一层背景,所以我的办法是直接在 tooltip 里面设置弹窗的背景颜色,边框的颜色就不管了。
2、当我设置 trigger 和 axisPointer 的时候, formatter 回调函数里面的参数 params 竟然由对象变成了数组,这就导致我无法获取 params 里面的 name 和 value。我折腾了很久才发现问题所在。
// com.getData({ name: params.name, value: params.value })
com.getData({ name: params[0].name, value: params[0].value })
3、最开始我用的是 reurn com.$el.innerHTML,样式无法生效,各种升级版本都没有用,打印才知道,弹窗最外层的盒子没有了,也就 my-tooltip 类名根本不在里面,会生效才怪!所以,return com.el 就好了。
// return com.$el.innerHTML
return com.$el
最后贴上我的 package.json 吧,因为碰到很多问题都是版本的原因。除了第三种方法我用的 echarts@5.0.0,其他都是 echarts@4.9.0。
{
"name": "my-echarts",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.5",
"echarts": "^4.9.0",
"vue": "^2.6.14",
"vue-router": "^3.2.0",
"vuex": "^3.4.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.15",
"@vue/cli-plugin-eslint": "~4.5.15",
"@vue/cli-plugin-router": "~4.5.15",
"@vue/cli-plugin-vuex": "~4.5.15",
"@vue/cli-service": "~4.5.15",
"@vue/eslint-config-standard": "^5.1.2",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^6.2.2",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"vue-template-compiler": "^2.6.14"
}
}