前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从iView中Select的渲染了解vue的渲染机制

从iView中Select的渲染了解vue的渲染机制

作者头像
码客说
发布2024-03-29 13:12:52
780
发布2024-03-29 13:12:52
举报
文章被收录于专栏:码客码客

前言

在使用iView的Select的时候,Select组件使用了双向绑定

代码语言:javascript
复制
<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是在dataprops之后再执行的,那为什么会出现这个问题呢?

我们可以查看一下源代码:

代码语言:javascript
复制
mounted(){
    this.$on('on-select-selected', this.onOptionClick);

    // set the initial values if there are any
    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();

    // remote search, set default-label
    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在渲染之前就覆盖了之前的默认值,这样渲染的时候就是新值了。

代码语言:javascript
复制
created() {
	console.info("created");
    this.getCronArr();
},

使用watch+immediate

默认watch的属性在mounted之前调用,添加immediate: true后,监听函数在创建后就会调用一次,所以会在mounted之前先调用。

建议:

监听props传入值的情况下使用该方式。

示例:

代码语言:javascript
复制
watch: {
    cronStr: {
      handler() {
        this.getCronArr();
      },
      immediate: true,
    },
},

使用nextTick

Vue会先确保当前的 DOM 更新队列中的所有工作完成,包括组件内部的延迟执行的代码,再执行await this.$nextTick()后的代码。

代码语言:javascript
复制
async mounted() {
    console.info("mounted");
    await this.$nextTick();
    this.getCronArr();
},

mounted+setTimeout

通过上面的源码我们发现,赋值是延迟执行的,我们再次赋值也添加延迟,就能都放在延迟的队列中,也会等到之前渲染完再执行。

代码语言:javascript
复制
mounted() {
    console.info("mounted");
    setTimeout(() => {
      this.getCronArr();
    });
},
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-02-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 解决方式
    • 使用created
      • 使用watch+immediate
        • 使用nextTick
          • mounted+setTimeout
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档