Vuex進(jìn)行Echarts數(shù)據(jù)頁面初始化后如何更新dom
需求
子組件只裝載數(shù)據(jù),不進(jìn)行HTTP請求,父組件在created的時(shí)候,拿到數(shù)據(jù)之后,并存入到store中,要求在異步I/O操作之后再重新渲染dom
問題描述
子組件為echarts圖表,當(dāng)子組件取數(shù)據(jù)時(shí),由于echarts圖表dom已經(jīng)渲染,異步I/O操作在頁面渲染之后才會將數(shù)據(jù)存入store中,使用computed計(jì)算屬性獲取object,初值為{},當(dāng)頁面渲染完成,計(jì)算得到object不能被watch屬性監(jiān)聽,故不能將新計(jì)算出數(shù)據(jù)重新渲染并顯示在頁面中(只針對echarts初始化渲染dom為初值,數(shù)據(jù)修改之后無法響應(yīng)式修改的問題)
代碼分析
// 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: '測試', 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ù)寫入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ì)算出來的值為初值obj:{success: 0,error: 0,pending: 0},而就在這時(shí)就已經(jīng)渲染dom到頁面上,而當(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鉤子
最簡單的做法是將變量obj放置在dom中,因?yàn)閛bj為響應(yīng)式數(shù)據(jù),當(dāng)obj在dom里發(fā)生改變,隨即調(diào)用update鉤子,dom被修改,再手動調(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>
初始化頁面
異步I/O得到數(shù)據(jù)之后
當(dāng)然,將數(shù)據(jù)放置在dom中,是很影響美觀的,這時(shí)候可以使用css display:none修飾一下
<div style="display:none">{{obj}}</div>
0x2 深度監(jiān)聽
Vue中的watch 方法其實(shí)默認(rèn)寫的是handler函數(shù),Vue.js會去處理這個(gè)邏輯,最終編譯出來其實(shí)就是這個(gè)handler
Vue 不能檢測到對象屬性的添加或刪除。由于 Vue 會在初始化實(shí)例時(shí)對屬性執(zhí)行 getter/setter 轉(zhuǎn)化過程,所以屬性必須在 data 對象上存在才能讓 Vue 轉(zhuǎn)換它,這樣才能讓它是響應(yīng)的,默認(rèn)情況下 handler 只監(jiān)聽obj這個(gè)屬性它的引用的變化,我們只有整個(gè)obj賦值的時(shí)候它才會監(jiān)聽到
如果我們需要監(jiān)聽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)聽肯定是會消耗資源的,當(dāng)object里內(nèi)嵌object,監(jiān)聽器會一層層的往下遍歷,給對象的所有屬性都加上這個(gè)監(jiān)聽器,任何修改obj里面任何一個(gè)屬性都會觸發(fā)這個(gè)監(jiān)聽器里的 handler
但是這樣不用修改Vuex中的代碼,適合object里屬性少,且無引用類型
0x3 修改obj引用
當(dāng)object的引用發(fā)生變化,那么watch就能監(jiān)聽得到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: { } })
推薦使用第三種方法,直接修改對象引用,這樣直接監(jiān)聽整個(gè)object比深度監(jiān)聽開銷更小
以上就是Vuex進(jìn)行Echarts數(shù)據(jù)頁面初始化后如何更新dom的詳細(xì)內(nèi)容,更多關(guān)于Vuex更新dom的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
如何實(shí)現(xiàn)雙向綁定mvvm的原理實(shí)現(xiàn)
這篇文章主要介紹了vue雙向數(shù)據(jù)綁定原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05vue-router2.0 組件之間傳參及獲取動態(tài)參數(shù)的方法
下面小編就為大家?guī)硪黄獀ue-router2.0 組件之間傳參及獲取動態(tài)參數(shù)的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11vue-auto-focus: 控制自動聚焦行為的 vue 指令方法
今天小編就為大家分享一篇vue-auto-focus: 控制自動聚焦行為的 vue 指令方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08vue-cli3 打包優(yōu)化之 splitchunks詳解
這篇文章主要介紹了vue-cli3 打包優(yōu)化之 splitchunks的相關(guān)知識,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07使用WebStorm開發(fā)Vue3項(xiàng)目詳細(xì)教程
這篇文章主要介紹了使用WebStorm開發(fā)Vue3項(xiàng)目的相關(guān)資料,本文介紹了在WebStorm中使用Vue3、TypeScript、Sass開發(fā)項(xiàng)目的配置過程,包括版本兼容性問題、項(xiàng)目搭建、依賴包安裝、代碼檢查工具配置、運(yùn)行和調(diào)試等步驟,需要的朋友可以參考下2024-11-11Vue用mixin合并重復(fù)代碼的實(shí)現(xiàn)
這篇文章主要介紹了Vue用mixin合并重復(fù)代碼的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11vue webpack build資源相對路徑的問題及解決方法
這篇文章主要介紹了vue webpack build資源相對路徑的問題,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06