Vue 组件通信与渲染时机踩坑汇总

2026年02月09日3 min read
Vue
前端

1. 父组件向子组件传值(props)

props 推荐使用对象写法,便于类型、默认值和必填约束。

<!-- Child.vue -->
<template>
  <view>{{ name || "默认值" }}</view>
</template>

<script>
export default {
  props: {
    name: {
      type: String,
      default: "kwydy",
      required: false,
    },
  },
};
</script>
<!-- Parent.vue -->
<template>
  <Child :name="userName" />
</template>

<script>
import Child from "./Child.vue";

export default {
  components: { Child },
  data() {
    return {
      userName: "Alice",
    };
  },
};
</script>

2. 子组件向父组件传值($emit)

子组件通过事件抛出数据,父组件监听事件并处理。

<!-- Child.vue -->
<template>
  <button @click="notifyParent">向父组件传值</button>
</template>

<script>
export default {
  methods: {
    notifyParent() {
      this.$emit("submit", { message: "你好父组件" });
    },
  },
};
</script>
<!-- Parent.vue -->
<template>
  <Child @submit="handleSubmit" />
</template>

<script>
import Child from "./Child.vue";

export default {
  components: { Child },
  methods: {
    handleSubmit(payload) {
      console.log(payload.message);
    },
  },
};
</script>

3. DOM 更新时机($nextTick)

数据刚修改后,DOM 还没完成更新。依赖真实 DOM 的逻辑要放进 this.$nextTick

this.message = "changed";
this.$nextTick(() => {
  // 此时 DOM 已更新
  this.calcHeight();
});

典型场景:

  1. 列表异步加载后测量高度。
  2. v-if 切换后初始化第三方插件。
  3. 表格数据更新后自动滚动到底部。

4. 数据初始化避免模板报错

如果模板里直接访问 groupDetail.data.name,那就要保证 data 初始值存在。

data() {
  return {
    groupDetail: { data: {} },
  };
}

否则接口返回前,模板渲染可能报 Cannot read property 'name' of undefined

5. this 指向踩坑(尤其在回调里)

在非箭头函数或第三方回调里,this 可能不是 Vue 实例。常见做法:

  1. 使用箭头函数保留词法作用域。
  2. 提前缓存实例:const vm = this
  3. 如果是在实例外部,直接引用实例变量(如 vue.noData = false)。
const vm = this;
request().then((res) => {
  vm.noData = res.data.records.length === 0;
});

6. 快速检查清单

  1. 父传子:props 是否声明类型与默认值。
  2. 子传父:$emit 事件名是否与父组件监听一致。
  3. DOM 操作:是否放在 $nextTick
  4. 深层对象:是否在 data 里给了完整初始结构。
  5. 异步回调:是否确认 this 指向正确。