博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Vue中用props给data赋初始值遇到的问题
阅读量:6148 次
发布时间:2019-06-21

本文共 2907 字,大约阅读时间需要 9 分钟。

2018-11-28更:文章发布后因为存在理解错误,经@Kim09AI同学提醒后做了调整,在此深表感谢。其他不足之处,还望不吝赐教。

前言

前段时间做一个运营活动的项目,上线后产品反馈页面埋点不对,在排查过程中发现,问题竟然是由于Vue中的data初始值导致,而data的初始值来自于props。为方便描述,现将问题抽象如下:

一、现象

代码:

    
用props初始化data中变量

代码解读:

  1. 根组件data中有一个对象:user,包含三个属性:name、gender、birthday,初始值都为空字符串
  2. 模拟api异步请求,500毫秒后对user的重新赋值,三个属性都不再为空
  3. 声明一个子组件userInfo,props中有一个对象userData,用于接收父组件的user;data中有一个变量userName,初始值来自于userData.name

结果:

clipboard.png

页面初始化后,姓名、性别、生日都显示为空,500毫秒后性别和生日显示正常结果,仅姓名没有变化。

为什么会这样呢?

二、原因及解决办法

我最初的想法:user.name是String,属于基本数据类型,用它给子组件data中userName赋值,属于基本数据类型赋值,所以当父组件中user.name变化时,子组件中userName并不会随之变化。

是这样的吗?于是我决定将user.name改为对象,通过引用数据类型赋值,然后观察是否符合预期。代码如下:

    
用props初始化data中变量-对象形式

运行结果:

clipboard.png

完美!!!

如果我们不想把user.name改为Object类型,有没有其他的解决办法呢?

既然基本数据类型赋值没法实现值同步,那我们可以考虑监听props中的值,然后手动变更局部变量。基于此,我们很自然的就想到Vue中有监听作用的两个功能:watch、computed

为了缩减篇幅,我们此处只贴出userInfo组件,其他代码与第一个示例一致,具体如下:

方法一:watch

let userInfo = Vue.component('userInfo' ,{        name: 'user-info',        props: {            userData: Object        },        data() {          return {            userName: this.userData.name          }        },        watch: {            'userData.name': function (val) { //监听props中的属性                this.userName = val;            }        },        template: `            
姓名:{
{ userName }}
性别:{
{ userData.gender }}
生日:{
{ userData.birthday }}
` });

方法二:computed

let userInfo = Vue.component('userInfo' ,{        name: 'user-info',        props: {            userData: Object        },        data() {          return {            userName: this.userData.name          }        },        computed: {            computedUserName(){                return this.userData.name            }        },        template: `            
姓名:{
{ computedUserName }}
性别:{
{ userData.gender }}
生日:{
{ userData.birthday }}
` });

经验证,结果符合皆预期!

三、走过的弯路

第一条弯路

详见评论区@Kim09AI同学的评论。

第二条弯路

其实,曾以为导致文章开头的问题,是由于data在初始化后深拷贝,props再次变化data并不会刷新导致的。

直到文章发布之初,仍然持此观点,后来经@Kim09AI同学提醒才恍然大悟。

当初之所以深信是data被深拷贝导致的,主要是自己在翻到Vue官方文档看到关于的描述:

clipboard.png

看到"递归地”那个词,就想当然地认为data被深拷贝了,因为深拷贝的核心原理就是递归。

其实现在再回过头来看那段描述,包括在一章的描述:

clipboard.png

它们真正含义是:Vue会递归地遍历data所有的属性,并使用Object.defineProperty把这些属性全部转为getter/setter,让data中的属性更具“交互性”,以此作为实现双向绑定的基础。包括还顺便解释了一下为什么Vue不支持IE8的原因:IE8不支持Object.defineProperty。

这也仅仅解释了为什么只有在组件初始化之初data中已经声明的属性才具有“交互性”,即data中属性的变化会引起视图变化,而其他在最初data中没有声明的属性则不会。正如在所说:

clipboard.png

小结一下:

  • 文章开头的问题是一个关于基本数据类型和引用数据类型赋值的问题
  • data在初始化时被递归遍历转化是用于实现双向绑定

这么看来,二者是没有任何关系的。

四、关于Vue中props的要点

事后又仔细翻了一下关于的文档:

clipboard.png

大概梳理一下:

1.props是单向数据流:父组件的数据变化,通过props实时反应在子组件中,反之不然

2.不允许在子组件中直接操作props

3.可以变相操作props

(1)在data中声明局部变量,并用props初始化
(2)在computed中对props值转换后输出

五、一点反思

分享是一种知识的传递,严谨和正确是最重要的,技术文章更是如此。想当然和不加深究实为大忌,引以为戒。

转载地址:http://ermya.baihongyu.com/

你可能感兴趣的文章
vsftpd 相关总结
查看>>
售前工程师的成长---一个老员工的经验之谈
查看>>
Get到的优秀博客网址
查看>>
【Git入门之四】操作项目
查看>>
老男孩教育每日一题-第107天-简述你对***的理解,常见的有哪几种?
查看>>
Python学习--time
查看>>
在OSCHINA上的第一篇博文,以后好好学习吧
查看>>
软件概要设计做什么,怎么做
查看>>
dwr
查看>>
word2010中去掉红色波浪线的方法
查看>>
fabric上下文管理器(context mangers)
查看>>
php小知识
查看>>
Windows下安装、运行Lua
查看>>
Nginx 反向代理、负载均衡、页面缓存、URL重写及读写分离详解(二)
查看>>
初识中间件之消息队列
查看>>
MyBatis学习总结(三)——优化MyBatis配置文件中的配置
查看>>
Spring常用注解
查看>>
我的友情链接
查看>>
PCS子层有什么用?
查看>>
查看端口,关闭端口
查看>>