欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue3?中的ref與props屬性詳解

 更新時(shí)間:2025年04月26日 16:11:40   作者:旺代  
這篇文章主要介紹了Vue3?中的ref與props屬性知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧

ref 屬性 與 props

一、核心概念對(duì)比

特性ref (標(biāo)簽屬性)props
作用對(duì)象DOM 元素/組件實(shí)例組件間數(shù)據(jù)傳遞
數(shù)據(jù)流向父組件訪問(wèn)子組件/DOM父組件 → 子組件
響應(yīng)性直接操作對(duì)象單向數(shù)據(jù)流(只讀)
使用場(chǎng)景獲取 DOM/調(diào)用子組件方法組件參數(shù)傳遞
Vue3 變化不再自動(dòng)數(shù)組形式需要 defineProps 聲明

二、ref 屬性的深度解析

1. 基礎(chǔ)用法

<!-- 獲取 DOM 元素 -->
<template>
  <input ref="inputRef" type="text">
  <ChildComponent ref="childRef" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
// DOM 引用
const inputRef = ref(null)
// 組件引用
const childRef = ref(null)
onMounted(() => {
  inputRef.value.focus() // 操作 DOM
  childRef.value.sayHello() // 調(diào)用子組件方法
})
</script>

2. 組件引用規(guī)范

// 子組件 ChildComponent.vue
<script setup>
// 必須暴露方法才能被父組件調(diào)用
defineExpose({
  sayHello: () => console.log('Hello from child!'),
  childData: ref('子組件數(shù)據(jù)')
})
</script>

3. 類(lèi)型安全(TypeScript)

// 父組件中定義組件引用類(lèi)型
import ChildComponent from './ChildComponent.vue'
const childRef = ref<InstanceType<typeof ChildComponent>>()

三、props 的響應(yīng)式處理

1. 基礎(chǔ)聲明

<!-- 父組件 -->
<ChildComponent :title="parentTitle" />
<!-- 子組件 -->
<script setup>
const props = defineProps({
  title: {
    type: String,
    required: true
  }
})
</script>

2. 保持響應(yīng)性

// 正確方式:使用 toRef
import { toRef } from 'vue'
const title = toRef(props, 'title')
// 錯(cuò)誤!直接解構(gòu)會(huì)失去響應(yīng)性
// const { title } = props

四、聯(lián)合使用場(chǎng)景

場(chǎng)景:表單驗(yàn)證組件

<!-- 父組件 -->
<template>
  <ValidationForm 
    ref="formRef" 
    :rules="validationRules"
    @submit="handleSubmit"
  />
</template>
<script setup>
const formRef = ref(null)
const validationRules = ref({/* 驗(yàn)證規(guī)則 */})
// 調(diào)用子組件方法
const validateForm = () => {
  formRef.value.validate()
}
</script>
<!-- 子組件 ValidationForm.vue -->
<script setup>
defineProps(['rules'])
const validate = () => {
  // 執(zhí)行驗(yàn)證邏輯
}
// 暴露方法給父組件
defineExpose({ validate })
</script>

五、核心差異總結(jié)

對(duì)比維度ref (標(biāo)簽屬性)props
數(shù)據(jù)方向父 → 子(操作子組件/DOM)父 → 子(數(shù)據(jù)傳遞)
可修改性可直接修改子組件暴露的內(nèi)容只讀(需通過(guò)事件通知父組件修改)
響應(yīng)式機(jī)制直接引用對(duì)象需要 toRef 保持響應(yīng)性
典型應(yīng)用DOM操作/調(diào)用子組件方法組件參數(shù)配置
組合式 API通過(guò) ref() 創(chuàng)建引用通過(guò) defineProps 聲明

六、最佳實(shí)踐指南

1. ref 使用原則

  • 最小化暴露:只暴露必要的組件方法/數(shù)據(jù)
  • 避免直接修改:不要通過(guò) ref 直接修改子組件狀態(tài)
  • 配合 TypeScript:使用類(lèi)型定義確保安全訪問(wèn)

2. props 使用規(guī)范

  • 只讀原則:始終視 props 為不可變數(shù)據(jù)
  • 響應(yīng)式轉(zhuǎn)換:使用 toRef 處理需要響應(yīng)式的 props
  • 明確驗(yàn)證:始終定義 props 的類(lèi)型驗(yàn)證

七、常見(jiàn)問(wèn)題解決

Q1: 為什么通過(guò) ref 訪問(wèn)子組件屬性得到 undefined?

原因:子組件未通過(guò) defineExpose 暴露屬性
解決方案

// 子組件
defineExpose({
  publicMethod: () => {/* ... */}
})

Q2: 如何同時(shí)使用 ref 和 v-for?

<template>
  <ChildComponent 
    v-for="item in list" 
    :key="item.id"
    :ref="setItemRef"
  />
</template>
<script setup>
const itemRefs = ref([])
const setItemRef = el => {
  if (el) itemRefs.value.push(el)
}
</script>

Q3: 如何類(lèi)型安全地組合 ref 和 props

// 父組件
import ChildComponent from './ChildComponent.vue'
type ChildComponentExpose = {
  validate: () => boolean
}
const childRef = ref<ChildComponentExpose>()
// 子組件
defineExpose<ChildComponentExpose>({
  validate: () => true
})

八、綜合應(yīng)用示例

父組件

<template>
  <UserForm
    ref="userForm"
    :user-data="formData"
    @submit="handleSubmit"
  />
  <button @click="validateForm">驗(yàn)證表單</button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import UserForm from './UserForm.vue'
type UserFormExpose = {
  validate: () => boolean
  resetForm: () => void
}
const userForm = ref<UserFormExpose>()
const formData = ref({ name: '', email: '' })
const validateForm = () => {
  if (userForm.value?.validate()) {
    console.log('表單驗(yàn)證通過(guò)')
  }
}
const handleSubmit = (data) => {
  console.log('提交數(shù)據(jù):', data)
}
</script>

子組件 UserForm.vue

<template>
  <form @submit.prevent="submitForm">
    <input v-model="localData.name">
    <input v-model="localData.email">
    <button type="submit">提交</button>
  </form>
</template>
<script setup lang="ts">
import { ref, toRefs } from 'vue'
const props = defineProps<{
  userData: {
    name: string
    email: string
  }
}>()
const emit = defineEmits(['submit'])
// 本地副本(避免直接修改 props)
const localData = ref({ ...props.userData })
const validate = () => {
  return localData.value.name.length > 0 
    && localData.value.email.includes('@')
}
const resetForm = () => {
  localData.value = { name: '', email: '' }
}
const submitForm = () => {
  emit('submit', localData.value)
}
defineExpose({
  validate,
  resetForm
})
</script>

關(guān)鍵總結(jié):

  • ref 屬性:用于直接訪問(wèn) DOM/子組件實(shí)例,需要配合 defineExpose 使用
  • props:用于父組件向子組件傳遞數(shù)據(jù),需保持只讀特性
  • 協(xié)作模式:
    • 父組件通過(guò) props 傳遞數(shù)據(jù)
    • 子組件通過(guò)事件通知父組件
    • 必要時(shí)通過(guò) ref 調(diào)用子組件方法
  • 類(lèi)型安全:使用 TypeScript 類(lèi)型定義確??煽吭L問(wèn)

事件傳遞

在 Vue3 中,子組件向父組件傳遞數(shù)據(jù)主要通過(guò) 事件機(jī)制 實(shí)現(xiàn)。以下是 5 種主要實(shí)現(xiàn)方式及其使用場(chǎng)景:

一、基礎(chǔ)事件傳遞 (推薦)

實(shí)現(xiàn)方式
子組件觸發(fā)自定義事件 → 父組件監(jiān)聽(tīng)事件

<!-- 子組件 ChildComponent.vue -->
<script setup>
const emit = defineEmits(['sendData']) // 聲明事件
const sendToParent = () => {
  emit('sendData', { message: 'Hello from child!' }) // 觸發(fā)事件
}
</script>
<template>
  <button @click="sendToParent">發(fā)送數(shù)據(jù)</button>
</template>
<!-- 父組件 ParentComponent.vue -->
<template>
  <ChildComponent @send-data="handleData" />
</template>
<script setup>
const handleData = (payload) => {
  console.log(payload.message) // 輸出:Hello from child!
}
</script>

最佳實(shí)踐

  • 使用 kebab-case 事件名(如 send-data
  • 通過(guò) TypeScript 定義事件類(lèi)型:
const emit = defineEmits<{
  (e: 'sendData', payload: { message: string }): void
}>()

二、v-model 雙向綁定 (表單場(chǎng)景推薦)

實(shí)現(xiàn)原理
v-model 是 :modelValue + @update:modelValue 的語(yǔ)法糖

<!-- 子組件 InputComponent.vue -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
const updateValue = (e) => {
  emit('update:modelValue', e.target.value)
}
</script>
<template>
  <input 
    :value="modelValue" 
    @input="updateValue"
  >
</template>
<!-- 父組件 -->
<template>
  <InputComponent v-model="inputValue" />
</template>
<script setup>
const inputValue = ref('')
</script>

多 v-model 綁定

<ChildComponent 
  v-model:name="userName"
  v-model:age="userAge"
/>

三、異步回調(diào)模式 (需要返回值時(shí))

適用場(chǎng)景:需要等待父組件處理結(jié)果的異步操作

<!-- 子組件 -->
<script setup>
const emit = defineEmits(['request'])
const handleClick = async () => {
  const response = await emit('request', { id: 123 })
  console.log('父組件返回:', response)
}
</script>
<!-- 父組件 -->
<template>
  <ChildComponent @request="handleRequest" />
</template>
<script setup>
const handleRequest = async (payload) => {
  const data = await fetchData(payload.id)
  return data // 返回給子組件
}
</script>

四、Expose 方法調(diào)用 (需要直接訪問(wèn)子組件)

<!-- 子組件 -->
<script setup>
const childData = ref('子組件數(shù)據(jù)')
defineExpose({
  getData: () => childData.value,
  updateData: (newVal) => childData.value = newVal
})
</script>
<!-- 父組件 -->
<template>
  <ChildComponent ref="childRef" />
</template>
<script setup>
const childRef = ref(null)
const getChildData = () => {
  console.log(childRef.value?.getData()) // 輸出:子組件數(shù)據(jù)
  childRef.value?.updateData('新數(shù)據(jù)')
}
</script>

五、狀態(tài)管理方案 (跨組件通信)

適用場(chǎng)景:多層嵌套組件或兄弟組件通信

// store/counter.js
import { reactive } from 'vue'
export const counterStore = reactive({
  count: 0,
  increment() {
    this.count++
  }
})
<!-- 子組件 -->
<script setup>
import { counterStore } from './store/counter'
const updateCount = () => {
  counterStore.increment()
}
</script>
<!-- 父組件 -->
<script setup>
import { counterStore } from './store/counter'
</script>
<template>
  當(dāng)前計(jì)數(shù):{{ counterStore.count }}
</template>

方法對(duì)比表

方法適用場(chǎng)景優(yōu)點(diǎn)缺點(diǎn)
基礎(chǔ)事件傳遞簡(jiǎn)單數(shù)據(jù)傳遞直觀明確多層嵌套時(shí)需逐層傳遞
v-model 綁定表單輸入組件語(yǔ)法簡(jiǎn)潔僅適用簡(jiǎn)單雙向綁定
異步回調(diào)模式需要父組件響應(yīng)結(jié)果支持異步交互邏輯復(fù)雜度稍高
Expose 方法需要直接操作子組件靈活性強(qiáng)破壞組件封裝性
狀態(tài)管理跨組件/復(fù)雜場(chǎng)景解耦組件關(guān)系需要額外學(xué)習(xí)成本

最佳實(shí)踐指南

  • 優(yōu)先使用事件傳遞:保持組件獨(dú)立性
  • 復(fù)雜場(chǎng)景用狀態(tài)管理:Pinia 是 Vue3 官方推薦方案
  • v-model 用于表單:保持雙向綁定的簡(jiǎn)潔性
  • 避免濫用 ref:防止組件過(guò)度耦合
  • TypeScript 類(lèi)型定義
// 事件類(lèi)型定義
defineEmits<{
  (e: 'updateData', payload: { id: number }): void
  (e: 'cancel'): void
}>()
// Props 類(lèi)型定義
defineProps<{
  userId: number
  userName: string
}>()

完整示例:購(gòu)物車(chē)組件交互

<template>
  <div class="cart-item">
    <span>{{ item.name }}</span>
    <input 
      type="number" 
      :value="item.quantity"
      @input="updateQuantity($event.target.value)"
    >
    <button @click="emit('remove', item.id)">刪除</button>
  </div>
</template>
<!-- 子組件 CartItem.vue -->
<script setup>
const props = defineProps({
  item: {
    type: Object,
    required: true
  }
})
const emit = defineEmits(['update:quantity', 'remove'])
const updateQuantity = (newQty) => {
  emit('update:quantity', {
    id: props.item.id, 
    qty: newQty
  })
}
</script>
<template>
  <CartItem 
    v-for="item in cartItems"
    :key="item.id"
    :item="item"
    @update:quantity="handleUpdate"
    @remove="handleRemove"
  />
</template>
<!-- 父組件 ShoppingCart.vue -->
<script setup>
const cartItems = ref([
  { id: 1, name: '商品A', quantity: 2 },
  { id: 2, name: '商品B', quantity: 1 }
])
const handleUpdate = ({ id, qty }) => {
  const item = cartItems.value.find(i => i.id === id)
  if (item) item.quantity = Number(qty)
}
const handleRemove = (id) => {
  cartItems.value = cartItems.value.filter(i => i.id !== id)
}
</script>

到此這篇關(guān)于Vue3 中的ref與props的文章就介紹到這了,更多相關(guān)Vue3 ref與props內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 前端本地存儲(chǔ)方案localForage在vue3中使用方法

    前端本地存儲(chǔ)方案localForage在vue3中使用方法

    localForage是前端本地存儲(chǔ)的庫(kù),支持多種存儲(chǔ)后端,并提供了一致的API來(lái)存儲(chǔ)和檢索數(shù)據(jù),這篇文章主要給大家介紹了關(guān)于前端本地存儲(chǔ)方案localForage在vue3中使用的相關(guān)資料,需要的朋友可以參考下
    2024-09-09
  • vue 簡(jiǎn)單自動(dòng)補(bǔ)全的輸入框的示例

    vue 簡(jiǎn)單自動(dòng)補(bǔ)全的輸入框的示例

    這篇文章主要介紹了vue 簡(jiǎn)單自動(dòng)補(bǔ)全的輸入框的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • vue+element實(shí)現(xiàn)動(dòng)態(tài)換膚的示例代碼

    vue+element實(shí)現(xiàn)動(dòng)態(tài)換膚的示例代碼

    本文主要介紹了vue+element實(shí)現(xiàn)動(dòng)態(tài)換膚的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • uniapp+vue3路由跳轉(zhuǎn)傳參的實(shí)現(xiàn)

    uniapp+vue3路由跳轉(zhuǎn)傳參的實(shí)現(xiàn)

    本文主要介紹了uniapp+vue3路由跳轉(zhuǎn)傳參的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-11-11
  • Vue中textarea自適應(yīng)高度方案的實(shí)現(xiàn)

    Vue中textarea自適應(yīng)高度方案的實(shí)現(xiàn)

    本文主要介紹了Vue中textarea自適應(yīng)高度方案的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • vue仿淘寶訂單狀態(tài)的tab切換效果

    vue仿淘寶訂單狀態(tài)的tab切換效果

    這篇文章主要為大家詳細(xì)介紹了vue仿淘寶訂單狀態(tài)tab切換效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • vue3(vite)設(shè)置代理封裝axios api解耦功能

    vue3(vite)設(shè)置代理封裝axios api解耦功能

    這篇文章主要介紹了vue3(vite)設(shè)置代理封裝axios api解耦,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • 使用vue3搭建后臺(tái)系統(tǒng)的詳細(xì)步驟

    使用vue3搭建后臺(tái)系統(tǒng)的詳細(xì)步驟

    這篇文章主要介紹了使用vue3搭建后臺(tái)系統(tǒng)的過(guò)程記錄,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • vue項(xiàng)目input標(biāo)簽checkbox,change和click綁定事件的區(qū)別說(shuō)明

    vue項(xiàng)目input標(biāo)簽checkbox,change和click綁定事件的區(qū)別說(shuō)明

    這篇文章主要介紹了vue項(xiàng)目input標(biāo)簽checkbox,change和click綁定事件的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • vue中如何實(shí)現(xiàn)拖拽調(diào)整順序功能

    vue中如何實(shí)現(xiàn)拖拽調(diào)整順序功能

    這篇文章主要介紹了vue中如何實(shí)現(xiàn)拖拽調(diào)整順序功能問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05

最新評(píng)論