最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue實(shí)現(xiàn)父子組件通信的八種方式

 更新時(shí)間:2025年11月11日 09:29:43   作者:良山有風(fēng)來(lái)  
你是不是經(jīng)常遇到這樣的場(chǎng)景?父組件的數(shù)據(jù)要傳給子組件,子組件的事件要通知父組件,兄弟組件之間要共享狀態(tài)...每次寫(xiě)Vue組件通信都覺(jué)得頭大,不知道用哪種方式最合適? 別擔(dān)心!今天我就帶你徹底搞懂Vue

你是不是經(jīng)常遇到這樣的場(chǎng)景?父組件的數(shù)據(jù)要傳給子組件,子組件的事件要通知父組件,兄弟組件之間要共享狀態(tài)...每次寫(xiě)Vue組件通信都覺(jué)得頭大,不知道用哪種方式最合適?

別擔(dān)心!今天我就帶你徹底搞懂Vue組件通信的8種核心方式,每種方式都有詳細(xì)的代碼示例和適用場(chǎng)景分析??赐赀@篇文章,你就能根據(jù)具體業(yè)務(wù)場(chǎng)景選擇最合適的通信方案,再也不用為組件間傳值發(fā)愁了!

Props:最基礎(chǔ)的父子通信

Props是Vue中最基礎(chǔ)也是最常用的父子組件通信方式。父組件通過(guò)屬性向下傳遞數(shù)據(jù),子組件通過(guò)props選項(xiàng)接收。

// 子組件 ChildComponent.vue
<template>
  <div>
    <h3>子組件接收到的消息:{{ message }}</h3>
    <p>用戶(hù)年齡:{{ userInfo.age }}</p>
  </div>
</template>

<script>
export default {
  // 定義props,可以指定類(lèi)型和默認(rèn)值
  props: {
    message: {
      type: String,
      required: true  // 必須傳遞這個(gè)prop
    },
    userInfo: {
      type: Object,
      default: () => ({})  // 默認(rèn)空對(duì)象
    }
  }
}
</script>

// 父組件 ParentComponent.vue
<template>
  <div>
    <child-component 
      :message="parentMessage" 
      :user-info="userData"
    />
  </div>
</template>

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

export default {
  components: { ChildComponent },
  data() {
    return {
      parentMessage: '來(lái)自父組件的問(wèn)候',
      userData: {
        name: '小明',
        age: 25
      }
    }
  }
}
</script>

適用場(chǎng)景:簡(jiǎn)單的父子組件數(shù)據(jù)傳遞,數(shù)據(jù)流清晰明確。但要注意,props是單向數(shù)據(jù)流,子組件不能直接修改props。

$emit:子組件向父組件通信

當(dāng)子組件需要向父組件傳遞數(shù)據(jù)或觸發(fā)父組件的某個(gè)方法時(shí),就需要用到$emit。子組件通過(guò)觸發(fā)自定義事件,父組件通過(guò)v-on監(jiān)聽(tīng)這些事件。

// 子組件 SubmitButton.vue
<template>
  <button @click="handleClick">
    提交表單
  </button>
</template>

<script>
export default {
  methods: {
    handleClick() {
      // 觸發(fā)自定義事件,并傳遞數(shù)據(jù)
      this.$emit('form-submit', {
        timestamp: new Date(),
        formData: this.formData
      })
    }
  }
}
</script>

// 父組件 FormContainer.vue
<template>
  <div>
    <submit-button @form-submit="handleFormSubmit" />
  </div>
</template>

<script>
import SubmitButton from './SubmitButton.vue'

export default {
  components: { SubmitButton },
  methods: {
    handleFormSubmit(payload) {
      console.log('接收到子組件的數(shù)據(jù):', payload)
      // 這里可以處理表單提交邏輯
      this.submitToServer(payload.formData)
    }
  }
}
</script>

適用場(chǎng)景:子組件需要通知父組件某個(gè)事件發(fā)生,或者需要傳遞數(shù)據(jù)給父組件處理。

ref:直接訪問(wèn)子組件實(shí)例

通過(guò)ref屬性,父組件可以直接訪問(wèn)子組件的實(shí)例,調(diào)用其方法或訪問(wèn)其數(shù)據(jù)。

// 子組件 CustomInput.vue
<template>
  <input 
    ref="inputRef" 
    v-model="inputValue" 
    type="text"
  />
</template>

<script>
export default {
  data() {
    return {
      inputValue: ''
    }
  },
  methods: {
    // 子組件的自定義方法
    focus() {
      this.$refs.inputRef.focus()
    },
    clear() {
      this.inputValue = ''
    },
    getValue() {
      return this.inputValue
    }
  }
}
</script>

// 父組件 ParentComponent.vue
<template>
  <div>
    <custom-input ref="myInput" />
    <button @click="handleFocus">聚焦輸入框</button>
    <button @click="handleClear">清空輸入框</button>
  </div>
</template>

<script>
import CustomInput from './CustomInput.vue'

export default {
  components: { CustomInput },
  methods: {
    handleFocus() {
      // 通過(guò)ref直接調(diào)用子組件的方法
      this.$refs.myInput.focus()
    },
    handleClear() {
      // 調(diào)用子組件的清空方法
      this.$refs.myInput.clear()
      
      // 也可以直接訪問(wèn)子組件的數(shù)據(jù)(不推薦)
      // this.$refs.myInput.inputValue = ''
    }
  }
}
</script>

適用場(chǎng)景:需要直接操作子組件的DOM元素或調(diào)用子組件方法的場(chǎng)景。但要謹(jǐn)慎使用,避免破壞組件的封裝性。

Event Bus:任意組件間通信

Event Bus通過(guò)創(chuàng)建一個(gè)空的Vue實(shí)例作為事件中心,實(shí)現(xiàn)任意組件間的通信,特別適合非父子組件的情況。

// event-bus.js - 創(chuàng)建事件總線
import Vue from 'vue'
export const EventBus = new Vue()

// 組件A - 事件發(fā)送者
<template>
  <button @click="sendMessage">發(fā)送全局消息</button>
</template>

<script>
import { EventBus } from './event-bus'

export default {
  methods: {
    sendMessage() {
      // 觸發(fā)全局事件
      EventBus.$emit('global-message', {
        text: 'Hello from Component A!',
        from: 'ComponentA'
      })
    }
  }
}
</script>

// 組件B - 事件監(jiān)聽(tīng)者
<template>
  <div>
    <p>最新消息:{{ latestMessage }}</p>
  </div>
</template>

<script>
import { EventBus } from './event-bus'

export default {
  data() {
    return {
      latestMessage: ''
    }
  },
  mounted() {
    // 監(jiān)聽(tīng)全局事件
    EventBus.$on('global-message', (payload) => {
      this.latestMessage = `${payload.from} 說(shuō):${payload.text}`
    })
  },
  beforeDestroy() {
    // 組件銷(xiāo)毀前移除事件監(jiān)聽(tīng),防止內(nèi)存泄漏
    EventBus.$off('global-message')
  }
}
</script>

適用場(chǎng)景:簡(jiǎn)單的跨組件通信,小型項(xiàng)目中的狀態(tài)管理。但在復(fù)雜項(xiàng)目中建議使用Vuex或Pinia。

provide/inject:依賴(lài)注入

provide和inject主要用于高階組件開(kāi)發(fā),允許祖先組件向其所有子孫后代注入依賴(lài),而不需要層層傳遞props。

// 祖先組件 Ancestor.vue
<template>
  <div>
    <middle-component />
  </div>
</template>

<script>
export default {
  // 提供數(shù)據(jù)和方法
  provide() {
    return {
      // 提供響應(yīng)式數(shù)據(jù)
      appTheme: this.theme,
      // 提供方法
      changeTheme: this.changeTheme,
      // 提供常量
      appName: '我的Vue應(yīng)用'
    }
  },
  data() {
    return {
      theme: 'dark'
    }
  },
  methods: {
    changeTheme(newTheme) {
      this.theme = newTheme
    }
  }
}
</script>

// 深層子組件 DeepChild.vue
<template>
  <div :class="`theme-${appTheme}`">
    <h3>應(yīng)用名稱(chēng):{{ appName }}</h3>
    <button @click="changeTheme('light')">切換亮色主題</button>
    <button @click="changeTheme('dark')">切換暗色主題</button>
  </div>
</template>

<script>
export default {
  // 注入祖先組件提供的數(shù)據(jù)
  inject: ['appTheme', 'changeTheme', 'appName'],
  
  // 也可以指定默認(rèn)值和來(lái)源
  // inject: {
  //   theme: {
  //     from: 'appTheme',
  //     default: 'light'
  //   }
  // }
}
</script>

適用場(chǎng)景:組件層級(jí)很深,需要避免props逐層傳遞的麻煩。常用于開(kāi)發(fā)組件庫(kù)或大型應(yīng)用的基礎(chǔ)配置。

attrs/attrs/attrs/listeners:跨層級(jí)屬性傳遞

attrs包含了父組件傳入的所有非props屬性,attrs包含了父組件傳入的所有非props屬性,attrs包含了父組件傳入的所有非props屬性,listeners包含了父組件傳入的所有事件監(jiān)聽(tīng)器,可以用于創(chuàng)建高階組件。

// 中間組件 MiddleComponent.vue
<template>
  <div>
    <!-- 傳遞所有屬性和事件到子組件 -->
    <child-component v-bind="$attrs" v-on="$listeners" />
  </div>
</template>

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

export default {
  components: { ChildComponent },
  inheritAttrs: false, // 不讓屬性綁定到根元素
  mounted() {
    console.log('$attrs:', this.$attrs) // 所有非props屬性
    console.log('$listeners:', this.$listeners) // 所有事件監(jiān)聽(tīng)器
  }
}
</script>

// 最終子組件 ChildComponent.vue
<template>
  <input
    v-bind="$attrs"
    v-on="$listeners"
    class="custom-input"
  />
</template>

<script>
export default {
  mounted() {
    // 可以直接使用父組件傳遞的所有屬性和事件
    console.log('接收到的屬性:', this.$attrs)
  }
}
</script>

// 父組件使用
<template>
  <middle-component
    placeholder="請(qǐng)輸入內(nèi)容"
    maxlength="20"
    @focus="handleFocus"
    @blur="handleBlur"
  />
</template>

適用場(chǎng)景:創(chuàng)建包裝組件、高階組件,需要透?jìng)鲗傩院褪录膱?chǎng)景。

Vuex:集中式狀態(tài)管理

Vuex是Vue的官方狀態(tài)管理庫(kù),適用于中大型復(fù)雜應(yīng)用的狀態(tài)管理。

// store/index.js
import { createStore } from 'vuex'

const store = createStore({
  state() {
    return {
      count: 0,
      user: null,
      loading: false
    }
  },
  mutations: {
    // 同步修改狀態(tài)
    increment(state) {
      state.count++
    },
    setUser(state, user) {
      state.user = user
    },
    setLoading(state, loading) {
      state.loading = loading
    }
  },
  actions: {
    // 異步操作
    async login({ commit }, credentials) {
      commit('setLoading', true)
      try {
        const user = await api.login(credentials)
        commit('setUser', user)
        return user
      } finally {
        commit('setLoading', false)
      }
    }
  },
  getters: {
    // 計(jì)算屬性
    isLoggedIn: state => !!state.user,
    doubleCount: state => state.count * 2
  }
})

// 組件中使用
<template>
  <div>
    <p>計(jì)數(shù)器:{{ count }}</p>
    <p>雙倍計(jì)數(shù):{{ doubleCount }}</p>
    <p v-if="isLoggedIn">歡迎,{{ user.name }}!</p>
    <button @click="increment">增加</button>
    <button @click="login" :disabled="loading">
      {{ loading ? '登錄中...' : '登錄' }}
    </button>
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'

export default {
  computed: {
    // 映射state和getters到計(jì)算屬性
    ...mapState(['count', 'user', 'loading']),
    ...mapGetters(['doubleCount', 'isLoggedIn'])
  },
  methods: {
    // 映射mutations和actions到方法
    ...mapMutations(['increment']),
    ...mapActions(['login'])
  }
}
</script>

適用場(chǎng)景:中大型復(fù)雜應(yīng)用,多個(gè)組件需要共享狀態(tài),需要嚴(yán)格的狀態(tài)管理流程。

Pinia:新一代狀態(tài)管理

Pinia是Vue官方推薦的新一代狀態(tài)管理庫(kù),相比Vuex更加輕量、直觀,并且完美支持TypeScript。

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
    name: '我的計(jì)數(shù)器'
  }),
  
  getters: {
    doubleCount: (state) => state.count * 2,
    // 使用this訪問(wèn)其他getter
    doubleCountPlusOne() {
      return this.doubleCount + 1
    }
  },
  
  actions: {
    increment() {
      this.count++
    },
    async incrementAsync() {
      // 異步action
      await new Promise(resolve => setTimeout(resolve, 1000))
      this.increment()
    },
    reset() {
      this.count = 0
    }
  }
})

// 組件中使用
<template>
  <div>
    <h3>{{ name }}</h3>
    <p>當(dāng)前計(jì)數(shù):{{ count }}</p>
    <p>雙倍計(jì)數(shù):{{ doubleCount }}</p>
    <button @click="increment">增加</button>
    <button @click="incrementAsync">異步增加</button>
    <button @click="reset">重置</button>
  </div>
</template>

<script>
import { useCounterStore } from '@/stores/counter'

export default {
  setup() {
    const counterStore = useCounterStore()
    
    // 可以直接解構(gòu),但會(huì)失去響應(yīng)式
    // 使用storeToRefs保持響應(yīng)式
    const { name, count, doubleCount } = counterStore
    
    return {
      // state和getters
      name,
      count,
      doubleCount,
      // actions
      increment: counterStore.increment,
      incrementAsync: counterStore.incrementAsync,
      reset: counterStore.reset
    }
  }
}
</script>

// 在多個(gè)store之間交互
import { useUserStore } from '@/stores/user'

export const useCartStore = defineStore('cart', {
  actions: {
    async checkout() {
      const userStore = useUserStore()
      
      if (!userStore.isLoggedIn) {
        await userStore.login()
      }
      
      // 結(jié)賬邏輯...
    }
  }
})

適用場(chǎng)景:現(xiàn)代Vue應(yīng)用的狀態(tài)管理,特別是需要TypeScript支持和更簡(jiǎn)潔API的項(xiàng)目。

實(shí)戰(zhàn)場(chǎng)景選擇指南

現(xiàn)在你已經(jīng)了解了8種Vue組件通信方式,但在實(shí)際開(kāi)發(fā)中該如何選擇呢?我來(lái)給你一些實(shí)用建議:

如果是簡(jiǎn)單的父子組件通信,優(yōu)先考慮props和$emit,這是最直接的方式。

當(dāng)組件層級(jí)較深,需要避免props逐層傳遞時(shí),provide/inject是不錯(cuò)的選擇。

對(duì)于非父子組件間的簡(jiǎn)單通信,Event Bus可以快速解決問(wèn)題,但要注意事件管理。

在需要?jiǎng)?chuàng)建高階組件或包裝組件時(shí),attrs和attrs和attrslisteners能大大簡(jiǎn)化代碼。

對(duì)于中大型復(fù)雜應(yīng)用,需要集中管理狀態(tài)時(shí),Vuex或Pinia是必備的。個(gè)人更推薦Pinia,因?yàn)樗F(xiàn)代、更簡(jiǎn)潔。

如果需要直接操作子組件,ref提供了最直接的方式,但要謹(jǐn)慎使用以保持組件的封裝性。

記住,沒(méi)有最好的通信方式,只有最適合當(dāng)前場(chǎng)景的方式。在實(shí)際項(xiàng)目中,往往是多種方式結(jié)合使用。

寫(xiě)在最后

組件通信是Vue開(kāi)發(fā)中的核心技能,掌握這些通信方式就像掌握了組件間的"對(duì)話語(yǔ)言"。從簡(jiǎn)單的props/$emit到復(fù)雜的Pinia狀態(tài)管理,每種方式都有其獨(dú)特的價(jià)值和適用場(chǎng)景。

關(guān)鍵是要理解每種方式的原理和優(yōu)缺點(diǎn),在實(shí)際開(kāi)發(fā)中根據(jù)組件關(guān)系、數(shù)據(jù)流復(fù)雜度、項(xiàng)目規(guī)模等因素做出合適的選擇。

你現(xiàn)在對(duì)Vue組件通信是不是有了更清晰的認(rèn)識(shí)?在實(shí)際項(xiàng)目中,你最喜歡用哪種通信方式?有沒(méi)有遇到過(guò)特別的通信難題?

以上就是Vue實(shí)現(xiàn)父子組件通信的八種方式的詳細(xì)內(nèi)容,更多關(guān)于Vue父子組件通信的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue3基礎(chǔ)知識(shí)剖析

    vue3基礎(chǔ)知識(shí)剖析

    筆者這篇文章會(huì)從vue3基礎(chǔ)的知識(shí)點(diǎn)開(kāi)始剖析,特別是在將composition?API的時(shí)候,在代碼示例中不會(huì)一上來(lái)就使用setup語(yǔ)法糖,而是用早期的setup函數(shù),這樣方便于初學(xué)的小伙伴們理解跟學(xué)習(xí)
    2022-08-08
  • vue使用axios上傳文件(FormData)的方法

    vue使用axios上傳文件(FormData)的方法

    這篇文章主要介紹了vue使用axios上傳文件(FormData)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • Vue多頁(yè)項(xiàng)目實(shí)現(xiàn)在每次版本更新時(shí)做提示的解決方案

    Vue多頁(yè)項(xiàng)目實(shí)現(xiàn)在每次版本更新時(shí)做提示的解決方案

    項(xiàng)目中使用懶加載方式加載組件,在新部署鏡像后,由于瀏覽器緩存又去加載舊的js chunk,但是之時(shí)舊的js chunk已經(jīng)不存在,加載不出來(lái)造成bug,所以本文給大家介紹了Vue多頁(yè)項(xiàng)目實(shí)現(xiàn)在每次版本更新時(shí)做提示的解決方案,需要的朋友可以參考下
    2025-11-11
  • Vue+Echarts實(shí)現(xiàn)簡(jiǎn)單折線圖

    Vue+Echarts實(shí)現(xiàn)簡(jiǎn)單折線圖

    這篇文章主要為大家詳細(xì)介紹了Vue+Echarts實(shí)現(xiàn)簡(jiǎn)單折線圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Vue.js項(xiàng)目部署到服務(wù)器的詳細(xì)步驟

    Vue.js項(xiàng)目部署到服務(wù)器的詳細(xì)步驟

    這篇文章給大家介紹了Vue.js項(xiàng)目部署到服務(wù)器的詳細(xì)步驟,既然是部署到服務(wù)器,肯定是需要一個(gè)云的。具體思路步驟大家可以參考下本文
    2017-07-07
  • Vue組件化常用方法之組件傳值與通信

    Vue組件化常用方法之組件傳值與通信

    這篇文章主要給大家介紹了關(guān)于Vue組件化常用方法之組件傳值與通信的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Vue3.x的版本中build后dist文件中出現(xiàn)legacy的js文件問(wèn)題

    Vue3.x的版本中build后dist文件中出現(xiàn)legacy的js文件問(wèn)題

    這篇文章主要介紹了Vue3.x的版本中build后dist文件中出現(xiàn)legacy的js文件問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • 詳解Vue項(xiàng)目的打包方式(生成dist文件)

    詳解Vue項(xiàng)目的打包方式(生成dist文件)

    本文主要介紹了詳解Vue項(xiàng)目的打包方式(生成dist文件),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Vue+Ant Design開(kāi)發(fā)簡(jiǎn)單表格組件的實(shí)戰(zhàn)指南

    Vue+Ant Design開(kāi)發(fā)簡(jiǎn)單表格組件的實(shí)戰(zhàn)指南

    在現(xiàn)代前端開(kāi)發(fā)中,數(shù)據(jù)表格是展示信息最常用的組件之一,本文主要為大家介紹了一個(gè)基于Vue和Ant Design的表格組件開(kāi)發(fā)過(guò)程,感興趣的可以了解下
    2025-06-06
  • 使用vue-router設(shè)置每個(gè)頁(yè)面的title方法

    使用vue-router設(shè)置每個(gè)頁(yè)面的title方法

    下面小編就為大家分享一篇使用vue-router設(shè)置每個(gè)頁(yè)面的title方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02

最新評(píng)論

枣庄市| 大洼县| 大同县| 汤阴县| 崇礼县| 英德市| 疏附县| 西丰县| 宣武区| 嘉义县| 丰镇市| 鸡东县| 三明市| 蒙阴县| 攀枝花市| 封开县| 澄城县| 天台县| 肇州县| 阳春市| 湘乡市| 泰宁县| 延边| 昌都县| 息烽县| 冕宁县| 德安县| 武清区| 曲阜市| 昌黎县| 平舆县| 越西县| 闵行区| 元阳县| 嘉荫县| 彭阳县| 全州县| 香河县| 清新县| 礼泉县| 鄂尔多斯市|