摘要:基于此,我们很自然的就想到中有监听作用的两个功能。正如在所说小结一下文章开头的问题是一个关于基本数据类型和引用数据类型赋值的问题在初始化时被递归遍历转化是用于实现双向绑定这么看来,二者是没有任何关系的。想当然和不加深究实为大忌,引以为戒。
2018-11-28更:文章发布后因为存在理解错误,经@Kim09AI同学提醒后做了调整,在此深表感谢。其他不足之处,还望不吝赐教。
前言前段时间做一个运营活动的项目,上线后产品反馈页面埋点不对,在排查过程中发现,问题竟然是由于Vue中的data初始值导致,而data的初始值来自于props。为方便描述,现将问题抽象如下:
一、现象 代码:代码解读:用props初始化data中变量
根组件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改为对象,通过引用数据类型赋值,然后观察是否符合预期。代码如下:
用props初始化data中变量-对象形式
运行结果:
完美!!!
如果我们不想把user.name改为Object类型,有没有其他的解决办法呢?
既然基本数据类型赋值没法实现值同步,那我们可以考虑监听props中的值,然后手动变更局部变量。基于此,我们很自然的就想到Vue中有监听作用的两个功能:watch、computed。
为了缩减篇幅,我们此处只贴出userInfo组件,其他代码与第一个示例一致,具体如下:
方法一:watchlet 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: `方法二:computed` });姓名:{{ userName }}性别:{{ userData.gender }}生日:{{ userData.birthday }}
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官方文档看到关于data的描述:
看到"递归地”那个词,就想当然地认为data被深拷贝了,因为深拷贝的核心原理就是递归。
其实现在再回过头来看那段描述,包括在Reactivity in Depth一章的描述:
它们真正含义是:Vue会递归地遍历data所有的属性,并使用Object.defineProperty把这些属性全部转为getter/setter,让data中的属性更具“交互性”,以此作为实现双向绑定的基础。包括还顺便解释了一下为什么Vue不支持IE8的原因:IE8不支持Object.defineProperty。
这也仅仅解释了为什么只有在组件初始化之初data中已经声明的属性才具有“交互性”,即data中属性的变化会引起视图变化,而其他在最初data中没有声明的属性则不会。正如在The Vue Instance所说:
小结一下:
文章开头的问题是一个关于基本数据类型和引用数据类型赋值的问题
data在初始化时被递归遍历转化是用于实现双向绑定
这么看来,二者是没有任何关系的。
四、关于Vue中props的要点事后又仔细翻了一下关于props的文档:
大概梳理一下:
1.props是单向数据流:父组件的数据变化,通过props实时反应在子组件中,反之不然
2.不允许在子组件中直接操作props
3.可以变相操作props
(1)在data中声明局部变量,并用props初始化
(2)在computed中对props值转换后输出
分享是一种知识的传递,严谨和正确是最重要的,技术文章更是如此。想当然和不加深究实为大忌,引以为戒。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/99420.html
摘要:组件中使用定时器及销毁问题如果我们在页面中使用了一个定时器,当从页面跳转到页面时,如果不手动清除这个定时器,那么它仍旧会执行,这不是我们所期望的。 公司年初开始从jquery转型到vue开发,思想上从jquery的操作DOM到vue的操作数据,刚开始还不太习惯,但用了一段时间发现确实比较方便。在刚开始用vue的时候,也踩了一些坑,现在分享出来,供刚入门上手开发vue的朋友参考,都是一些...
摘要:当一个组件没有声明任何时,这里会包含所有父作用域的绑定和除外,并且可以通过传入内部组件在创建高级别的组件时非常有用。 写在前面 组件间的通信是是实际开发中非常常用的一环,如何使用对项目整体设计、开发、规范都有很实际的的作用,我在项目开发中对此深有体会,总结下vue组件间通信的几种方式,讨论下各自的使用场景 文章对相关场景预览 父->子组件间的数据传递 子->父组件间的数据传递 兄弟...
摘要:组件的复用你可以将组件进行任意次数的复用注意当点击按钮时,每个组件都会各自独立维护它的。 1、基本示例 // 定义一个名为 button-counter 的新组件 Vue.component(button-counter, { data: function () { return { count: 0 } }, template: You cli...
摘要:前言最近在使用框架,用到了对话框组件,大致实现的效果,跟我之前自己在移动端项目里面弄的一个弹窗组件差不太多。现在基本上弹窗组件都已实现的差不多了,还差一个弹窗的关闭事件,这里就涉及到子组件往父组件传参了。 前言 最近在使用element-ui框架,用到了Dialog对话框组件,大致实现的效果,跟我之前自己在移动端项目里面弄的一个弹窗组件差不太多。然后就想着把这种弹窗组件的实现方式与大家...
摘要:前言最近在使用框架,用到了对话框组件,大致实现的效果,跟我之前自己在移动端项目里面弄的一个弹窗组件差不太多。现在基本上弹窗组件都已实现的差不多了,还差一个弹窗的关闭事件,这里就涉及到子组件往父组件传参了。 前言 最近在使用element-ui框架,用到了Dialog对话框组件,大致实现的效果,跟我之前自己在移动端项目里面弄的一个弹窗组件差不太多。然后就想着把这种弹窗组件的实现方式与大家...
阅读 820·2023-04-25 19:49
阅读 3755·2021-09-30 09:47
阅读 2740·2021-09-13 10:21
阅读 2679·2021-08-24 10:04
阅读 3167·2019-08-30 15:55
阅读 2295·2019-08-30 15:55
阅读 2398·2019-08-30 15:54
阅读 3470·2019-08-30 13:53