⭐️ 更多前端技術和知識點,搜索訂閱號
JS 菌
訂閱html
問題復現:父組件中經過名爲 source 的 prop 向子組件 Chart 傳入數據前端
<Chart :source="chartData"></Chart>
複製代碼
import Chart from '../components/Chart'
export default {
name: 'Home',
components: { Chart },
data () {
return {
chartData: []
}
},
mounted () {
setTimeout(() => {
this.chartData = [
[89.3, 58212, 'Matcha Latte'],
[57.1, 78254, 'Milk Tea'],
[74.4, 41032, 'Cheese Cocoa'],
[50.1, 12755, 'Cheese Brownie'],
[89.7, 20145, 'Matcha Cocoa'],
[68.1, 79146, 'Tea'],
[19.6, 91852, 'Orange Juice'],
[10.6, 101852, 'Lemon Juice'],
[32.7, 20112, 'Walnut Brownie']
]
}, 2000)
}
}
複製代碼
子組件接收 source 數據當存在且至少有一條數據的時候,建立 id 爲 main 的 div,用以初始化 echarts 實例app
<div v-if="source && source.length" id="main" ref="main" style="width: 600px;height: 400px;"></div>
<div vi-else>none</div>
複製代碼
Chart 組件經過接收數據 watch prop 的變化動態的調用 echarts 的 setOptions 方法,最終渲染數據。echarts
export default {
// ...
watch: {
source (newVal, oldVal) {
this.setOpts()
}
},
props: ['source'],
methods: {
setOpts () {
let myChart = this.$echarts.init(this.$refs.main)
myChart.setOption({
dataset: {
// ...
source: this.source
},
// ...
})
}
}
}
複製代碼
若是直接這麼寫一定報錯:函數
Error in callback for watcher "source": "TypeError: Cannot read property 'getAttribute' of undefined"ui
在代碼中增長一行代碼:this
watch: {
source (newVal, oldVal) {
console.log(newVal, this.$refs.main) // [Array ...] undefined
this.setOpts()
}
},
複製代碼
啓示 source 數據雖然有了,但 div 還並未掛載,所以 echarts 沒法完成初始化spa
那麼想固然的咱們就會去在 mounted 生命週期函數中調用 setOpts 方法:code
mounted () {
console.log(this.source, this.$refs.main) // [] undefined
this.setOpts()
},
複製代碼
這樣也是錯的,由於模板語法中使用了 v-if,那麼當 source 並未知足條件的時候,div 固然也不會掛載。所以 div 仍然沒法訪問到。component
Error in mounted hook: "TypeError: Cannot read property 'getAttribute' of undefined"
解決辦法是要麼去掉 v-if 要麼換另外一種寫法
有時咱們須要在沒有數據的狀況下增長一個佔位標籤用來展現一些額外的提醒信息,如「暫未獲取到數據」等。那麼去掉 v-if 確定不行。
既然如此咱們保留 v-if 但寫法有所改變:
修改 Chart 組件:
<template>
<div>
<div id="main" ref="main" style="width: 600px;height: 400px;"></div>
</div>
</template>
複製代碼
咱們只須要一個 source 數據源,當 mounted 的時候調用 setOpts 方法,當 watch 數據變化的時候再次調用以更新數據
export default {
name: 'Chart',
props: ['source'],
mounted () {
this.setOpts()
},
watch: {
source () {
this.setOpts()
}
},
methods: {
setOpts () {
let myChart = this.$echarts.init(this.$refs.main)
myChart.setOption({
dataset: {
dimensions: ['score', 'amount', 'product'],
source: this.source
},
xAxis: { type: 'category' },
yAxis: {},
series: [
{
type: 'bar',
encode: {
x: 'product',
y: 'amount'
}
}
]
})
}
}
}
複製代碼
v-if 的判斷咱們把他移出去了咱們判斷 chartData 是否獲取到,一旦獲取到數據,立刻加載 Chart 組件,這樣就能夠避開在組件內部調用 v-if 帶來的問題:
<template>
<div>
<Chart :source="chartData" v-if="flag"></Chart>
<div v-else>none</div>
</div>
</template>
複製代碼
import Chart from '../components/Chart'
export default {
name: 'Home',
components: { Chart },
data () {
return {
chartData: [],
flag: false
}
},
methods: {
getData () {
setTimeout(() => {
this.chartData = [
[89.3, 58212, 'Matcha Latte'],
[57.1, 78254, 'Milk Tea'],
[74.4, 41032, 'Cheese Cocoa'],
[50.1, 12755, 'Cheese Brownie'],
[89.7, 20145, 'Matcha Cocoa'],
[68.1, 79146, 'Tea'],
[19.6, 91852, 'Orange Juice'],
[10.6, 101852, 'Lemon Juice'],
[32.7, 20112, 'Walnut Brownie']
]
this.flag = true
}, 2000)
}
},
mounted () {
this.getData()
}
}
複製代碼
另外還可將 Chart 組件和站位標籤一同封裝成一個 ChartWrapper。
這樣就不會因在組件內部調用 watch 監聽 props 的變化動態 v-if 判斷並掛載數據到 DOM 上出現的這種問題了。
請關注個人訂閱號,不按期推送有關 JS 的技術文章,只談技術不談八卦 😊