Vuex進(jìn)行Echarts數(shù)據(jù)頁(yè)面初始化后如何更新dom
需求
子組件只裝載數(shù)據(jù),不進(jìn)行HTTP請(qǐng)求,父組件在created的時(shí)候,拿到數(shù)據(jù)之后,并存入到store中,要求在異步I/O操作之后再重新渲染dom
問(wèn)題描述
子組件為echarts圖表,當(dāng)子組件取數(shù)據(jù)時(shí),由于echarts圖表dom已經(jīng)渲染,異步I/O操作在頁(yè)面渲染之后才會(huì)將數(shù)據(jù)存入store中,使用computed計(jì)算屬性獲取object,初值為{},當(dāng)頁(yè)面渲染完成,計(jì)算得到object不能被watch屬性監(jiān)聽(tīng),故不能將新計(jì)算出數(shù)據(jù)重新渲染并顯示在頁(yè)面中(只針對(duì)echarts初始化渲染dom為初值,數(shù)據(jù)修改之后無(wú)法響應(yīng)式修改的問(wèn)題)
代碼分析
// vuex
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
obj: {
success: 0,
error: 0,
pending: 0
}
},
mutations: {
setObj (state, data) {
state.obj.success = data.success
state.obj.error = data.error
state.obj.pending = data.pending
}
},
actions: {
},
modules: {
}
})子組件
<template>
<div>
i'm test page
<div ref="basicBarChart" style="width:100%;height:350px">
</div>
</div>
</template>
<script>
// import { mapState } from 'vuex'
export default {
data () {
return {
}
},
mounted () {
this.renderBarChart()
},
methods: {
renderBarChart () {
const chart = this.$refs.basicBarChart
const myChart = this.$echarts.init(chart)
if (myChart) {
myChart.setOption({
tooltip: {
trigger: 'item',
formatter: '{a} <br/> : {c} (vvxyksv9kd%)'
},
legend: {
orient: 'vertical',
left: 'left ',
data: ['成功', '失敗', '驗(yàn)證']
},
series: [
{
name: '測(cè)試',
type: 'pie',
radius: '55%',
data: [
{ value: this.obj.success, name: '成功' },
{ value: this.obj.error, name: '失敗' },
{ value: this.obj.pending, name: '驗(yàn)證' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
})
window.addEventListener('resize', function () {
myChart.resize()
})
}
this.$on('hook:destroyed', () => {
window.removeEventListener('resize', function () {
myChart.resize()
})
})
}
},
computed: {
obj () {
return this.$store.state.obj
}
},
watch: {
obj (newVal, oldVal) {
console.log(newVal)
}
}
}
</script>父組件
<template>
<div>
<my-add></my-add>
</div>
</template>
<script>
import add from '@/components/add'
export default {
data () {
return {
}
},
mounted () {
this.getTest()
},
beforeDestroy () {
this.$store.commit('count/setObj', { success: 0, error: 0, pending: 0 })
},
methods: {
async getTest () {
setTimeout(() => {
this.$store.commit('setObj', { success: Math.ceil(Math.random() * 100), error: Math.ceil(Math.random() * 100), pending: Math.ceil(Math.random() * 100) })
}, 2000)
}
},
components: {
'my-add': add
}
}
</script>效果圖如下,可以看到echarts圖表未更新,這里模擬了一個(gè)異步操作,2s之后,父組件才把數(shù)據(jù)寫(xiě)入store中

我們知道,computed屬性的數(shù)據(jù)為響應(yīng)式數(shù)據(jù),那么為什么echarts圖表未更新呢?我們看代碼
<script>
// import { mapState } from 'vuex'
export default {
data () {
return {
}
},
mounted () {
this.renderBarChart()
},
methods: {
renderBarChart () {
}
},
computed: {
obj () {
return this.$store.state.obj
}
}
}
</script>dom渲染之后,也就是mounted的時(shí)候,調(diào)用renderBarChart函數(shù),這個(gè)時(shí)候?qū)om進(jìn)行渲染,而正在這個(gè)時(shí)候,computed計(jì)算出來(lái)的值為初值obj:{success: 0,error: 0,pending: 0},而就在這時(shí)就已經(jīng)渲染dom到頁(yè)面上,而當(dāng)?shù)玫秸嬲臄?shù)據(jù)之后,dom已經(jīng)渲染完成了,而我們使用renderBarChart函數(shù)中的數(shù)據(jù)雖然是響應(yīng)式數(shù)據(jù),但是需要再調(diào)用一次這個(gè)函數(shù)才能重新渲染這個(gè)dom
解決方法
那么如何重新渲染這個(gè)dom呢?
0x1 聲明式渲染&&update鉤子
最簡(jiǎn)單的做法是將變量obj放置在dom中,因?yàn)閛bj為響應(yīng)式數(shù)據(jù),當(dāng)obj在dom里發(fā)生改變,隨即調(diào)用update鉤子,dom被修改,再手動(dòng)調(diào)用renderBarChart函數(shù)將echarts的canvas dom重新渲染
子組件
<template>
<div>
i'm test page
{{obj}}
<div ref="basicBarChart" style="width:100%;height:350px"></div>
</div>
</template>
<script>
export default{
updated(){
this.renderBarChart()
},
// ...略
}
</script>
初始化頁(yè)面

異步I/O得到數(shù)據(jù)之后

當(dāng)然,將數(shù)據(jù)放置在dom中,是很影響美觀的,這時(shí)候可以使用css display:none修飾一下
<div style="display:none">{{obj}}</div>
0x2 深度監(jiān)聽(tīng)
Vue中的watch 方法其實(shí)默認(rèn)寫(xiě)的是handler函數(shù),Vue.js會(huì)去處理這個(gè)邏輯,最終編譯出來(lái)其實(shí)就是這個(gè)handler
Vue 不能檢測(cè)到對(duì)象屬性的添加或刪除。由于 Vue 會(huì)在初始化實(shí)例時(shí)對(duì)屬性執(zhí)行 getter/setter 轉(zhuǎn)化過(guò)程,所以屬性必須在 data 對(duì)象上存在才能讓 Vue 轉(zhuǎn)換它,這樣才能讓它是響應(yīng)的,默認(rèn)情況下 handler 只監(jiān)聽(tīng)obj這個(gè)屬性它的引用的變化,我們只有整個(gè)obj賦值的時(shí)候它才會(huì)監(jiān)聽(tīng)到
如果我們需要監(jiān)聽(tīng)obj里的屬性的值呢?這時(shí)候就要用上deep屬性了
<template>
<div>
i'm test page
{{obj}}
<div ref="basicBarChart" style="width:100%;height:350px"></div>
</div>
</template>
<script>
export default{
// ...略
watch:{
obj:{
handler(newVal,oldVal){
console.log('我準(zhǔn)備調(diào)用renderBarChart函數(shù)了')
this.renderBarChart()
},
deep:true
}
}
}
</script>

深度監(jiān)聽(tīng)肯定是會(huì)消耗資源的,當(dāng)object里內(nèi)嵌object,監(jiān)聽(tīng)器會(huì)一層層的往下遍歷,給對(duì)象的所有屬性都加上這個(gè)監(jiān)聽(tīng)器,任何修改obj里面任何一個(gè)屬性都會(huì)觸發(fā)這個(gè)監(jiān)聽(tīng)器里的 handler
但是這樣不用修改Vuex中的代碼,適合object里屬性少,且無(wú)引用類(lèi)型
0x3 修改obj引用
當(dāng)object的引用發(fā)生變化,那么watch就能監(jiān)聽(tīng)得到object的變化
修改Vuex的代碼
// vuex
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
obj: {}
},
mutations: {
setObj (state, data) {
state.obj = data
}
},
actions: {
},
modules: {
}
})
推薦使用第三種方法,直接修改對(duì)象引用,這樣直接監(jiān)聽(tīng)整個(gè)object比深度監(jiān)聽(tīng)開(kāi)銷(xiāo)更小
以上就是Vuex進(jìn)行Echarts數(shù)據(jù)頁(yè)面初始化后如何更新dom的詳細(xì)內(nèi)容,更多關(guān)于Vuex更新dom的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
如何實(shí)現(xiàn)雙向綁定mvvm的原理實(shí)現(xiàn)
這篇文章主要介紹了vue雙向數(shù)據(jù)綁定原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
vue-router2.0 組件之間傳參及獲取動(dòng)態(tài)參數(shù)的方法
下面小編就為大家?guī)?lái)一篇vue-router2.0 組件之間傳參及獲取動(dòng)態(tài)參數(shù)的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11
vue-auto-focus: 控制自動(dòng)聚焦行為的 vue 指令方法
今天小編就為大家分享一篇vue-auto-focus: 控制自動(dòng)聚焦行為的 vue 指令方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
vue-cli3 打包優(yōu)化之 splitchunks詳解
這篇文章主要介紹了vue-cli3 打包優(yōu)化之 splitchunks的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07
使用WebStorm開(kāi)發(fā)Vue3項(xiàng)目詳細(xì)教程
這篇文章主要介紹了使用WebStorm開(kāi)發(fā)Vue3項(xiàng)目的相關(guān)資料,本文介紹了在WebStorm中使用Vue3、TypeScript、Sass開(kāi)發(fā)項(xiàng)目的配置過(guò)程,包括版本兼容性問(wèn)題、項(xiàng)目搭建、依賴(lài)包安裝、代碼檢查工具配置、運(yùn)行和調(diào)試等步驟,需要的朋友可以參考下2024-11-11
Vue用mixin合并重復(fù)代碼的實(shí)現(xiàn)
這篇文章主要介紹了Vue用mixin合并重復(fù)代碼的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
vue webpack build資源相對(duì)路徑的問(wèn)題及解決方法
這篇文章主要介紹了vue webpack build資源相對(duì)路徑的問(wèn)題,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
vue異步請(qǐng)求數(shù)據(jù)重新渲染方式
這篇文章主要介紹了vue異步請(qǐng)求數(shù)據(jù)重新渲染方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01

