Vue-ref与props的使用详解

 更新时间:2026年01月15日 09:20:54   作者:咖啡の猫  
文章总结了Vue3中props和ref的使用方法、特点及区别,包括基本用法、类型校验、默认值设置、事件通信等,并指出了常见误区和最佳实践

一、props:父组件向子组件传递数据

props 是单向数据流的核心,用于父组件向子组件传递数据。

1. 基本用法(Vue 3 +<script setup>)

子组件(ChildComponent.vue)

<script setup>
// 定义接收的 props
defineProps({
  title: {
    type: String,
    required: true
  },
  count: {
    type: Number,
    default: 0
  }
})
</script>

<template>
  <div class="child">
    <h3>{{ title }}</h3>
    <p>当前计数:{{ count }}</p>
  </div>
</template>

父组件(ParentComponent.vue)

<script setup>
import ChildComponent from './ChildComponent.vue'

const parentTitle = '来自父组件的数据'
const parentCount = 5
</script>

<template>
  <div>
    <h1>父组件</h1>
    <ChildComponent 
      :title="parentTitle" 
      :count="parentCount" 
    />
  </div>
</template>

✅ 数据从父 → 子,单向流动

2.props的特点

特性说明
✅ 响应式父组件数据变化,子组件自动更新
❌ 不可直接修改子组件不能修改 props(会报警告)
✅ 类型校验支持 type、required、default
✅ 默认值可设置 default 值

错误示例:子组件修改 props

// ❌ 错误!不要这样做
props.count++ // 警告:Avoid mutating a prop directly

✅ 正确做法:通过事件通知父组件修改

<!-- 子组件 -->
<script setup>
const emit = defineEmits(['update-count'])
const increment = () => {
  emit('update-count', props.count + 1)
}
</script>

<template>
  <button @click="increment">+1</button>
</template>
<!-- 父组件 -->
<ChildComponent 
  :count="count" 
  @update-count="count = $event"
/>

✅ 实现“子组件通知父组件更新数据”。

二、ref:获取 DOM 元素或子组件实例

ref 是一个响应式引用,可用于:

  • 模板中:获取 DOM 元素
  • 组件中:获取子组件实例
  • 变量:创建响应式数据(Vue 3)

1. 获取 DOM 元素

<script setup>
import { ref, onMounted } from 'vue'

// 创建 ref
const inputRef = ref(null)

onMounted(() => {
  // DOM 渲染完成后,inputRef.value 指向真实 DOM
  inputRef.value.focus() // 自动聚焦
})
</script>

<template>
  <input ref="inputRef" type="text" placeholder="自动聚焦输入框" />
</template>

ref 在模板中通过字符串名绑定,在 JS 中通过变量访问。

2. 获取子组件实例

子组件(Modal.vue)

<script setup>
import { ref } from 'vue'

const isVisible = ref(false)

// 提供方法给父组件调用
function open() {
  isVisible.value = true
}

function close() {
  isVisible.value = false
}

// 暴露给父组件
defineExpose({
  open,
  close
})
</script>

<template>
  <div v-if="isVisible" class="modal">
    <p>这是一个模态框</p>
    <button @click="close">关闭</button>
  </div>
</template>

父组件(Parent.vue)

<script setup>
import { ref } from 'vue'
import Modal from './Modal.vue'

const modalRef = ref(null)

const openModal = () => {
  modalRef.value.open() // 调用子组件方法
}
</script>

<template>
  <div>
    <button @click="openModal">打开模态框</button>
    <Modal ref="modalRef" />
  </div>
</template>

✅ 通过 defineExpose 暴露方法,父组件通过 ref 调用。

3.ref创建响应式数据(Vue 3)

<script setup>
import { ref } from 'vue'

const count = ref(0) // ref 包装基本类型

const increment = () => {
  count.value++ // 注意:需要 .value
}
</script>

<template>
  <p>计数:{{ count }}</p>
  <button @click="increment">+1</button>
</template>

ref 是 Vue 3 响应式系统的基础之一(与 reactive 并列)。

三、ref与props的对比

维度propsref
作用父 → 子 传递数据获取 DOM / 组件实例 / 创建响应式变量
方向自上而下(单向)自下而上(调用子组件)或内部使用
响应式是(父变子变)是(ref 变量本身是响应式)
可修改性子组件不能直接修改可以修改(如 count.value++)
使用场景数据传递DOM 操作、方法调用、响应式变量
Vue 2 写法this.$refs.xxxthis.$refs.xxx
Vue 3 写法defineProps()ref() + 模板绑定

一句话总结

props 用于“传数据”,ref 用于“拿实例”或“做响应式变量”。

四、Vue 2 vs Vue 3 差异

Vue 2 写法

// 子组件
export default {
  props: ['title'],
  mounted() {
    this.$refs.input.focus()
  }
}

// 父组件
export default {
  methods: {
    callChild() {
      this.$refs.childModal.open()
    }
  }
}

Vue 3<script setup>写法

<script setup>
// 使用 defineProps 和 ref
const props = defineProps(['title'])
const inputRef = ref(null)
</script>

✅ Vue 3 更简洁,但需注意 refsetup 中的 .value 问题。

五、常见误区与最佳实践

❌ 误区 1:在setup中直接使用ref变量不加.value

// ❌ 错误
const count = ref(0)
console.log(count) // RefImpl { value: 0 }

// ✅ 正确
console.log(count.value) // 0

❌ 误区 2:子组件直接修改props

// ❌ 错误
props.count++

// ✅ 正确:通过事件通知父组件
emit('update:count', props.count + 1)

✅ 最佳实践

  • props 只用于传递数据,不用于方法调用
  • ref 用于需要直接操作的场景(如聚焦、动画、第三方库集成)
  • 避免过度使用 ref 调用子组件方法,优先使用 emit 事件通信
  • 复杂状态管理使用 Pinia 或 Vuex,而非层层 props 传递

六、总结

API核心用途是否响应式是否可修改推荐场景
props父 → 子 传数据❌(子不能改)配置项、展示数据
ref获取实例 / 响应式变量DOM 操作、方法调用、局部状态

通信原则

  • 数据流props 向下,emit 向上
  • 实例调用ref 获取子组件,谨慎使用
  • 响应式ref 和 reactive 是 Vue 3 的基石

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • vue和webpack打包项目相对路径修改的方法

    vue和webpack打包项目相对路径修改的方法

    这篇文章主要介绍了vue和webpack打包项目相对路径修改的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • vue3修改link标签默认icon无效问题详解

    vue3修改link标签默认icon无效问题详解

    这篇文章主要介绍了vue3修改link标签默认icon无效问题详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • Vue页面骨架屏的实现方法

    Vue页面骨架屏的实现方法

    在开发webapp的时候总是会受到首屏加载时间过长的影响,越来越多的APP采用了“骨架屏”的方式去提升用户体验。这篇文章主要介绍了Vue页面骨架屏的实现方法,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • vue elementUi+sortable.js实现嵌套表格拖拽问题

    vue elementUi+sortable.js实现嵌套表格拖拽问题

    这篇文章主要介绍了vue elementUi+sortable.js实现嵌套表格拖拽问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • vue中 this.$set的用法详解

    vue中 this.$set的用法详解

    这篇文章主要介绍了vue中 this.$set的用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • 在导入.vue文件的时候,ts报错提示:找不到模块“@/Layout/index.vue”或其相应的类型声明问题

    在导入.vue文件的时候,ts报错提示:找不到模块“@/Layout/index.vue”或其相应的类型声明问题

    这篇文章主要介绍了在导入.vue文件的时候,ts报错提示:找不到模块“@/Layout/index.vue”或其相应的类型声明问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • Vue3 使用axios拦截器打印前端日志

    Vue3 使用axios拦截器打印前端日志

    这篇文章主要介绍了Vue3 使用axios拦截器打印前端日志,这是一种比较值得推荐的方式,也就是写一次,就不用总写console.log了。下面来看看文章的详细内容,需要的朋友可以参考一下
    2021-11-11
  • 在VUE3中禁止网页返回到上一页的方法

    在VUE3中禁止网页返回到上一页的方法

    这篇文章主要介绍了在VUE3中如何禁止网页返回到上一页,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-09-09
  • Vue使用vue-area-linkage实现地址三级联动效果的示例

    Vue使用vue-area-linkage实现地址三级联动效果的示例

    很多时候我们需要使用地址三级联动,即省市区三级联动,这篇文章主要介绍了Vue使用vue-area-linkage实现地址三级联动效果的示例,感兴趣的小伙伴们可以参考一下
    2018-06-06
  • Vue 中 onclick和@click区别解析

    Vue 中 onclick和@click区别解析

    这篇文章主要介绍了Vue 中 onclick和@click区别,简单点说就是onclick 只能触发 js的原生方法,不能触发vue的封装方法,@click 只能触发vue的封装方法,不能触发js的原生方法,需要的朋友可以参考下
    2024-02-02

最新评论