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

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

 

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

  1. [转]Vue中用props给data赋初始值遇到的问题解决

    原文地址:https://segmentfault.com/a/1190000017149162 2018-11-28更:文章发布后因为存在理解错误,经@Kim09AI同学提醒后做了调整,在此深表感谢 ...

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

    今天无意发现下面这个表现: $  env -i bash -c cd bash: line 0: cd: HOME not set $ env -i bash -c 'echo $HOME' 这表明了 ...

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

    static 和 final 关键字 对实例变量赋初始值的影响 最近一直在看<深入理解Java虚拟机>,在看完了对象内存分配.Class文件格式之后,想深扒一下实例变量是如何被赋上初始值的 ...

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

    之前博客,非常easy的就实现了模型数据和页面显示的自己主动绑定.如今我们使用控制器,给模型赋初始值. 假设使用jquery来实现变量赋初值,须要在页面载入完毕后运行$("#target&q ...

  5. C语言赋初始值

  6. vector 赋初始值的问题

    这个,输出为1 这个,啥都输不出来. 据说是因为没有初始化. 其实我搜了一下 vector<vector<int> > A;//正确的定义方式 vector<vector ...

  7. vue & modal props & form data update bug

    vue & modal props & form data update bug OK <div> <BindModal :dialogBindVisible=&qu ...

  8. DropdownList 赋初始值问题

    网上查了这样的代码 虽然是可以用.但是会点击多次会出现”“ dropdownList不能选多个值的问题“ private void initdroplistitemlirun(string c_Bus ...

  9. 静态Map类型变量赋初始值

    private static Map<String,String> sysTypeList = new HashMap<String, String>(); static { ...

随机推荐

  1. SAS学习笔记4 基本运算语句(lag、retain、_n_函数)

    lag:返回的是上一次lag函数运行时的实参,即lag(argument)=上一次lag函数执行时的argument retain:对变量进行值的初始化和保留到下一个迭代步 _n_:data步的自动变 ...

  2. DataGridView绑定数据、删除数据

    定义学生类: using System; using System.Collections.Generic; using System.Linq; using System.Text; using S ...

  3. 如何禁止Chrome浏览器隐藏URL的WWW前缀

    如何禁止Chrome浏览器隐藏URL的WWW前缀 一.打开Chrome浏览器 二.在Chrome浏览器的地址栏中输入以下内容并回车: chrome://flags/#omnibox-ui-hide-s ...

  4. Twitter Bootstrap:前端框架利器

    Bootstrap 的文件结构 读者可以直接从 GitHub 下载到 Bootstrap 源码,本地解压后可以看到这样的目录结构:docs.img.jquery-ui- bootstrap.js 和 ...

  5. leetcode-174. Dungeon Game 地下城游戏

    一道关于骑士救公主故事的题目. 一些恶魔抓住了公主(P)并将她关在了地下城的右下角.地下城是由 M x N 个房间组成的二维网格.我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过 ...

  6. C#基础 类及常用函数【string 、Math 、DiteTime 、TimeSpan】

    一  string 类型 string str = "abcdefg"; str.Length  -  字符串长度,返回int类型 str.TrimStart()          ...

  7. Viewer.js的inline模式

    开始 前几天接到一个小的支持,要做一个有图像预览和操作功能的demo,并且给出了参照的模板.刚开始简单的看了一下给的模板,一个是boxImg.js,另一个是Viewer.js. 问题 其实图片预览的插 ...

  8. goroutine的设计与实现

    goroutine背后的系统知识 http://www.sizeofvoid.net/goroutine-under-the-hood/ 下周写完

  9. java - day008 - 接口,内部类

    接口 作用: 结构设计工具,用来解耦合,需要有子类,隔离具体实现 接口是一个极端的抽象类 用 interface 代替 class 用 implements 代替 extends // 接口中所有东西 ...

  10. No package libmcrypt available.

    Centos安装PHP时,安装php依赖包时yum install libmcrypt libmcrypt-devel,报错如下: No package libmcrypt available. No ...