vue3封裝echarts組件的實(shí)現(xiàn)步驟
1、引言
在現(xiàn)代Web應(yīng)用開發(fā)中,數(shù)據(jù)可視化已成為不可或缺的一部分。ECharts,作為一款強(qiáng)大的圖表庫,提供了豐富的圖表類型和高度定制化的選項(xiàng),深受開發(fā)者喜愛。然而,在Vue項(xiàng)目中直接使用ECharts可能會遇到狀態(tài)管理、響應(yīng)式更新和組件化封裝的挑戰(zhàn)。本文將介紹如何在Vue3中封裝一個(gè)高效、可復(fù)用的ECharts組件——TChart。
2、組件亮點(diǎn)
- 響應(yīng)式圖表:自動(dòng)調(diào)整大小以適應(yīng)容器。
- 空數(shù)據(jù)展示:支持自定義空數(shù)據(jù)狀態(tài)顯示。
- 事件監(jiān)聽:自動(dòng)綁定和解綁圖表事件。
- 主題切換:動(dòng)態(tài)改變圖表主題。
- 性能優(yōu)化:通過防抖函數(shù)減少不必要的渲染和資源消耗。
3、技術(shù)棧
- Vue 3: 使用Composition API進(jìn)行狀態(tài)管理和邏輯組織。
- ECharts: 數(shù)據(jù)可視化核心庫。
- VueUse: 提供
useResizeObserver等實(shí)用工具函數(shù)。
4、組件結(jié)構(gòu)
TChart組件的核心在于其模板和腳本部分:
- 模板:包含圖表容器和空數(shù)據(jù)狀態(tài)展示插槽。
- 腳本:
- 初始化圖表并設(shè)置選項(xiàng)。
- 監(jiān)聽窗口和圖表容器尺寸變化,實(shí)現(xiàn)響應(yīng)式布局。
- 自動(dòng)綁定和解綁圖表事件。
- 支持動(dòng)態(tài)主題切換和選項(xiàng)更新。
5、實(shí)現(xiàn)步驟
5.1 安裝echarts
npm install echarts
5.2 注冊echarts
并在 main 文件中注冊使用
import * as echarts from "echarts" // 引入echarts app.config.globalProperties.$echarts = echarts // 全局使用
5.3 新建TChart組件
~components/TCharts.vue
<template>
<div class="t-chart" v-bind="$attrs">
<div
v-show="!formatEmpty"
class="t-chart-container"
:id="id"
ref="echartRef"
/>
<slot v-if="formatEmpty" name="empty">
<el-empty v-bind="$attrs" :description="description" />
</slot>
<slot></slot>
</div>
</template>
<script setup lang="ts" name="TChart">
import {
onMounted,
getCurrentInstance,
ref,
watch,
nextTick,
onBeforeUnmount,
markRaw,
useAttrs,
} from 'vue'
import { useResizeObserver } from '@vueuse/core'
import { debounce, toLine } from '../../utils'
import { computed } from 'vue'
const { proxy } = getCurrentInstance() as any
const props = defineProps({
options: {
type: Object,
default: () => ({}),
},
id: {
type: String,
default: () => Math.random().toString(36).substring(2, 8),
},
theme: {
type: String,
default: '',
},
isEmpty: {
type: [Boolean, Function],
default: false,
},
description: {
type: String,
default: '暫無數(shù)據(jù)',
},
})
const echartRef = ref<HTMLDivElement>()
const chart = ref()
const emits = defineEmits()
const events = Object.entries(useAttrs())
// 圖表初始化
const renderChart = () => {
chart.value = markRaw(proxy.$echarts.init(echartRef.value, props.theme))
setOption(props.options)
// 返回chart實(shí)例
emits('chart', chart.value)
// 監(jiān)聽圖表事件
events.forEach(([key, value]) => {
if (key.startsWith('on') && !key.startsWith('onChart')) {
const on = toLine(key).substring(3)
chart.value.on(on, (...args) => emits(on, ...args))
}
})
// 監(jiān)聽元素變化
useResizeObserver(echartRef.value, resizeChart)
// 如果不想用vueuse,可以使用下邊的方法代替,但組件使用v-show時(shí),不會觸發(fā)resize事件
// window.addEventListener('resize', resizeChart)
}
// 重繪圖表函數(shù)
const resizeChart = debounce(
() => {
chart.value?.resize()
},
300,
true
)
// 設(shè)置圖表函數(shù)
const setOption = debounce(
async (data) => {
if (!chart.value) return
chart.value.setOption(data, true, true)
await nextTick()
resizeChart()
},
300,
true
)
const formatEmpty = computed(() => {
if (typeof props.isEmpty === 'function') {
return props.isEmpty(props.options)
}
return props.isEmpty
})
watch(
() => props.options,
async (nw) => {
await nextTick()
setOption(nw)
},
{ deep: true }
)
watch(
() => props.theme,
async () => {
chart.value.dispose()
renderChart()
}
)
onMounted(() => {
renderChart()
})
onBeforeUnmount(() => {
// 取消監(jiān)聽
// window.removeEventListener('resize', resizeChart)
// 銷毀echarts實(shí)例
chart.value.dispose()
chart.value = null
})
</script>
<style lang="scss" scoped>
.t-chart {
position: relative;
width: 100%;
height: 100%;
&-container {
width: 100%;
height: 100%;
}
}
</style>
utils/index.ts
type Func = (...args: any[]) => any
/**
* 防抖函數(shù)
* @param { Function } func 函數(shù)
* @param { Number } delay 防抖時(shí)間
* @param { Boolean } immediate 是否立即執(zhí)行
* @param { Function } resultCallback
*/
export function debounce(
func: Func,
delay: number = 500,
immediate?: boolean,
resultCallback?: Func
) {
let timer: null | ReturnType<typeof setTimeout> = null
let isInvoke = false
const _debounce = function (this: unknown, ...args: any[]) {
return new Promise((resolve, reject) => {
if (timer) clearTimeout(timer)
if (immediate && !isInvoke) {
try {
const result = func.apply(this, args)
if (resultCallback) resultCallback(result)
resolve(result)
} catch (e) {
reject(e)
}
isInvoke = true
} else {
timer = setTimeout(() => {
try {
const result = func.apply(this, args)
if (resultCallback) resultCallback(result)
resolve(result)
} catch (e) {
reject(e)
}
isInvoke = false
timer = null
}, delay)
}
})
}
_debounce.cancel = function () {
if (timer) clearTimeout(timer)
isInvoke = false
timer = null
}
return _debounce
}
/**
* 節(jié)流函數(shù)
* @param { Function } func
* @param { Boolean } interval
* @param { Object } options
* leading:初始 trailing:結(jié)尾
*/
export function throttle(
func: Func,
interval: number,
options = { leading: false, trailing: true }
) {
let timer: null | ReturnType<typeof setTimeout> = null
let lastTime = 0
const { leading, trailing } = options
const _throttle = function (this: unknown, ...args: any[]) {
const nowTime = Date.now()
if (!lastTime && !leading) lastTime = nowTime
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer)
timer = null
}
lastTime = nowTime
func.apply(this, args)
}
if (trailing && !timer) {
timer = setTimeout(() => {
lastTime = !leading ? 0 : Date.now()
timer = null
func.apply(this, args)
}, remainTime)
}
}
_throttle.cancel = function () {
if (timer) clearTimeout(timer)
timer = null
lastTime = 0
}
return _throttle
}
/**
* 駝峰轉(zhuǎn)換下劃線
* @param { String } name
*/
export function toLine(name: string) {
return name.replace(/([A-Z])/g, '_$1').toLowerCase()
}
6、使用組件
6.1使用示例
<template>
<div>
<el-button @click="isShow = !isShow">{{
isShow ? '隱藏' : '顯示'
}}</el-button>
<el-button @click="addData()">增加數(shù)據(jù)</el-button>
<t-chart
v-show="isShow"
:options="options"
style="width: 100%; height: 500px"
@click="click"
@dblclick="addData()"
@mousedown="mousedown"
@mousemove="mousemove"
@mouseover="mouseover"
@mouseout="mouseout"
@globalout="globalout"
@contextmenu="contextmenu"
@chart="chart"
/>
</div>
</template>
<script setup lang="ts">
import TChart from '../components/TChart'
import { ref } from 'vue'
const options = ref({
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
yAxis: {
type: 'value',
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line',
},
],
})
const isShow = ref(true)
const addData = () => {
options.value.xAxis.data.push(
'test' + Math.random().toString(36).substring(2, 8)
)
options.value.series[0].data.push(Math.random() * 200)
}
const click = (e) => {
console.log('click-----', e)
}
const mousedown = (e) => {
console.log('mousedown-----', e)
}
const mousemove = (e) => {
console.log('mousemove-----', e)
}
const mouseover = (e) => {
console.log('mouseover-----', e)
}
const mouseout = (e) => {
console.log('mouseout-----', e)
}
const globalout = (e) => {
console.log('globalout-----', e)
}
const contextmenu = (e) => {
console.log('contextmenu-----', e)
}
const chartRef = ref(null)
const chart = (dom) => {
chartRef.value = dom
}
</script>
6.2效果圖



更多使用示例,可以看看文檔 TChart 圖表
深入淺出---封裝思路
接下來,我想和大家聊一下封裝思路。首先,封裝一個(gè)組件,我需要考慮什么,從哪方面考慮,讓我們看看ai的回答
封裝組件是前端開發(fā)中的一種常見實(shí)踐,它有助于提高代碼的復(fù)用性、可維護(hù)性和可讀性。在進(jìn)行組件封裝時(shí),應(yīng)遵循以下原則:
- 單一職責(zé)原則:一個(gè)組件應(yīng)該只負(fù)責(zé)一項(xiàng)功能,這樣可以保證組件的簡潔和可復(fù)用性。
- 高內(nèi)聚低耦合:組件內(nèi)部的功能應(yīng)該緊密相關(guān)(高內(nèi)聚),而組件之間的依賴關(guān)系應(yīng)該盡量減少(低耦合)。這有助于提高組件的獨(dú)立性和靈活性。
- 明確的輸入輸出:組件應(yīng)該有清晰的輸入(props)和輸出(state變化或事件)。這有助于其他開發(fā)者理解組件的使用方式。
- 可復(fù)用性:設(shè)計(jì)組件時(shí)應(yīng)考慮到其復(fù)用性,避免硬編碼特定場景的邏輯,使得組件可以在多種場景下使用。
- 可測試性:組件應(yīng)當(dāng)易于測試,可以通過單元測試和集成測試驗(yàn)證其功能。避免在組件中使用過多的全局狀態(tài)或復(fù)雜的異步操作,以降低測試難度。
- 響應(yīng)式設(shè)計(jì):組件應(yīng)該能夠根據(jù)屏幕尺寸和其他環(huán)境因素自動(dòng)調(diào)整布局和樣式,提供良好的用戶體驗(yàn)。
- 文檔和注釋:為組件編寫詳細(xì)的文檔和注釋,說明組件的用途、輸入?yún)?shù)、返回值和使用示例,幫助其他開發(fā)者快速理解和使用組件。
- 性能優(yōu)化:在可能的情況下,對組件進(jìn)行性能優(yōu)化,如使用虛擬DOM、避免不必要的重渲染等,提高應(yīng)用的運(yùn)行效率。
- 一致性:保持組件風(fēng)格和行為的一致性,遵循項(xiàng)目的編碼規(guī)范和設(shè)計(jì)指南,提高整體的代碼質(zhì)量和用戶體驗(yàn)。
- 模塊化:將大型組件分解成多個(gè)小的、可組合的子組件,每個(gè)子組件負(fù)責(zé)一部分功能,通過組合這些子組件來構(gòu)建更復(fù)雜的組件。
遵循這些原則可以幫助你創(chuàng)建出高質(zhì)量、可維護(hù)的組件,從而提升整個(gè)項(xiàng)目的開發(fā)效率和代碼質(zhì)量。
基于上邊的原則,我們再考慮下封裝echarts的實(shí)現(xiàn)。
接下來,我們來看一下官方的示例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>ECharts</title>
<!-- 引入剛剛下載的 ECharts 文件 -->
<script src="echarts.js"></script>
</head>
<body>
<!-- 為 ECharts 準(zhǔn)備一個(gè)定義了寬高的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于準(zhǔn)備好的dom,初始化echarts實(shí)例
var myChart = echarts.init(document.getElementById('main'));
// 指定圖表的配置項(xiàng)和數(shù)據(jù)
var option = {
title: {
text: 'ECharts 入門示例'
},
tooltip: {},
legend: {
data: ['銷量']
},
xAxis: {
data: ['襯衫', '羊毛衫', '雪紡衫', '褲子', '高跟鞋', '襪子']
},
yAxis: {},
series: [
{
name: '銷量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};
// 使用剛指定的配置項(xiàng)和數(shù)據(jù)顯示圖表。
myChart.setOption(option);
</script>
</body>
</html>實(shí)現(xiàn)的步驟的步驟有哪些?
- 引入echarts
- 定義一個(gè)DOM元素(容器)
- 獲取DOM元素(容器)并初始化echarts實(shí)例
- 指定圖表的配置項(xiàng)和數(shù)據(jù)
- 使用剛指定的配置項(xiàng)和數(shù)據(jù)顯示圖表。
每當(dāng)我想使用echarts組件時(shí),都得經(jīng)過這五個(gè)步驟。當(dāng)我想實(shí)現(xiàn)多個(gè)圖表時(shí),這多個(gè)圖表對比起來,哪些是步驟是變化的?哪些的不變的?
細(xì)心的網(wǎng)友會發(fā)現(xiàn),其中,變化最多的,是第四個(gè)步驟“圖表的配置項(xiàng)和數(shù)據(jù)”。那我,是不是可以將這些重復(fù)性的操作,封裝到組件里,讓組件替我去完成。
接下來,讓我們來一步一步實(shí)現(xiàn)代碼
1.基本功能
1.1準(zhǔn)備DOM元素(容器)
<template>
<div class="t-chart" v-bind="$attrs">
<div v-show="!formatEmpty" class="t-chart" :id="id" ref="echartRef" />
</template>
<style lang="scss" scoped>
.t-chart {
width: 100%;
height: 100%;
}
</style>
1.2 獲取容器并初始化echarts實(shí)例
優(yōu)化小技巧:通過ref獲取dom實(shí)例比document操作獲取dom,性能更好
<template>
<div class="t-chart" v-bind="$attrs">
<div v-show="!formatEmpty" class="t-chart" :id="id" ref="echartRef" />
</template>
<script setup lang="ts" name="TChart">
import { onMounted, getCurrentInstance, ref, markRaw } from "vue"
const { proxy } = getCurrentInstance() as any
const props = defineProps({
options: {
type: Object,
default: () => ({})
},
id: {
type: String,
default: () => Math.random().toString(36).substring(2, 8)
}
})
const echartRef = ref<HTMLDivElement>()
const chart = ref()
// 圖表初始化
const renderChart = () => {
chart.value = markRaw(proxy.$echarts.init(echartRef.value))
}
onMounted(() => {
renderChart()
})
</script>
<style lang="scss" scoped>
.t-chart {
width: 100%;
height: 100%;
}
</style>1.3 設(shè)置配置項(xiàng)和數(shù)據(jù)
<template>
<div class="t-chart" v-bind="$attrs">
<div v-show="!formatEmpty" class="t-chart" :id="id" ref="echartRef" />
</template>
<script setup lang="ts" name="TChart">
import { onMounted, getCurrentInstance, ref, markRaw } from "vue"
const { proxy } = getCurrentInstance() as any
const props = defineProps({
options: {
type: Object,
default: () => ({})
},
id: {
type: String,
default: () => Math.random().toString(36).substring(2, 8)
}
})
const echartRef = ref<HTMLDivElement>()
const chart = ref()
// 圖表初始化
const renderChart = () => {
chart.value = markRaw(proxy.$echarts.init(echartRef.value))
setOption(props.options)
}
// 設(shè)置圖表函數(shù)
const setOption = data => {
chart.value.setOption(data, true, true)
chart.value?.resize()
}
onMounted(() => {
renderChart()
})
</script>
<style lang="scss" scoped>
.t-chart {
width: 100%;
height: 100%;
}
</style>2.組件要實(shí)現(xiàn)的功能
很多時(shí)候,封裝封裝組件,并不是一次性就能做到很完美的狀態(tài),而是在使用中, 不斷去優(yōu)化,取改進(jìn)的。比如,在使用中,數(shù)據(jù)更新、頁面大小變化時(shí),圖表沒有重新渲染、echart事件沒有觸發(fā)。這些都是一點(diǎn)點(diǎn)去優(yōu)化改進(jìn)的。記住一個(gè)準(zhǔn)則:“先實(shí)現(xiàn)再優(yōu)化”
- 響應(yīng)式圖表
- 圖表尺寸的自適應(yīng)
- 事件監(jiān)聽
- 性能優(yōu)化
- 空數(shù)據(jù)展示
- 插槽
- 主題切換
- 獲取echarts實(shí)例
3.響應(yīng)式圖表
希望數(shù)據(jù)變化時(shí),可以重新繪制圖表
// 重繪圖表函數(shù)
const resizeChart = debounce(
() => {
chart.value?.resize()
},
300,
true
)
// 設(shè)置圖表函數(shù)
const setOption = debounce(
async data => {
if (!chart.value) return
chart.value.setOption(data, true, true)
await nextTick()
resizeChart()
},
300,
true
)
const formatEmpty = computed(() => {
if (typeof props.isEmpty === "function") {
return props.isEmpty(props.options)
}
return props.isEmpty
})
// 監(jiān)聽數(shù)據(jù)變化時(shí),重繪
watch(
() => props.options,
async nw => {
await nextTick()
setOption(nw)
},
{ deep: true }
)4.圖表尺寸的自適應(yīng)
希望容器尺寸變化時(shí),圖表能夠自適應(yīng)
筆者這邊使用了vueuse的useResizeObserver,來實(shí)現(xiàn)對元素變化的監(jiān)聽,為什么沒用resize? 是因?yàn)槠渲杏锌印?/p>
1、window大小變化時(shí),才會觸發(fā)監(jiān)聽
2、使用組件使用v-show的時(shí)候,不會觸發(fā),可能會蜷縮在一團(tuán)

import { useResizeObserver } from "@vueuse/core"
const renderChart = () => {
chart.value = markRaw(proxy.$echarts.init(echartRef.value, props.theme))
setOption(props.options)
// 監(jiān)聽元素變化
useResizeObserver(echartRef.value, resizeChart)
// 大小自適應(yīng)
// window.addEventListener('resize', resizeChart)
}
onBeforeUnmount(() => {
// 取消監(jiān)聽
// window.removeEventListener('resize', resizeChart)
})5.事件監(jiān)聽
通過useAttrs,拿到父組件傳過來的事件,并批量注冊emits事件
const events = Object.entries(useAttrs())
// 監(jiān)聽圖表事件
events.forEach(([key, value]) => {
if (key.startsWith('on') && !key.startsWith('onChart')) {
const on = toLine(key).substring(3)
chart.value.on(on, (...args) => emits(on, ...args))
}
})
6.性能優(yōu)化
- 通過markRaw,將echarts實(shí)例標(biāo)記為普通對象,減少響應(yīng)式帶來的損耗。
- 防抖函數(shù),用于圖表重繪和選項(xiàng)更新,減少不必要的調(diào)用,提高性能。
- 當(dāng)組件被銷毀時(shí),調(diào)用 dispose 方法銷毀實(shí)例,防止可能的內(nèi)存泄漏。
chart.value = markRaw(proxy.$echarts.init(echartRef.value, props.theme))
// 重繪圖表函數(shù)
const resizeChart = debounce(
() => {
chart.value?.resize()
},
300,
true
)
// 設(shè)置圖表函數(shù)
const setOption = debounce(
async data => {
if (!chart.value) return
chart.value.setOption(data, true, true)
await nextTick()
resizeChart()
},
300,
true
)
onBeforeUnmount(() => {
// 銷毀echarts實(shí)例
chart.value.dispose()
chart.value = null
})6.空數(shù)據(jù)展示
組件可以通過isEmpty,來設(shè)置echarts圖表空狀態(tài),類型可以是Boolean,也可以是個(gè)函數(shù),方便靈活調(diào)用,還可以設(shè)置description,空數(shù)據(jù)時(shí)的展示文字

<template>
<div class="t-chart" v-bind="$attrs">
<div
v-show="!formatEmpty"
class="t-chart-container"
:id="id"
ref="echartRef"
/>
<slot v-if="formatEmpty" name="empty">
<el-empty v-bind="$attrs" :description="description" />
</slot>
<slot></slot>
</div>
</template>
<script setup lang="ts" name="TChart">
const props = defineProps({
isEmpty: {
type: [Boolean, Function],
default: false,
},
description: {
type: String,
default: '暫無數(shù)據(jù)',
},
})
const formatEmpty = computed(() => {
if (typeof props.isEmpty === 'function') {
return props.isEmpty(props.options)
}
return props.isEmpty
})
...
</script>7.插槽
可以通過插槽,在組件內(nèi)增加內(nèi)容,也可以替換空狀態(tài)的內(nèi)容

<template>
<div class="t-chart" v-bind="$attrs">
<div
v-show="!formatEmpty"
class="t-chart-container"
:id="id"
ref="echartRef"
/>
<slot v-if="formatEmpty" name="empty">
<el-empty v-bind="$attrs" :description="description" />
</slot>
<slot></slot>
</div>
</template>
<style lang="scss" scoped>
.t-chart {
position: relative;
width: 100%;
height: 100%;
&-container {
width: 100%;
height: 100%;
}
}
</style>
8.主題切換
監(jiān)聽props的主題,動(dòng)態(tài)切換echarts 主題

const props = defineProps({
theme: {
type: String,
default: '',
}
})
// 圖表初始化
const renderChart = () => {
chart.value = markRaw(proxy.$echarts.init(echartRef.value, props.theme))
// ...
}
watch(
() => props.theme,
async () => {
chart.value.dispose()
renderChart()
}
)9.獲取echarts實(shí)例
注冊了echarts實(shí)例后,將實(shí)例返回給父組件
chart.value = markRaw(proxy.$echarts.init(echartRef.value, props.theme))
// 返回chart實(shí)例
emits('chart', chart.value)完整代碼
具體的,可以回看5.3 新建TChart組件
<template>
<div class="t-chart" v-bind="$attrs">
<div
v-show="!formatEmpty"
class="t-chart-container"
:id="id"
ref="echartRef"
/>
<slot v-if="formatEmpty" name="empty">
<el-empty v-bind="$attrs" :description="description" />
</slot>
<slot></slot>
</div>
</template>
<script setup lang="ts" name="TChart">
import {
onMounted,
getCurrentInstance,
ref,
watch,
nextTick,
onBeforeUnmount,
markRaw,
useAttrs,
} from 'vue'
import { useResizeObserver } from '@vueuse/core'
import { debounce, toLine } from '../../utils'
import { computed } from 'vue'
const { proxy } = getCurrentInstance() as any
const props = defineProps({
options: {
type: Object,
default: () => ({}),
},
id: {
type: String,
default: () => Math.random().toString(36).substring(2, 8),
},
theme: {
type: String,
default: '',
},
isEmpty: {
type: [Boolean, Function],
default: false,
},
description: {
type: String,
default: '暫無數(shù)據(jù)',
},
})
const echartRef = ref<HTMLDivElement>()
const chart = ref()
const emits = defineEmits()
const events = Object.entries(useAttrs())
// 圖表初始化
const renderChart = () => {
chart.value = markRaw(proxy.$echarts.init(echartRef.value, props.theme))
setOption(props.options)
// 返回chart實(shí)例
emits('chart', chart.value)
// 監(jiān)聽圖表事件
events.forEach(([key, value]) => {
if (key.startsWith('on') && !key.startsWith('onChart')) {
const on = toLine(key).substring(3)
chart.value.on(on, (...args) => emits(on, ...args))
}
})
// 監(jiān)聽元素變化
useResizeObserver(echartRef.value, resizeChart)
// 大小自適應(yīng)
// window.addEventListener('resize', resizeChart)
}
// 重繪圖表函數(shù)
const resizeChart = debounce(
() => {
chart.value?.resize()
},
300,
true
)
// 設(shè)置圖表函數(shù)
const setOption = debounce(
async (data) => {
if (!chart.value) return
chart.value.setOption(data, true, true)
await nextTick()
resizeChart()
},
300,
true
)
const formatEmpty = computed(() => {
if (typeof props.isEmpty === 'function') {
return props.isEmpty(props.options)
}
return props.isEmpty
})
watch(
() => props.options,
async (nw) => {
await nextTick()
setOption(nw)
},
{ deep: true }
)
watch(
() => props.theme,
async () => {
chart.value.dispose()
renderChart()
}
)
onMounted(() => {
renderChart()
})
onBeforeUnmount(() => {
// 取消監(jiān)聽
// window.removeEventListener('resize', resizeChart)
// 銷毀echarts實(shí)例
chart.value.dispose()
chart.value = null
})
</script>
<style lang="scss" scoped>
.t-chart {
position: relative;
width: 100%;
height: 100%;
&-container {
width: 100%;
height: 100%;
}
}
</style>
最后看看是否符合組件的設(shè)計(jì)原則

以上,就是我實(shí)現(xiàn)echarts組件的思路。
總結(jié)
到此這篇關(guān)于vue3封裝echarts組件的文章就介紹到這了,更多相關(guān)vue3封裝echarts組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue實(shí)現(xiàn)上拉加載下一頁效果的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Vue實(shí)現(xiàn)上拉加載下一頁效果,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Vue有一定幫助,需要的可以參考一下2022-08-08
如何封裝了一個(gè)vue移動(dòng)端下拉加載下一頁數(shù)據(jù)的組件
這篇文章主要介紹了如何封裝了一個(gè)vue移動(dòng)端下拉加載下一頁數(shù)據(jù)的組件,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01
詳解vue之自行實(shí)現(xiàn)派發(fā)與廣播(dispatch與broadcast)
這篇文章主要介紹了詳解vue之自行實(shí)現(xiàn)派發(fā)與廣播(dispatch與broadcast),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
el-table樹形數(shù)據(jù)量過大,導(dǎo)致頁面卡頓問題及解決
這篇文章主要介紹了el-table樹形數(shù)據(jù)量過大,導(dǎo)致頁面卡頓問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04
vue實(shí)現(xiàn)導(dǎo)出excel的多種方式總結(jié)
在Vue中實(shí)現(xiàn)導(dǎo)出Excel有多種方式,可以通過前端實(shí)現(xiàn),也可以通過前后端配合實(shí)現(xiàn),這篇文章將為大家詳細(xì)介紹幾種常用的實(shí)現(xiàn)方式,需要的可以參考下2023-08-08

