這篇文章帶給大家的內容是關於Vue中用props給data賦初始值時遇到的問題及解決方法,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。
前段時間做一個營運活動的項目,上線後產品回饋頁面埋點不對,在排查過程中發現,問題竟然是由於Vue中的data初始值導致,而data的初始值來自於props。為方便描述,現將問題抽像如下:
一、現象
#程式碼:
nbsp;html> <meta> <title>用props初始化data中变量</title> <script></script> <div> <user-info></user-info> </div> <script> //全局组件 let userInfo = Vue.component('userInfo' ,{ name: 'user-info', props: { userData: Object }, data() { return { userName: this.userData.name } }, template: ` <div> <div>姓名:{{userName}} <div>性别:{{userData.gender}} <div>生日:{{userData.birthday}} ` }); //Vue实例 new Vue({ el: '#app', data: { user: { name: '', gender: '', birthday: '' } }, created(){ this.getUserData(); }, methods:{ getUserData(){ setTimeout(()=>{ this.user = { name: '于永雨', gender: '男', birthday: '1991-7' } }, 500) } }, components: { userInfo } }); </script>
程式碼解讀:
#根元件data中有一個物件:user,包含三個屬性:name、gender、birthday,初始值都為空字串
模擬api非同步請求, 500毫秒後對user的重新賦值,三個屬性都不再為空#聲明一個子元件userInfo,props中有一個物件userData,用於接收父元件的user; data中有一個變數userName,初始值來自於userData.name 結果:
##頁面初始化後,姓名、性別、生日都顯示為空,500毫秒後性別和生日顯示正常結果,僅姓名沒有變化。
為什麼會這樣呢?
我最初的想法:user.name是String,屬於基本資料類型,用它給子元件data中userName賦值,屬於基本資料類型賦值,所以當父元件中user.name變化時,子元件中userName並不會隨之變化。是這樣的嗎?於是我決定將user.name改為對象,透過引用資料類型賦值,然後觀察是否符合預期。程式碼如下:
nbsp;html> <meta> <title>用props初始化data中变量-对象形式</title> <script></script> <div> <user-info></user-info> </div> <script> //全局组件 let userInfo = Vue.component('userInfo' ,{ name: 'user-info', props: { userData: Object }, data() { return { userName: this.userData.name } }, template: ` <div> <div>姓名:{{userName.text}} <div>性别:{{userData.gender}} <div>生日:{{userData.birthday}} ` }); //Vue实例 new Vue({ el: '#app', data: { user: { name: {text: ''}, gender: '', birthday: '' } }, created(){ this.getUserData(); }, methods:{ getUserData(){ setTimeout(()=>{ this.user = { name: {text: '于永雨'}, gender: '男', birthday: '1991-7' } }, 500) } }, components: { userInfo } }); </script>
運行結果:姓名仍然沒有值,和第一次結果一樣! ! !
二、原因那麼,原因到底是什麼呢?百思不得解,後來和朋友討論時,有人提出:會不會因為data在初始化時深拷貝? 我覺得這種解釋比較可靠,於是去收集證據,首先去Vue官網翻了一下關於data的文檔,其中:當看到"遞歸地"那個詞,基本上就能斷定上面的推論是正確的,因為深拷貝的核心原理就是遞歸
。原來,Vue初始化時會遞歸地遍歷data所有的屬性,並使用Object.defineProperty把這些屬性全部轉為getter/setter,用來實現雙向綁定。 官方文件在Reactivity in Depth一章中明確有說:
#還順便解釋了為什麼Vue不支持IE8的原因:IE8不支援Object.defineProperty。 三、解決方法
既然因為data深拷貝的原因,data無法隨著props的變化而更新,我們很自然的就想到Vue中有監聽作用的兩個功能:watch、computed。
修改程式碼如下,觀察結果:nbsp;html> <meta> <title>解决方案:watch、computed</title> <script></script> <div> <user-info></user-info> </div> <script> //全局组件 let userInfo = Vue.component('userInfo' ,{ name: 'user-info', props: { userData: Object }, data() { return { userName: this.userData.name } }, computed: { computedUserName(){ return this.userData.name } }, watch: { 'userData.name': function (val) {//监听props中的属性 this.userName = val; } }, template: ` <div> <div>姓名(watch):{{ userName }} <div>姓名(computed):{{ computedUserName }} <div>性别:{{ userData.gender }} <div>生日:{{ userData.birthday }} ` }); //Vue实例 new Vue({ el: '#app', data: { user: { name: '', gender: '', birthday: '' } }, created(){ this.getUserData(); }, methods:{ getUserData(){ setTimeout(()=>{ this.user = { name: '于永雨', gender: '男', birthday: '1991-7' } }, 500) } }, components: { userInfo } }); </script>
四、總結:關於Vue中props的要點
###事後又仔細翻了一下關於props的文檔:############## #######大概梳理一下:######1.props是單向資料流:父元件的資料變化,透過props即時反應在子元件中,反之不然######2 .不允許在子元件中直接操作props######3.可以變相操作props######(1)在data中宣告局部變量,並用props初始化,###弊端:局部變數不隨著props更新而更新#########(2)在computed中對props值轉換後輸出#########以上是Vue中用props為data賦初始值時遇到的問題及解決方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!