基于Vue3的Echarts5组件封装支持地图配置,c+v开箱即用。

😊不多逼逼,拒绝废话,直接上代码!

1.支持自动重新set数据,减少非必要的心智负担

2.支持响应式的容器大小改变,自动获取父容器高度

3.可以通过组件对象获取原生api扩展支持

4.支持地图的生成配置及下沉功能

5.自动监听组件的图列点击行为,并通过自定义事件触发

XML 复制代码
<template>
    <div ref="echartsRef" :style="echartsSize"/>
</template>

<script setup lang="ts" name="Echarts">
/**
 * @Description:echarts组件封装
 * @author 莫若省
 * @mail 14462213@qq.com
 * @date 2023/12/29
 */
import type {EChartsType} from "echarts"
import { GeoJSONSourceInput } from 'echarts/types/src/coord/geo/geoTypes';
import * as echarts from 'echarts';
import {onBeforeUnmount, onMounted, reactive, ref, watch} from "vue";
//引入节流函数
import throttle from 'lodash/throttle';
const props = defineProps({
  // 配置项
  options: {
    type: Object,
    default: () => < Record<string, any>>({}),
  },
  // 容器宽高
  width:{
    type:  Number,
    default:0
  },
  // 容器宽高
  height:{
    type:  Number,
    default:0
  },
  //地图名称
  mapName:{
    type:  String,
    default:''
  },
  //地图数据
  mapData: {
    type: Object,
    default: () => <GeoJSONSourceInput>({})
  },
  //是否开启点击事件监听(如果需要自行通过ref获取echarts实例监听事件设置为false)
  openClickEvent:{
    type:  Boolean,
    default:true
  }
})
const emit = defineEmits(['clickEvent'])
// 定义一个ref类型的变量,用于获取DOM元素作为基础容器
const echartsRef = ref<HTMLElement>();
//定义全局的echarts实例
let echartsInstance: EChartsType | null | undefined;
//监视器对象
let obServer: ResizeObserver | null
//当前echarts实例的宽高
const echartsSize = reactive({
  width:props.width + 'px',
  height:props.height + 'px'
})
//设置当前echarts宽高的功能函数
const setEchartsSize = ()=>{
  const width =  props.width || echartsRef.value?.parentElement?.offsetWidth
  const height =  props.height || echartsRef.value?.parentElement?.offsetHeight || 0
  //如果未能获取高度抛出错误
  if(echartsInstance && !height){
    console.error('Did not get the container height, tried to set the container height to 100%, please check the container height is correct!')
  }
  echartsSize.width = width + 'px'
  echartsSize.height = height ? height + 'px' : '100%'
  return {
    width:echartsSize.width,
    height:echartsSize.height
  }
}
/**
 * @Description: echarts初始化函数
 * @author 莫若省
 * @mail 14462213@qq.com
 * @date 2023/12/29
 */
const echartsInit = (echartsContainerDom:HTMLElement)=>{
  // 设置echarts实例宽高
  const domSize = setEchartsSize()
  echartsContainerDom.style.width = domSize.width
  echartsContainerDom.style.height = domSize.height
  //地图配置初始化(需要传入mapName和mapData)
  props.mapName && echarts.registerMap(props.mapName, props.mapData as GeoJSONSourceInput);
  // 基于准备好的dom,初始化echarts实例,如果已经实例化过了就用之前的(单列模式)。
  const echart = echartsInstance ? echartsInstance : echarts.init(echartsContainerDom);
  // 设置配置项
  echart.setOption(props.options)
  //监听点击事件
  props.openClickEvent && echart.on('click',(params)=>{
    emit('clickEvent',params)
  })
  //将组件实例返回
  return echart
}
/**
 * @Description: echarts重新设置配置项的功能函数
 * @author 莫若省
 * @mail 14462213@qq.com
 * @date 2023/12/29
 */
const echartsResetOptions = (newOptions: Record<string, any>)=>(echartsInstance as EChartsType).setOption(newOptions)
/**
 * @Description: echarts监听容器或视口发生改变的功能函数
 * @author 莫若省
 * @mail 14462213@qq.com
 * @date 2023/12/29
 */
const echartsResize = ()=>{
  //重新渲染echarts尺寸的功能函数
  const resizeHandel =()=> {
    (echartsInstance as EChartsType).resize()
    setEchartsSize()
  }
  //监听全局的window对象,当window发生尺寸发生改变时,重新渲染echarts实例
  window.addEventListener('resize',throttle(resizeHandel,1000))
  //如果支持ResizeObserver并且当前echarts实例的父元素存在,那么及监听父容器发生改变时重新渲染echarts实例
  if(ResizeObserver && echartsRef.value!.parentElement) {
     obServer = new ResizeObserver(throttle(() => {
      resizeHandel()
    }, 1000))
    //放入监听对象
    obServer.observe(echartsRef.value!.parentElement as HTMLElement)
  }
  if(!ResizeObserver) console.warn('The current browser does not support ResizeObserver and will not be able to listen for independent changes to the outer container!')
}
/**
 * @Description: 获取当前echarts实例的功能函数
 * @author 莫若省
 * @mail 14462213@qq.com
 * @date 2023/12/29
 */
const  getEchartsInstance = ()=>echartsInstance
onMounted(()=>{
  // 初始化echarts,生成实例对象
  echartsInstance = echartsInit(echartsRef.value! as HTMLElement)
  //开启容器尺寸响应式监测
  echartsResize()
})
onBeforeUnmount(()=>{
  //销毁echarts实例对象
  echartsInstance?.dispose()
  echartsInstance = null
  //移除监听事件
  window.removeEventListener('resize',echartsResize)
  //销毁ResizeObserver实例对象
  obServer?.disconnect()
  obServer = null
})
//监听props的改变
watch(()=>props,()=>{
  if(!echartsInstance){
    console.error('The current component has not been initialized')
    return}
  //进行数据重制
  echartsInit(echartsRef.value! as HTMLElement)
},{
  //开启深度监听
  deep:true,
})
defineExpose({
  // 重新生成配置项的功能函数
  echartsResetOptions,
  // 获取当前echarts实例的功能函数
  getEchartsInstance,
})
</script>
<style scoped lang="scss">
</style>

组件内使用了lodash 大佬可以自行封个节流函数处理,小白可以通过npm/pnpm安装

js 复制代码
pnpm i lodash

属性

Props 类型 默认值 必填
options object {}/配置项 true
width number 0/父容器宽/100% false
height number 0/父容器高/100% false
mapName string ""/(需要使用地图时传入即可) false
mapData object {}/地图信息对象 false
openClickEvent boolean true/(设置为true时,在挂着完毕后自动监听echarts点击事件,可通过自定义事件'clickEvent'触发) false

自定义事件

Event 行参 触发时机
@clickEvent eventPrams(Echarts的点击事件参数) 当图列被点击时

组件实例方法

FnName 实参 返回值
getEchartsInstance null echarts实例对象
echartsResetOptions echarts配置对象 undefined

使用Demo,简单实现地图点击板块自动下沉功能

XML 复制代码
<template>
  <div class="app">
      <ECharts :options="options" map-name="beijing" :map-data="mapData" @click-event="clickEvent"/>
  </div>
</template>

<script setup lang="ts">
import ECharts from "./components/Echarts/index.vue"
import {reactive, ref} from "vue";
import beijingMap from "./components/Echarts/map/beijing.json"

const mapData = ref(beijingMap)
const options = reactive({
  series: [{
    type: 'map',
    map: 'beijing',
  }]
})
const clickEvent = (params: any)=> {
  //获取新的地图信息
  mapData.value.features = mapData.value.features.filter(item => item.properties.name === params.name)
}
</script>
<style lang="scss" scoped>
.app {
  width: 100%;
  height: 100vh;
}
</style>
相关推荐
还是鼠鼠2 小时前
图书管理系统 Axios 源码 __删除图书功能
前端·javascript·vscode·ajax·前端框架·node.js·bootstrap
轻口味2 小时前
Vue.js `Suspense` 和异步组件加载
前端·javascript·vue.js
m0_zj4 小时前
8.[前端开发-CSS]Day08-图形-字体-字体图标-元素定位
前端·css
还是鼠鼠4 小时前
图书管理系统 Axios 源码__编辑图书
前端·javascript·vscode·ajax·前端框架
北极象4 小时前
vue3中el-input无法获得焦点的问题
前端·javascript·vue.js
百度网站快速收录4 小时前
网站快速收录:如何优化网站头部与底部信息?
前端·html·百度快速收录·网站快速收录
Loong_DQX5 小时前
【react+redux】 react使用redux相关内容
前端·react.js·前端框架
GISer_Jing5 小时前
react redux监测值的变化
前端·javascript·react.js
engchina5 小时前
CSS 样式化表格:从基础到高级技巧
前端·css
m0_528723815 小时前
react中useEffect的使用
前端·javascript·react.js