vue的組件通訊方法總結大全
1.通過屬性傳值props??
父組件向子組件傳送數據,這應該是最常用的方式了
子組件接收到數據之后,不能直接修改父組件的數據。會報錯,所以當父組件重新渲染時,數據會被覆蓋。如果子組件內想要修改的話,推薦使用computedprops 可以是數組或對象,用于接收來自父組件的數據。
// 父組件 List.vue
<template>
<div>
<List-item :str="str" :obj="obj" :arr="arr"></List-item>
</div>
</template>
<script>
import ListItem from "./ListItem";
export default {
data() {
return {
str: "給子組件傳值",
obj: {msg: "給子組件傳值"},
arr: [1, 2, 3]
}
},
components: {
ListItem
}
}
</script>
// 子組件 ListItem.vue
<template>
<div>
<div>{{msg}}</div>
<div>{{obj}}</div>
<div>{{arr}}</div>
</div>
</template>
<script>
export default {
props: {
msg: String, // props是字符串
obj: Object, // props是對象
arr: Array // props是數組
}
}
</script>
2.修飾符 .sync??
修飾符 .sync,它對 props 起到了一種修飾的作用,使用 .sync 進行修飾的 props 意味子組件有修改它的意圖,這種情況下它只起到一個標注性作用,有它沒它都不會影響邏輯
使用 .sync 修改上邊的代碼:
// 父組件 List.vue
<template>
<!-- 這里不寫 .sync 也不會影響結果 -->
<List-item :title.sync="title" @update:title="updataTitle"></List-item>
</template>
<script>
import ListItem from "./ListItem";
export default {
data() {
return {
title: "我是title",
}
},
components: {
ListItem
},
methods: {
updataTitle(res) {
this.title = res;
}
}
}
</script>
// 子組件 ListItem.vue
<template>
<div>
<button @click="handleClick">Click me</button>
<div>{{title}}</div>
</div>
</template>
<script>
export default {
props: {
title: String,
},
methods: {
handleClick() {
// 子組件向父組件傳值
this.$emit('update:title', '我要父組件更新 title');
}
}
}
</script>
3.使用.sync 向子組件傳遞 多個props:??
當我們用一個對象同時設置多個 prop 的時候,也可以將這個 .sync 修飾符和 v-bind 配合使用:
<text-document v-bind.sync="doc"></text-document>
這樣會把 doc 對象中的每一個屬性 (如 title) 都作為一個獨立的 prop 傳進去,然后各自添加用于更新的 v-on 監(jiān)聽器。
4.通過 ref 注冊子組件引用??
盡管存在 prop 和事件,有的時候你仍可能需要在 JavaScript 里直接訪問一個子組件。為了達到這個目的,可以通過 ref 特性為這個子組件賦予一個 ID 引用。
<template>
<div>
<List-item ref="item" :title="title"></List-item>
<div>{{data}}</div>
</div>
</template>
<script>
import ListItem from "./List-item";
export default {
data() {
return {
title: "我是title",
data: ""
}
},
components: {
ListItem
},
mounted() {
this.data = this.$refs.item.message;
}
}
</script>
5.通過$parent獲取父組件實例的方法或者屬性??
這種方式,從嚴格意思上講不是值的傳遞,而是一種"取"(不推薦直接通過實例進行值的獲?。?。
可以通過 Vue 的實例屬性 $parent 獲得父組件的實例,借助實例可以調用父實例中的方法,或者獲取父實例上的屬性,從而達到取值的目的。
// 父組件 List.vue
...
<script>
export default {
data() {
return {
message: "hello children",
msg: "hello"
}
},
methods: {
sendMessage() {
return this.message;
}
}
}
</script>
// 子組件 ListItem.vue
<template>
<div>
<div>{{data}}</div>
<div>{{msg}}</div>
</div>
</template>
<script>
export default {
data() {
return {
data: "",
msg: ""
}
},
mounted() {
this.data = this.$parent.sendMessage(); // 調用父實例中的方法
this.msg = this.$parent.msg; // 獲取父實例中的屬性
}
}
</script>
??????:
- 通過
$parent獲取父實例this.$parent.event。 - 通過
props傳遞方法。 - 通過
$emit監(jiān)聽父組件中的方法this.$emit("envnt")。
6. 通過事件傳值 $emit??
子組件使用 $emit 發(fā)送一個自定義事件,事件名稱是一個字符串。
父組件使用指令 v-on 綁定子組件發(fā)送的自定義事件。
// 父組件 List.vue
<template>
<div>
<!-- 監(jiān)聽自定義事件 -->
<List-item v-on:welcome="getWelcome"></List-item>
</div>
</template>
<script>
import ListItem from "./List-item";
export default {
components: {
ListItem
},
methods: {
getWelcome(data) {
alert(data)
}
}
}
</script>
// 子組件 ListItem.vue
<template>
<button @click="handleClick">Click me</button>
</template>
<script>
export default {
methods: {
handleClick() {
// 使用 $emit 發(fā)送自定義事件 welcome
this.$emit('welcome', 'hello');
}
}
}
</script>
7.$children??
獲取父組件下的所有子組件的實例,返回的是一個數組 使用范圍:該屬性只針對vue組件,與js中childNodes還是有區(qū)別的。
$ildren: 獲取子組件實例集合hildNodes: 獲取子節(jié)點集合使用方法:
<template>
<A></A>
<B></B>
</template>
<script>
export default{
data(){},
mounted(){
// 通過$children可以獲取到A和B兩個子組件的實例
console.log('children:',this.$children)
}
}
</script>
其中,
this.$children[0]
可以獲取到A組件的實例,一樣的,我們可以使用A組件的屬性以及他的方法。
8.Vuex??
Vuex介紹
Vuex是一個專為 Vue.js 應用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應用的所有組件的狀態(tài),并以相應的規(guī)則保證狀態(tài)以一種可預測的方式發(fā)生變化.Vuex解決了多個視圖依賴于同一狀態(tài)和來自不同視圖的行為需要變更同一狀態(tài)的問題,將開發(fā)者的精力聚焦于數據的更新而不是數據在組件之間的傳遞上
Vuex各個模塊
state:用于數據的存儲,是store中的唯一數據源getters:如vue中的計算屬性一樣,基于state數據的二次包裝,常用于數據的篩選和多個數據的相關性計算mutations:類似函數,改變state數據的唯一途徑,且不能用于處理異步事件actions:類似于mutation,用于提交mutation來改變狀態(tài),而不直接變更狀態(tài),可以包含任意異步操作modules:類似于命名空間,用于項目中將各個模塊的狀態(tài)分開定義和操作,便于維護
Vuex實例應用
這里我們先新建 store文件夾, 對Vuex進行一些封裝處理
在 store 文件夾下添加 index.js 文件
// index.js
// 自動掛載指定目錄下的store
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
let modules = {}
// @/store/module 目錄下的文件自動掛載為 store 模塊
const subModuleList = require.context('@/store/modules', false, /.js$/)
subModuleList.keys().forEach(subRouter => {
const moduleName = subRouter.substring(2, subRouter.length - 3)
modules[moduleName] = subModuleList(subRouter).default
})
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules
})
在 store 文件夾下添加 module 文件夾,在module文件夾再新建 user.js 文件
// user.js
import user from '@/utils/user.js'
import userApi from '@/apis/user'
import { OPEN_ACCOUNT_STAGE, STAGE_STATUS } from '@/constant'
let getUserPromise = null
export default {
namespaced: true,
state() {
return {
userInfo: null, // 用戶信息
isLogined: !!user.getToken(), // 是否已經登錄
}
},
mutations: {
// 更新用戶信息
updateUser(state, payload) {
state.isLogined = !!payload
state.userInfo = payload
},
},
actions: {
// 獲取當前用戶信息
async getUserInfo(context, payload) {
// forceUpdate 表示是否強制更新
if (context.state.userInfo && !payload?.forceUpdate) {
return context.state.userInfo
}
if (!getUserPromise || payload?.forceUpdate) {
getUserPromise = userApi.getUserInfo()
}
// 獲取用戶信息
try {
const userInfo = await getUserPromise
context.commit('updateUser', userInfo)
} finally {
getUserPromise = null
}
return context.state.userInfo
},
// 登出
async logout(context, payload = {}) {
// 是否手動退出
const { manual } = payload
if (manual) {
await userApi.postLogout()
}
user.clearToken()
context.commit('updateUser', null)
},
}
}
然后在項目的 main.js 文件中引入
import Vue from 'vue'
import App from '@/app.vue'
import { router } from '@/router'
import store from '@/store/index'
const vue = new Vue({
el: '#app',
name: 'root',
router,
store,
render: h => h(App),
})
封裝完成,即可正常操縱
this.$store.state.user.isLogined
this.$store.state.user.userInfo
this.$store.commit('user/updateUser', {})
await this.$store.dispatch('user/logout', { manual: true })
9.eventBus??
ventBus夠簡化各組件間的通信,讓我們的代碼書寫變得簡單,能有效的分離事件發(fā)送方和接收方(也就是解耦的意思),能避免復雜和容易出錯的依賴性和生命周期問題。
- Event 事件。它可以是任意類型。
- Subscriber 事件訂閱者。在EventBus3.0之前我們必須定義以onEvent開頭的那幾個方法,分別是onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,而在3.0之后事件處理的方法名可以隨意取,不過需要加上注解@subscribe(),并且指定線程模型,默認是POSTING。
- Publisher 事件的發(fā)布者。我們可以在任意線程里發(fā)布事件,一般情況下,使用EventBus.getDefault()就可以得到一個EventBus對象,然后再調用post(Object)方法即可。
10. provide / inject??
provide / inject 是vue2.2.0新增的api, 簡單來說就是父組件中通過provide來提供變量, 然后再子組件中通過inject來注入變量。
provide 選項應該是
- 一個對象或返回一個對象的函數。該對象包含可注入其子孫的屬性。在該對象中你可以使用 ES2015 Symbols 作為 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的環(huán)境下可工作。
inject 選項應該是:
- 一個字符串數組
- 一個對象(詳情點擊這里) 基本用法:
// 祖先組件 提供foo
//第一種
export default {
name: "father",
provide() {
return {
foo: 'hello'
}
},
}
//第二種
export default {
name: "father",
provide: {
foo:'hello~~~~'
},
}
//后代組件 注入foo, 直接當做this.foo來用
export default {
inject:['foo'],
}
上面的兩種用法有什么區(qū)別嗎?
- 如果你只是傳一個字符串,像上面的
hello,那么是沒有區(qū)別的,后代都能讀到。 - 如果你需要
this對象屬性的值(如下所示代碼),那么第二種是傳不了的,后代組件拿不到數據。所以建議只寫第一種
//當你傳遞對象給后代時
provide() {
return {
test: this.msg
}
},
注意:一旦注入了某個數據,比如上面示例中的 foo,那這個組件中就不能再聲明 foo 這個數據了,因為它已經被父級占有。
provide 和 inject 綁定并不是可響應的。
這是刻意為之的。然而,如果你傳入了一個可監(jiān)聽的對象,那么其對象的屬性還是可響應的。因為對象是引用類型。
先來個值類型的數據(也就是字符串)例子,不會響應
provide(){
return{
test:this.msg
}
},
data() {
return {
msg: "Welcome to Your Vue.js App",
}
}
mounted(){
setTimeout(()=>{
this.msg = "halo world";
console.log(this._provided.msg)
//log:Welcome to Your Vue.js App
},3000)
},
如上所示,這樣做是不行的,打印出來的 _provided 中的數據并沒有改,子組件取得值也沒變。
你甚至可以直接給 this._provided.msg 賦值,但是即使是_provided.msg 里面的值改變了,子組件的取值,依然沒有變。
當你的參數是對象的時候,就可以響應了,如下:
provide(){
return{
test:this.activeData
}
},
data() {
return {
activeData:{name:'halo'},
}
}
mounted(){
setTimeout(()=>{
this.activeData.name = 'world';
},3000)
}
這就是vue官方中寫道的對象的屬性是可以響應的
provide/inject 實現(xiàn)全局變量
provide/inject不是只能從祖先傳遞給后代嗎?是的,但是,如果我們綁定到最頂層的組件app.vue,是不是所有后代都接收到了,就是當做全局變量來用了。
//app.vue
export default {
name: 'App',
provide(){
return{
app:this
}
},
data(){
return{
text:"it's hard to tell the night time from the day"
}
},
methods:{
say(){
console.log("Desperado, why don't you come to your senses?")
}
}
}
//其他所有子組件,需要全局變量的,只需要按需注入app即可
export default {
inject:['foo','app'],
mounted(){
console.log(this.app.text); // 獲取app中的變量
this.app.say(); // 可以執(zhí)行app中的方法,變身為全局方法!
}
}
provide/inject 實現(xiàn)頁面刷新,不閃爍
- 用
vue-router重新路由到當前頁面,頁面是不進行刷新的 - 采用
window.reload(),或者router.go(0)刷新時,整個瀏覽器進行了重新加載,閃爍,體驗不好
那我們怎么做呢?
跟上面的原理差不多,我們只在控制路由的組件中寫一個函數(使用v-if控制router-view的顯示隱藏,這里的原理不作贅述),然后把這個函數傳遞給后代,然后在后代組件中調用這個方法即可刷新路由啦。
//app.vue
<router-view v-if="isShowRouter"/>
export default {
name: 'App',
provide() {
return {
reload: this.reload
}
},
data() {
return {
isShowRouter: true,
}
},
methods:{
reload() {
this.isShowRouter = false;
this.$nextTick(() => {
this.isShowRouter = true;
})
}
}
}
//后代組件
export default {
inject: ['reload'],
}
這里 provide 使用了函數傳遞給后代,然后后代調用這個函數,這種思路,也是可以做子后代向父組件傳參通訊的思路了。這里的原理,和 event 事件訂閱發(fā)布就很像了
11.通過 $root 訪問根實例??
通過 $root,任何組件都可以獲取當前組件樹的根 Vue 實例,通過維護根實例上的 data,就可以實現(xiàn)組件間的數據共享。
//main.js 根實例
new Vue({
el: '#app',
store,
router,
// 根實例的 data 屬性,維護通用的數據
data: function () {
return {
author: ''
}
},
components: { App },
template: '<App/>',
});
<!--組件A-->
<script>
export default {
created() {
this.$root.author = '于是乎'
}
}
</script>
<!--組件B-->
<template>
<div><span>本文作者</span>{{ $root.author }}</div>
</template>
注意:通過這種方式,雖然可以實現(xiàn)通信,但在應用的任何部分,任何時間發(fā)生的任何數據變化,都不會留下變更的記錄,這對于稍復雜的應用來說,調試是致命的,不建議在實際應用中使用。
12. attrs與attrs 與 attrs與listenter??
多層嵌套組件傳遞數據時,如果只是傳遞數據,而不做中間處理的話就可以用這個,比如父組件向孫子組件傳遞數據時
$attrs:包含父作用域里除 class 和 style 除外的非 props 屬性集合。通過this.attrs獲取父作用域中所有符合條件的屬性集合,然后還要繼續(xù)傳給子組件內部的其他組件,就可以通過v−bind = " attrs 獲取父作用域中所有符合條件的屬性集合,然后還要繼續(xù)傳給子組件內部的其他組件,就可以通過 v-bind="attrs獲取父作用域中所有符合條件的屬性集合,然后還要繼續(xù)傳給子組件內部的其他組件,就可以通過v−bind="attrs"
$listeners:包含父作用域里 .native 除外的監(jiān)聽事件集合。如果還要繼續(xù)傳給子組件內部的其他組件,就可以通過 v-on=“$linteners”
使用方式是相同的:
// Parent.vue
<template>
<child :name="name" title="1111" ></child>
</template
export default{
data(){
return {
name:"小解"
}
}
}
// Child.vue
<template>
// 繼續(xù)傳給孫子組件
<sun-child v-bind="$attrs"></sun-child>
</template>
export default{
props:["name"], // 這里可以接收,也可以不接收
mounted(){
// 如果props接收了name 就是 { title:1111 },否則就是{ name:"小解", title:1111 }
console.log(this.$attrs)
}
}
總結
常見使用場景可以分為三類:
- 父子組件通信:
props、$parent / $children、provide / inject、ref \ $refs、$attrs / $listeners - 兄弟組件通信:
eventBus、vuex、自己實現(xiàn)簡單的 Store 模式 - 跨級通信:
eventBus、Vuex、自己實現(xiàn)簡單的 Store 模式、provide / inject、$attrs / $listeners
以上就是vue的組件通訊方法總結大全的詳細內容,更多關于vue組件通訊的資料請關注腳本之家其它相關文章!
相關文章
element-plus結合sortablejs實現(xiàn)table行拖拽效果
使用element-plus的el-table組件創(chuàng)建出來的table,結合sortable.js實現(xiàn)table行拖動排序,文中有詳細的代碼示例供大家參考,具有一定的參考價值,感興趣的同學可以自己動手試一試2023-10-10
Vue3動態(tài)組件<component>渲染失效原因分析
在vue2中使用正常,但是遷移到Vue3中,發(fā)現(xiàn)組件無法渲染, 本文給大家分別展示Vue2和Vue3的代碼,組件能正常在Vue2中渲染,在Vue確沒有渲染出來,并通過代碼示例給出了解決方法,需要的朋友可以參考下2024-11-11
Vue + element 實現(xiàn)多選框組并保存已選id集合的示例代碼
這篇文章主要介紹了Vue + element 實現(xiàn)多選框組并保存已選id集合,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06

