vue3+vite+JS使用Echarts封裝一個(gè)餅圖完整代碼(父子組件聯(lián)動(dòng))
前言
本文要在vue3+vite+JS項(xiàng)目中,使用Echarts封裝一個(gè)餅圖子組件,父組件中引入子組件并傳入數(shù)據(jù)。傳入的數(shù)據(jù)包括標(biāo)題、高度、寬度、餅圖數(shù)據(jù),resize監(jiān)聽(tīng)尺寸。子組件監(jiān)聽(tīng)餅圖數(shù)據(jù)的變化,來(lái)更新子組件的顯示內(nèi)容。

一、實(shí)現(xiàn)思路
- 子組件封裝:基于 ECharts 封裝餅圖組件,接收父組件傳入的標(biāo)題、寬高、餅圖數(shù)據(jù)等 props;
- 響應(yīng)式處理:監(jiān)聽(tīng)餅圖數(shù)據(jù)變化,自動(dòng)更新圖表;監(jiān)聽(tīng)窗口 resize 事件,自適應(yīng)調(diào)整圖表尺寸;
- 父組件使用:導(dǎo)入子組件,傳入自定義數(shù)據(jù),實(shí)現(xiàn)靈活配置。
二、完整代碼實(shí)現(xiàn)
1. 安裝 ECharts 依賴
npm install echarts --save # 或 yarn add echarts
2. 餅圖子組件(PieChart.vue)
<template>
<!-- 圖表容器,寬高由父組件傳入 -->
<div
ref="chartRef"
class="pie-chart-container"
:style="{ width: width + 'px', height: height + 'px' }"
></div>
</template>
<script setup>
import { ref, watch, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
// 定義接收的 props
const props = defineProps({
// 餅圖標(biāo)題
title: {
type: String,
default: '餅圖示例'
},
// 圖表寬度(px)
width: {
type: Number,
default: 400
},
// 圖表高度(px)
height: {
type: Number,
default: 300
},
// 餅圖數(shù)據(jù)(格式:[{ name: '分類1', value: 100 }, ...])
chartData: {
type: Array,
required: true,
validator: (val) => {
// 簡(jiǎn)單校驗(yàn)數(shù)據(jù)格式
return val.every(item => item.hasOwnProperty('name') && item.hasOwnProperty('value'))
}
}
})
// 圖表實(shí)例引用
const chartRef = ref(null)
// ECharts 實(shí)例
let chartInstance = null
// 初始化圖表
const initChart = () => {
// 確保容器存在
if (!chartRef.value) return
// 初始化 ECharts 實(shí)例
chartInstance = echarts.init(chartRef.value)
// 設(shè)置圖表配置項(xiàng)
const option = {
title: {
text: props.title,
left: 'center' // 標(biāo)題居中
},
tooltip: {
trigger: 'item', // 鼠標(biāo)懸浮提示
formatter: '{a}
: {c} (wppm3vysvbp%)' // 提示格式:名稱:數(shù)值(百分比)
},
legend: {
orient: 'vertical', // 圖例垂直排列
left: 'left' // 圖例居左
},
series: [
{
name: props.title,
type: 'pie',
radius: ['40%', '70%'], // 餅圖內(nèi)外半徑
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: 16,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: props.chartData // 餅圖數(shù)據(jù)
}
]
}
// 渲染圖表
chartInstance.setOption(option)
}
// 更新圖表(數(shù)據(jù)變化時(shí)調(diào)用)
const updateChart = () => {
if (!chartInstance) return
// 僅更新數(shù)據(jù)相關(guān)配置,避免重復(fù)初始化
chartInstance.setOption({
title: { text: props.title },
series: [{ data: props.chartData }]
})
}
// 監(jiān)聽(tīng)窗口 resize,自適應(yīng)調(diào)整圖表尺寸
const handleResize = () => {
if (chartInstance) {
chartInstance.resize()
}
}
// 生命周期:掛載時(shí)初始化圖表 + 監(jiān)聽(tīng) resize
onMounted(() => {
initChart()
window.addEventListener('resize', handleResize)
})
// 生命周期:卸載時(shí)銷毀實(shí)例 + 移除監(jiān)聽(tīng)
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose() // 銷毀 ECharts 實(shí)例,釋放內(nèi)存
chartInstance = null
}
window.removeEventListener('resize', handleResize)
})
// 監(jiān)聽(tīng) props 變化,更新圖表
watch(
// 監(jiān)聽(tīng)標(biāo)題、寬高、數(shù)據(jù)的變化
[() => props.title, () => props.width, () => props.height, () => props.chartData],
() => {
// 寬高變化時(shí)先銷毀再重新初始化,數(shù)據(jù)/標(biāo)題變化時(shí)僅更新配置
if (props.width || props.height) {
chartInstance?.dispose()
initChart()
} else {
updateChart()
}
},
{
deep: true // 深度監(jiān)聽(tīng)數(shù)組/對(duì)象變化
}
)
</script>
<style scoped>
.pie-chart-container {
/* 防止容器內(nèi)邊距影響尺寸 */
box-sizing: border-box;
/* 解決圖表容器閃爍問(wèn)題 */
transition: all 0.3s ease;
}
</style>
3. 父組件(ParentPage.vue)
<template>
<div class="parent-page">
<h2>餅圖組件使用示例</h2>
<!-- 操作區(qū):修改數(shù)據(jù)/尺寸 -->
<div class="control-panel">
<button @click="changeChartData">切換餅圖數(shù)據(jù)</button>
<button @click="changeChartSize">修改圖表尺寸</button>
<button @click="changeChartTitle">修改圖表標(biāo)題</button>
</div>
<!-- 引入餅圖子組件,傳入配置 -->
<PieChart
:title="chartTitle"
:width="chartWidth"
:height="chartHeight"
:chart-data="chartData"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 導(dǎo)入餅圖子組件
import PieChart from './PieChart.vue'
// 定義餅圖配置數(shù)據(jù)(響應(yīng)式)
const chartTitle = ref('各部門人數(shù)分布')
const chartWidth = ref(500)
const chartHeight = ref(400)
// 初始餅圖數(shù)據(jù)
const chartData = ref([
{ name: '技術(shù)部', value: 30 },
{ name: '產(chǎn)品部', value: 15 },
{ name: '市場(chǎng)部', value: 20 },
{ name: '財(cái)務(wù)部', value: 8 },
{ name: '人事部', value: 7 }
])
// 模擬:切換餅圖數(shù)據(jù)
const changeChartData = () => {
chartData.value = [
{ name: '技術(shù)部', value: 40 },
{ name: '產(chǎn)品部', value: 10 },
{ name: '市場(chǎng)部', value: 25 },
{ name: '財(cái)務(wù)部', value: 5 },
{ name: '人事部', value: 10 },
{ name: '運(yùn)營(yíng)部', value: 10 } // 新增分類
]
}
// 模擬:修改圖表尺寸
const changeChartSize = () => {
chartWidth.value = 600
chartHeight.value = 450
}
// 模擬:修改圖表標(biāo)題
const changeChartTitle = () => {
chartTitle.value = '各部門人數(shù)分布(更新后)'
}
</script>
<style scoped>
.parent-page {
padding: 20px;
}
.control-panel {
margin-bottom: 20px;
}
.control-panel button {
margin-right: 10px;
padding: 8px 16px;
border: none;
border-radius: 4px;
background: #409eff;
color: #fff;
cursor: pointer;
}
.control-panel button:hover {
background: #66b1ff;
}
</style>
三、關(guān)鍵代碼解釋
子組件核心邏輯:
- props 定義:明確接收標(biāo)題、寬高、餅圖數(shù)據(jù),且對(duì)
chartData做格式校驗(yàn),確保數(shù)據(jù)合法性; - 圖表初始化:
initChart方法創(chuàng)建 ECharts 實(shí)例并配置基礎(chǔ)樣式,updateChart方法僅更新數(shù)據(jù)/標(biāo)題,避免重復(fù)初始化; - 響應(yīng)式監(jiān)聽(tīng):通過(guò)
watch深度監(jiān)聽(tīng) props 變化,寬高變化時(shí)重新初始化圖表,數(shù)據(jù)/標(biāo)題變化時(shí)僅更新配置; - 生命周期管理:
onMounted時(shí)初始化圖表并添加 resize 監(jiān)聽(tīng),onUnmounted時(shí)銷毀 ECharts 實(shí)例、移除監(jiān)聽(tīng),防止內(nèi)存泄漏; - resize 適配:監(jiān)聽(tīng)窗口尺寸變化,調(diào)用
chartInstance.resize()自動(dòng)調(diào)整圖表大小。
- props 定義:明確接收標(biāo)題、寬高、餅圖數(shù)據(jù),且對(duì)
父組件核心邏輯:
- 定義響應(yīng)式數(shù)據(jù)(標(biāo)題、寬高、餅圖數(shù)據(jù)),傳入子組件;
- 提供按鈕模擬數(shù)據(jù)/尺寸/標(biāo)題變化,驗(yàn)證子組件的響應(yīng)式更新能力。
四、使用注意事項(xiàng)
- 數(shù)據(jù)格式:父組件傳入的
chartData必須是[{ name: 'xxx', value: xxx }, ...]格式,子組件已做基礎(chǔ)校驗(yàn); - 內(nèi)存泄漏:子組件在
onUnmounted中銷毀 ECharts 實(shí)例、移除 resize 監(jiān)聽(tīng),避免頁(yè)面卸載后殘留事件; - 自適應(yīng)優(yōu)化:如果需要監(jiān)聽(tīng)父容器尺寸變化(而非窗口),可結(jié)合
element-resize-detector庫(kù)實(shí)現(xiàn); - 樣式適配:子組件容器的寬高使用
px單位,若需百分比,可修改 props 類型為 String(如width: '100%')。
五、封裝總結(jié)
- 子組件封裝了 ECharts 餅圖的核心邏輯,通過(guò) props 接收父組件配置,具備數(shù)據(jù)響應(yīng)式更新、窗口 resize 自適應(yīng)能力;
- 父組件可靈活傳入自定義數(shù)據(jù),通過(guò)修改響應(yīng)式數(shù)據(jù)即可觸發(fā)子組件更新,使用簡(jiǎn)單;
- 關(guān)鍵優(yōu)化點(diǎn):銷毀 ECharts 實(shí)例、移除事件監(jiān)聽(tīng),避免內(nèi)存泄漏;深度監(jiān)聽(tīng)數(shù)據(jù)變化,保證圖表實(shí)時(shí)更新。
到此這篇關(guān)于vue3+vite+JS使用Echarts封裝一個(gè)餅圖(父子組件聯(lián)動(dòng))的文章就介紹到這了,更多相關(guān)vue3+vite+JS用Echarts封裝餅圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Vue3+ts?開(kāi)發(fā)ProTable源碼教程示例
這篇文章主要為大家介紹了使用Vue3+ts?開(kāi)發(fā)ProTable源碼示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
VSCode開(kāi)發(fā)UNI-APP 配置教程及插件
uni-app 是一個(gè)使用 Vue.js 開(kāi)發(fā)所有前端應(yīng)用的框架,今天通過(guò)本文給大家分享VSCode開(kāi)發(fā)UNI-APP 配置教程及插件推薦與注意事項(xiàng),感興趣的朋友一起看看吧2021-08-08
Vue做一個(gè)簡(jiǎn)單的隨機(jī)點(diǎn)名冊(cè)
這篇文章主要介紹的是如何用Vue做一個(gè)簡(jiǎn)單的隨機(jī)點(diǎn)名冊(cè),主要是做個(gè)簡(jiǎn)單的點(diǎn)名器,不做樣式,需要的朋友可以參考一下,希望對(duì)你有所幫助2021-12-12
vue項(xiàng)目build打包后部分樣式錯(cuò)亂的解決
這篇文章主要介紹了vue項(xiàng)目build打包后部分樣式錯(cuò)亂的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
vue中如何實(shí)時(shí)監(jiān)聽(tīng)本地存儲(chǔ)
這篇文章主要介紹了vue中如何實(shí)時(shí)監(jiān)聽(tīng)本地存儲(chǔ),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
VUE對(duì)Storage的過(guò)期時(shí)間設(shè)置,及增刪改查方式
這篇文章主要介紹了VUE對(duì)Storage的過(guò)期時(shí)間設(shè)置,及增刪改查方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02
在Vuex使用dispatch和commit來(lái)調(diào)用mutations的區(qū)別詳解
今天小編就為大家分享一篇在Vuex使用dispatch和commit來(lái)調(diào)用mutations的區(qū)別詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09

