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值转换后输出

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

原文地址:https://www.cnblogs.com/mouseleo/p/11135291.html

时间: 2024-10-18 07:57:41

Vue中用props给data赋初始值遇到的问题解决的相关文章

Bash 什么时候会给 HOME 赋初始值

今天无意发现下面这个表现: $  env -i bash -c cd bash: line 0: cd: HOME not set $ env -i bash -c 'echo $HOME' 这表明了,Bash 只会从环境变量中继承 HOME 变量,从来不自己初始化它?为了证实这个想法,我去翻了下源码,发现其实并不是,在一种情况下,Bash 是会主动初始化 HOME 变量的: if (login_shell == 1 && posixly_correct == 0) set_home_va

(二)用控制器controller给模型数据赋初始值

之前博客,非常easy的就实现了模型数据和页面显示的自己主动绑定.如今我们使用控制器,给模型赋初始值. 假设使用jquery来实现变量赋初值,须要在页面载入完毕后运行$("#target").attr("value",selfValue);使用AngularJS代码例如以下: <!doctype html> <html lang="en" ng-app> <head> <meta charset=&quo

讨论:C#Calendar赋初始值

Q: 我在Page_Load的时候给Calendar赋初始值,但是Page显示之后,Calendar显示是当天(比如今天显示7月12号).我想让它默认显示出我给赋的时间(8/30/2006).我该怎么去设置呢? A: Calendar1.SelectedDate   =   new   DateTime(DateTime.Now. Year,   DateTime.Now.Month,   1);   //将1改成你要设置的天 A: 我的意思是这样:       比如我给它初始化一个10/3/2

C语言赋初始值

add_range局部变量i和sum没有赋初始值,那么i和sum的值具有不确定的值,所以切记要赋初始值.

static 和 final 关键字 对实例变量赋初始值的影响

static 和 final 关键字 对实例变量赋初始值的影响 最近一直在看<深入理解Java虚拟机>,在看完了对象内存分配.Class文件格式之后,想深扒一下实例变量是如何被赋上初始值的这个问题的细节. 在2.3.1小节中讲对象创建的时候,讲到内存分配有两种方式:一种是指针碰撞:另一种是空闲列表. 而选择哪种分配方式是由JAVA堆是否规整决定,而JAVA堆是否规整则由虚拟机所采用的垃圾收集器是否带压缩整理功能决定. 我们不管内存分配采用何种方式,当内存分配完成后,虚拟机将分配到的内存空间都初

jquery给input赋初始值,聚焦时清空

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <script src="js/jquery-1.8.0.

datetime-local设置初始值

//全局变量 var format = ""; //构造符合datetime-local格式的当前日期 function getFormat(){ format = ""; var nTime = new Date(); format += nTime.getFullYear()+"-"; format += (nTime.getMonth()+1)<10?"0"+(nTime.getMonth()+1):(nTime.

js Array 创建具有自定义初始值的数组

在原生js中,创建数组的常见方式有两种:Array() 或 new Array() 和 [] 方式. 构造函数创建数组和字面量定义数组的差异不谈, 当我们需要给创建数组赋初始值时,如果量少的话,可以直接通过 let arr = [2,4] 的方式创建; 而当量大而重复的时候,可以通过以下的方式创建: Array.apply(null,{length:20}).map(()=>2) //(20) [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,

简单模拟IOC容器:为添加了@Autowired的属性赋值(初始值)

创建@Autowired注解 package com.zzj.test; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //设置范围和生存周期 @Target({ElementType.TYPE,ElementType.FI