发现问题

在vue项目中,父子组件数据传递是最常见的场景,但是今天在开发过程中父级数据传递到子组件,控制子组件的显隐,发现存在问题,一直监听不到数据的变化,详细排查后发现是因为props在传递数据的时候子组件接收到数据后没有及时发生变化导致的。

这里使用的是 iview 框架

// 子组件
<template>
    <Modal
        v-model="isShowModel"
        title="测试弹窗">
        <p>Content of dialog</p>
        <p>Content of dialog</p>
        <p>Content of dialog</p>
    </Modal>
</template>

<script>
export default {
    name: 'TestModel',
    props: {
        showModel: {
            type: Boolean,
            default: false
        }
    },
    data() {
        return {
            isShowModel: this.showModel
        }
    }
}
</script>
// 父组件
<template>
  <div id="app">
    <TestModel :showModel="showModel"></TestModel>
    <Button type="primary" @click="changeShowModel">显示弹窗</Button>
  </div>
</template>

<script>
import TestModel from './components/TestModel.vue'

export default {
  components: {
    TestModel
  },
  data() {
    return {
      showModel: false,
    }
  },
  methods: {
    changeShowModel() {
      this.showModel = true;
    }
  }
}
</script>

问题分析

预期效果是点击按钮直接弹出弹窗,结果怎么也弹不出来。子组件中增加 watch 监听 props 发现数据已经变化了,但是 data 中接收 props 数据的变量并未改变,发现问题所在。

问题原因就是接收 props 数据的变量无法及时响应 props 的变化,下一步解决问题就是重点解决响应变化问题。

问题解决

解决方案1

子组件中增加 watch 监听 props 中传进来的数据变化,同时当子组件数据变化时,数据上传父组件。

// 子组件
<template>
    <Modal
        v-model="isShowModel"
        width="1000"
        title="测试弹窗"
        @on-cancel="cancel"    
    >
        <p>Content of dialog</p>
        <p>Content of dialog</p>
        <p>Content of dialog</p>
    </Modal>
</template>

<script>
export default {
    name: 'TestModel',
    props: {
        showModel: {
            type: Boolean,
            default: false
        }
    },
    data() {
        return {
            isShowModel: this.showModel
        }
    },
    watch: {
        showModel(v) {
            this.isShowModel = this.showModel
        }
    },
    methods: {
        cancel() {
            this.$emit('cancel', this.isShowModel);
        }
    }
}
</script>
// 父组件
methods: {
    modelCancel(v) {
        this.showModel = v;
    }
}

解决方案2

使用 vue 中的计算属性( computed )中的 set 方法。

// 子组件
<template>
    <Modal
        v-model="isShowModel"
        width="1000"
        title="测试弹窗"
    >
        <p>Content of dialog</p>
        <p>Content of dialog</p>
        <p>Content of dialog</p>
    </Modal>
</template>

<script>
export default {
    name: 'TestModel',
    props: {
        showModel: {
            type: Boolean,
            default: false
        }
    },
    computed: {
        isShowModel: {
            set(v) {
                this.$emit('cancel', v);
            },
            get() {
                return this.showModel;
            }
        }
    },
}
</script>

有兴趣的兄弟可以关注我的博客 www.maple.ink
个人博客

GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐