vue data 赋值 html,Vue中用props给data赋初始值遇到的问题解决

前言

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

一、现象

代码:

用props初始化data中变量

//全局组件

let userinfo = vue.component('userinfo' ,{

name: 'user-info',

props: {

userdata: object

},

data() {

return {

username: this.userdata.name

}

},

template: `

姓名:{{username}}
性别:{{userdata.gender}}
生日:{{userdata.birthday}}

`

});

//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

}

});

代码解读:

根组件data中有一个对象:user,包含三个属性:name、gender、birthday,初始值都为空字符串

模拟api异步请求,500毫秒后对user的重新赋值,三个属性都不再为空

声明一个子组件userinfo,props中有一个对象userdata,用于接收父组件的user;data中有一个变量username,初始值来自于userdata.name

结果:

2a569c5e85ccca15c8557d1113073c7d.png

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

为什么会这样呢?

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

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

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

//全局组件

let userinfo = vue.component('userinfo' ,{

name: 'user-info',

props: {

userdata: object

},

data() {

return {

username: this.userdata.name

}

},

template: `

姓名:{{username.text}}
性别:{{userdata.gender}}
生日:{{userdata.birthday}}

`

});

//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

}

});

运行结果:姓名仍然没有值,和第一次结果一样!!!

二、原因

那么,原因到底是什么呢?百思不得解,后来和小伙伴们讨论时,有人提出:会不会因为data在初始化时深拷贝?

我觉得这种解释比较靠谱,于是去收集证据,首先去vue官网翻了一下关于data的文档,其中:

b29566fd72b75253f37e781420eaa999.png

当看到"递归地"那个词,基本上就能断定上面的推论是正确的,因为深拷贝的核心原理就是递归。

原来,vue初始化时会递归地遍历data所有的属性,并使用object.defineproperty把这些属性全部转为getter/setter,用于实现双向绑定。官方文档在reactivity in depth一章明确有说:

5f745a2033ecab09f41ababdf0253bc5.png

还顺便解释了一下为什么vue不支持ie8的原因:ie8不支持object.defineproperty。

三、解决办法

既然因为data深拷贝的原因,data无法随着props的变化而更新,我们很自然的就想到vue中有监听作用的两个功能:watch、computed。

修改代码如下,观察结果:

解决方案:watch、computed

//全局组件

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: `

姓名(watch):{{ username }}
姓名(computed):{{ computedusername }}
性别:{{ userdata.gender }}
生日:{{ userdata.birthday }}

`

});

//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

}

});

运行结果

3b4380d0d1531d64b243174a4398cc2d.png

完美!!!

四、总结:关于vue中props的要点

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

c7d62ccb58848f0a5bf8cd5cc926575f.png

大概梳理一下:

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

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

3.可以变相操作props

(1)在data中声明局部变量,并用props初始化,弊端:局部变量不随着props更新而更新

(2)在computed中对props值转换后输出

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值