前言 在使用iView的Select的时候,Select组件使用了双向绑定
1 2 3 4 5 6 7 8 9 10 <Select class ="cron_item" v-model ="cronObj.hour" @on-change ="selectedChange" > <Option value ="*" > 任意</Option > <Option v-for ="num in 24" :key ="num" :value ="num - 1 + ''" > {{ num - 1 }}</Option > </Select >
cronObj.hour默认有值假如是*,在mounted的时候我们赋值为5,按道理组件上应该是5的,但是实际上却是*。
难道data中的数据的渲染比mounted还晚?
实际上不是的,mounted是在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 mounted ( ){ this .$on('on-select-selected' , this .onOptionClick ); if (!this .remote && this .selectOptions .length > 0 ){ this .values = this .getInitialValue ().map (value => { if (typeof value !== 'number' && !value) return null ; return this .getOptionData (value); }).filter (Boolean ); } this .checkUpdateStatus (); if (this .remote && this .value && this .defaultLabel ) { if (!this .multiple ) { this .query = this .defaultLabel ; } else if (this .multiple && (this .defaultLabel instanceof Array ) && this .value .length === this .defaultLabel .length ) { const values = this .value .map ((item, index ) => { return { value : item, label : this .defaultLabel [index] }; }); this .$emit('on-set-default-options' , JSON .parse (JSON .stringify (values))); setTimeout (() => { this .values = values; }); } } },
发现iView的Select组件中mounted中赋值是延迟执行的。
这就知道原因了,因为是延迟执行,所以在data渲染的时候,以为渲染过了,mounted回调就开始调用了。
对于两次传入的值,第一次在mounted中触发,后续的都在watch中触发,但是mounted中添加了异步执行,而watch中没有异步调用,所以后续更改的值反倒被之前的值覆盖。
等延迟执行后返回的是之前data的值,mounted设置的值就不生效了。
解决方式 解决方式有以下几种:
使用created created在渲染之前就覆盖了之前的默认值,这样渲染的时候就是新值了。
1 2 3 4 created ( ) { console .info ("created" ); this .getCronArr (); },
默认watch的属性在mounted之前调用,添加immediate: true后,监听函数在创建后就会调用一次,所以会在mounted之前先调用。
建议:
监听props传入值的情况下使用该方式。
示例:
1 2 3 4 5 6 7 8 watch : { cronStr : { handler ( ) { this .getCronArr (); }, immediate : true , }, },
使用nextTick Vue会先确保当前的 DOM 更新队列中的所有工作完成,包括组件内部的延迟执行的代码,再执行await this.$nextTick()后的代码。
1 2 3 4 5 async mounted ( ) { console .info ("mounted" ); await this .$nextTick(); this .getCronArr (); },
mounted+setTimeout 通过上面的源码我们发现,赋值是延迟执行的,我们再次赋值也添加延迟,就能都放在延迟的队列中,也会等到之前渲染完再执行。
1 2 3 4 5 6 mounted ( ) { console .info ("mounted" ); setTimeout (() => { this .getCronArr (); }); },