[TOC]
# DAY19(2025/07/02)Vue+Highchart
## 進度日誌
- 試做圖表互動功能
## 筆記區📘 Vue3
### 試做圖表互動功能
GenderAgeBar.vue
```html
<template>
<div>
<h2>性別與年齡分布</h2>
<highcharts :options="chartOptions" />
</div>
</template>
<script setup>
import { ref, onMounted, watch, inject, getCurrentInstance } from 'vue'
const filters = inject('filters')
const chartOptions = ref({
chart: { type: 'bar', height: 400 },
title: { text: null },
xAxis: { categories: ['<=20', '21~30', '31~40', '41~50', '51~60', '>=61', '未填寫'], title: { text: '年齡' } },
yAxis: { min: 0, title: { text: '人數', align: 'high' } },
legend: { reversed: true },
plotOptions: {
series: {
stacking: 'normal',
cursor: 'pointer',
point: {
events: {
click: function () {
const age = this.category
const gender = this.series.name
// 年齡多選
const ageIdx = filters.age.indexOf(age)
if (ageIdx === -1) filters.age.push(age)
else filters.age.splice(ageIdx, 1)
// 性別多選
const genderIdx = filters.gender.indexOf(gender)
if (genderIdx === -1) filters.gender.push(gender)
else filters.gender.splice(genderIdx, 1)
}
}
}
}
},
series: []
})
let rawData = null
onMounted(async () => {
const res = await fetch('/persona_target_guid.json')
const json = await res.json()
rawData = json.guid_data.find(e => e.類型 === '性別與年齡')
updateChart()
})
function updateChart() {
if (!rawData) return
const categories = ['<=20', '21~30', '31~40', '41~50', '51~60', '>=61', '未填寫']
const genders = filters && filters.gender.length ? filters.gender : ['男', '女', '未填寫']
chartOptions.value.series = genders.map(gender => ({
name: gender,
data: categories.map(k => Number(rawData[`${gender}_${k}`] || 0))
}))
chartOptions.value.xAxis.categories = categories
}
// 監聽 filters 變化
watch(
() => filters ? filters.gender.slice() : [],
updateChart,
{ deep: true }
)
</script>
```
App.vue
```html
<script setup>
import { provide } from 'vue'
import { filters } from './filters'
import GenderAgeBar from './components/GenderAgeBar.vue'
provide('filters', filters)
function toggleGender(gender) {
const idx = filters.gender.indexOf(gender)
if (idx >= 0) filters.gender.splice(idx, 1)
else filters.gender.push(gender)
}
</script>
<template>
<div>
<button @click="toggleGender('男')">男</button>
<button @click="toggleGender('女')">女</button>
<button @click="toggleGender('未填寫')">未填寫</button>
</div>
<GenderAgeBar />
</template>
```
filters.js
```js
import { reactive } from 'vue'
export const filters = reactive({
gender: [], // 例如 ['男', '女']
age: [], // 例如 ['21~30', '31~40']
// 之後你想加城市、日期都可以加在這裡
})
```
main.js
```js
import { createApp } from 'vue'
//import './style.css'
import App from './App.vue'
import HighchartsVue from 'highcharts-vue' // <- 一定要這行
createApp(App).use(HighchartsVue).mount('#app')
```
---
目前結果

目前是直接按下表格內容後「立即」顯示,並非「暫存」後按下篩選紐,進行資料篩選