Vue中用props給data賦初始值遇到的問題解決


Vue中用props給data賦初始值遇到的問題解決

 更新時間:2018年11月27日 10:09:14   作者:yuyongyu    我要評論

 
這篇文章主要介紹了Vue中用props給data賦初始值遇到的問題解決,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

前言

前段時間做一個運營活動的項目,上線后產品反饋頁面埋點不對,在排查過程中發現,問題竟然是由於Vue中的data初始值導致,而data的初始值來自於props。為方便描述,現將問題抽象如下:

一、現象

代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<!DOCTYPE html>
< html lang = "en" >
< head >
   < meta charset = "UTF-8" >
   < title >用props初始化data中變量</ title >
   < script src = "https://cdn.bootcss.com/vue/2.5.16/vue.min.js" ></ script >
</ head >
< body >
< div id = "app" >
   < user-info :user-data = "user" ></ 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 >
         < div >性別:{{userData.gender}}</ div >
         < div >生日:{{userData.birthday}}</ div >
       </ div >
     `
   });
 
   //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 >
</ body >
</ html >

代碼解讀:

  • 根組件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改為對象,通過引用數據類型賦值,然后觀察是否符合預期。代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<!DOCTYPE html>
< html lang = "en" >
< head >
   < meta charset = "UTF-8" >
   < title >用props初始化data中變量-對象形式</ title >
   < script src = "https://cdn.bootcss.com/vue/2.5.16/vue.min.js" ></ script >
</ head >
< body >
< div id = "app" >
   < user-info :user-data = "user" ></ 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 >
         < div >性別:{{userData.gender}}</ div >
         < div >生日:{{userData.birthday}}</ div >
       </ div >
     `
   });
 
 
   //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 >
</ body >
</ html >

運行結果:姓名仍然沒有值,和第一次結果一樣!!!

二、原因

那么,原因到底是什么呢?百思不得解,后來和小伙伴們討論時,有人提出:會不會因為data在初始化時深拷貝?

我覺得這種解釋比較靠譜,於是去收集證據,首先去Vue官網翻了一下關於data的文檔,其中:

當看到"遞歸地"那個詞,基本上就能斷定上面的推論是正確的,因為深拷貝的核心原理就是遞歸。

原來,Vue初始化時會遞歸地遍歷data所有的屬性,並使用Object.defineProperty把這些屬性全部轉為getter/setter,用於實現雙向綁定。官方文檔在Reactivity in Depth一章明確有說:

還順便解釋了一下為什么Vue不支持IE8的原因:IE8不支持Object.defineProperty。

三、解決辦法

既然因為data深拷貝的原因,data無法隨着props的變化而更新,我們很自然的就想到Vue中有監聽作用的兩個功能:watch、computed。

修改代碼如下,觀察結果:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<!DOCTYPE html>
< html lang = "en" >
< head >
   < meta charset = "UTF-8" >
   < title >解決方案:watch、computed</ title >
   < script src = "https://cdn.bootcss.com/vue/2.5.16/vue.min.js" ></ script >
</ head >
< body >
< div id = "app" >
   < user-info :user-data = "user" ></ 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 >
         < div >姓名(computed):{{ computedUserName }}</ div >
         < div >性別:{{ userData.gender }}</ div >
         < div >生日:{{ userData.birthday }}</ div >
       </ div >
     `
   });
 
 
   //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 >
</ body >
</ html >

運行結果

完美!!!

四、總結:關於Vue中props的要點

事后又仔細翻了一下關於props的文檔:

大概梳理一下:

1.props是單向數據流:父組件的數據變化,通過props實時反應在子組件中,反之不然

2.不允許在子組件中直接操作props

3.可以變相操作props

(1)在data中聲明局部變量,並用props初始化,弊端:局部變量不隨着props更新而更新

(2)在computed中對props值轉換后輸出

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM