【Vue】23.vue项目中子组件接收不到父组件传值的问题

项目背景:使用vue-cli3搭建的项目框架

问题描述:父组件里面有一个轮播图,这个轮播图我封装了一下,封装成了一个组件引到了这个页面里面,我们产品的需求是,根据页面获取到的婚姻状态做判断,第二张图片的链接点进去显示不同的文章,意思就是根据婚姻状态给第二张图片赋不同的链接值,所以我需要传给这个轮播图组件一个婚姻状态,这个婚姻状态呢,又是从接口里面动态获取到的,这个轮播图呢,又是在页面加载的时候就显示的。

刚开始的做法是这样的,data里面定义一个变量info.marriage,根据后台接口返回的婚姻状态,给info.marriage赋值,然后传到SlideShow这个轮播图组件里面,但是这样的话,由于接口异步加载的问题,子组件拿不到父组件传过来的数据,郁闷了好久,一直没找到原因。后来仔细看了一下vue组件的生命周期,发现了问题的所在,后来想到一种解决方法就是,在组件上加个开关,初始化的时候给一个false,数据加载赋值的时候再给他赋值为true,这样整一个加载顺序就不一样了,这样问题就解决了。

代码修改前:

    <div class="advertising-banner">
      <SlideShow
        :marriage="info.marriage"
        v-on:deductPointBackToParent="deductPointBackToParent"></SlideShow>
    </div>
  import {mapGetters, mapMutations} from 'vuex';
  import {getSingleReportResult, satisfyReport} from '../api/insurance';
  import CONSTANT from '../common/js/constant';
  import SlideShow from '../components/SlideShow.vue';

  export default {
    name: 'EvalutionDetails',
    data() {
      return {
        info: {
          marryType: '',
          marriage: '',
        },
      };
    },
    computed: {
      ...mapGetters(['getWxUnionId']),
    },
    beforeMount() {
      console.log('beforeMount');
    },
    mounted() {
      console.log('mounted');
      if (this.pageType === 2) {
        this.drawLine();
      }
    },
    beforeCreate() {
      console.log('beforeCreate');
    },
    created() {
      this.init();
      console.log('created');
    },
    methods: {
      ...mapMutations(['SAVE_WX_UNION_ID']),
      init() {
        this.reportType = this.getQueryString('reportType');
        this.resultId = this.getQueryString('resultId');
        this.serialNo = this.getQueryString('serialNo');
        this.unionId = this.getQueryString('unionId');
        this.pageType = this.getQueryString('reportType');
        this.SAVE_WX_UNION_ID(this.unionId);
        getSingleReportResult({
          reportType: this.reportType,
          resultId: this.resultId,
          serialNo: this.serialNo,
        }).then((response) => {
          if (response && response.data) {
            this.info.marryType = response.data.marriage;
            if (response.data.marriage === CONSTANT.INSURANCE_REPORT_MARRY_TYPE.SINGLE) {
              this.info.marriage = '1';
            } else if (response.data.marriage
              === CONSTANT.INSURANCE_REPORT_MARRY_TYPE.MARRIED_PREGNANCY) {
              this.info.marriage = '2';
            }
       }).catch((err) => {
          console.log(err);
        });
      },
      deductPointBackToParent(childValue) {
        console.log(`this.info.marriage: ${childValue}`);
      },
      getQueryString(name) {
        const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`);
        const r = window.location.search.substr(1).match(reg);
        if (r != null) return unescape(r[2]);
        return null;
      },
    },
    components: {
      SlideShow,
    },
  };

子组件没有加开关以前 ,父组件加载子组件执行顺序如下:

代码修改后:

    <div class="advertising-banner">
      <SlideShow v-if="testShow"
        :marriage="info.marriage"
        v-on:deductPointBackToParent="deductPointBackToParent"></SlideShow>
    </div>
  import {mapGetters, mapMutations} from 'vuex';
  import {getSingleReportResult, satisfyReport} from '../api/insurance';
  import CONSTANT from '../common/js/constant';
  import SlideShow from '../components/SlideShow.vue';

  export default {
    name: 'EvalutionDetails',
    data() {
      return {
        info: {
          marryType: '',
          marriage: '',
        },
        testShow: false,
      };
    },
    computed: {
      ...mapGetters(['getWxUnionId']),
    },
    beforeMount() {
      console.log('beforeMount');
    },
    mounted() {
      console.log('mounted');
      if (this.pageType === 2) {
        this.drawLine();
      }
    },
    beforeCreate() {
      console.log('beforeCreate');
    },
    created() {
      this.init();
      console.log('created');
    },
    methods: {
      ...mapMutations(['SAVE_WX_UNION_ID']),
      init() {
        this.reportType = this.getQueryString('reportType');
        this.resultId = this.getQueryString('resultId');
        this.serialNo = this.getQueryString('serialNo');
        this.unionId = this.getQueryString('unionId');
        this.pageType = this.getQueryString('reportType');
        this.SAVE_WX_UNION_ID(this.unionId);
        getSingleReportResult({
          reportType: this.reportType,
          resultId: this.resultId,
          serialNo: this.serialNo,
        }).then((response) => {
          if (response && response.data) {
            this.info.marryType = response.data.marriage;
            if (response.data.marriage === CONSTANT.INSURANCE_REPORT_MARRY_TYPE.SINGLE) {
              this.testShow = true;
              this.info.marriage = '1';
            } else if (response.data.marriage
              === CONSTANT.INSURANCE_REPORT_MARRY_TYPE.MARRIED_PREGNANCY) {
              this.testShow = true;
              this.info.marriage = '2';
            } else {
              this.testShow = true;
            }
        }).catch((err) => {
          console.log(err);
        });
      },
      deductPointBackToParent(childValue) {
        console.log(`this.info.marriage: ${childValue}`);
      },
      getQueryString(name) {
        const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`);
        const r = window.location.search.substr(1).match(reg);
        if (r != null) return unescape(r[2]);
        return null;
      },
    },
    components: {
      SlideShow,
    },
  };

子组件加了开关以后 ,父组件加载子组件执行顺序如下: 

 

 

### Vue2 中子组件父组件并触发父组件重新渲染 在 Vue2 中,当子组件父组件时,如果父组件未能及时更新视图,通常是因为父组件的状态变化未被正确检测到或未触发相应的生命周期钩子。为了确保父组件能够正常响应来自子组件的数据变更,可以采取以下几种解决方案: #### 使用 `$emit` 方法配合 `watch` 通过子组件中的事件发射机制来通知父组件数据已更改,并利用父组件内的侦听器(Watcher)监控特定 prop 的变动情况。 ```javascript // 子组件 (ChildComponent.vue) <template> <button @click="updateParent">点击修改父级状态</button> </template> <script> export default { methods: { updateParent() { this.$emit('value-updated', newValue); } } } </script> ``` ```html <!-- 父组件 (ParentComponent.vue) --> <template> <div> {{ message }} <!-- 添加 watch 属性监听 value 变化 --> <child-component @value-updated="handleValueUpdated"></child-component> </div> </template> <script> import ChildComponent from './ChildComponent'; export default { components: { ChildComponent }, data() { return { message: '', watchedProp: '' }; }, watch: { // 当 watchedProp 发生改变时自动调用 handleWatchedChange 函数 watchedProp(newValue, oldValue) { console.log(`新旧分别为 ${newValue} 和 ${oldValue}`); this.handleWatchedChange(); } }, methods: { handleValueUpdated(value) { this.watchedProp = value; }, handleWatchedChange() { this.message = `接收到的新消息是:${this.watchedProp}`; } } }; </script> ``` 这种方法确保了每当子组件发出新的时,父组件都会立即作出反应并更新其内部状态以及 DOM 结构[^1]。 #### 利用 `.sync` 或者自定义修饰符 Vue 提供了一个内置的`.sync`修饰符用于简化双向绑定的操作,在某些场景下也可以帮助解决此类问题。不过需要注意的是,这种方式本质上仍然是基于 emit/watch 实现的。 ```html <!-- 父组件模板部分 --> <child-component :some-prop.sync="parentData"></child-component> ``` 此时只需在子组件内使用 `$emit('update:someProp', newVal)` 即可同步回父组件相应变量[^4]。 #### 强制刷新策略 对于更复杂的业务逻辑或者特殊情况下的需求,则可能需要考虑采用更加激进的方式来强迫组件树重绘。比如可以在适当位置引入 key 控制,使得每次 props 更新都能引起整个组件实例销毁重建;或者是借助第三方库如 vue-force-update 来达到类似效果[^5]。 ```html <!-- 动态设置key属性让组件随prop变化而重新创建 --> <child-component :key="uniqueKeyBasedOnProps" ...></child-component> ``` 以上三种方式各有优劣,具体应用取决于实际项目的需求和技术栈的选择。建议先尝试较为温和的第一种方案——即合理运用 $emit 加上 watcher ——这往往是最直观也最容易维护的做法[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值