Vue父子組件傳值&自定義事件方式
Vue 父子組件傳值&自定義事件
因為vue 的數(shù)據是單向流動的,這是為了避免數(shù)據污染。
在官方文檔中也說到:所有的 prop 都使得其父子 prop 之間形成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,但是反過來則不行。
這樣會防止從子組件意外改變父級組件的狀態(tài),從而導致你的應用的數(shù)據流向難以理解。
大致歸納一下:父傳子--傳值、子傳父--傳事件
父傳子:父組件可以傳遞任何類型的數(shù)據給子組件
如果傳遞的數(shù)據是對象格式的,那么在子組件 內部監(jiān)聽 watch 的時候,需要使用深度監(jiān)聽,也就是添加 deep : true ,也就是下面的子組件的監(jiān)聽方式,如果是別的格式的,例如,字符串、數(shù)字、布爾值、 數(shù)組格式等,那就是普通監(jiān)聽就好了
父組件代碼
在父組件中 通過 v-bind 的縮寫形式 :listData='listData' 綁定了data 內部的數(shù)據,第一個 listData 只是一個名字,為了方便辨認,所以寫的相同。 第二個 listData 則是 data 內部的數(shù)據
<template> <div> <h3>我是father</h3> <Children :listData='listData' :xxx='xxx' :listObj='listObj'></Children> //子組件傳遞了一個數(shù)組、一個字符串、一個對象 </div> </template> <script> import Children from './children' //引入子組件 export default { data () { return { xxx:'123', listData: [{ id: 1, name: "TCL彩電", price: 1000, num: 1, img: "../../../assets/a.jpg" }], listObj: { name: "aaa", age: 18 } } }, components : { Children //注冊子組件 }, } </script>
子組件代碼
1、通過 props 接收父組件傳遞過來的數(shù)據,規(guī)范要求寫出數(shù)據的類型以及默認值,如果數(shù)據是數(shù)組或對象形式的,需要使用函數(shù)返回,不然控制臺會報錯。
2、props 接收數(shù)據之后,需要使用數(shù)據,這個時候需要用到 watch 監(jiān)聽器。對象監(jiān)聽需要用到 deep 深度監(jiān)聽,如果需要組件第一次進來之后就開始監(jiān)聽數(shù)據,那么需要 添加 immediate: true
<template> <div> <h3>我是children</h3> </div> </template> <script> export default { props: { listData: { type: Array, default: () => [] }, xxx:{ type:String, default : '' }, listObj:{ type: Object, default: () => {} } }, watch: { listData:{ handler(n,o) { console.log(n,o) } }, xxx:{ handler(n) { console.log(n) } }, listObj:{ handler(n,o) { console.log(n,o) }, deep: true, immediate: true, }, } }; </script>
子傳父--傳事件:子組件傳遞數(shù)據給父組件時存在三種方式,但是都是通過事件傳遞
1、父組件傳遞 函數(shù)類型的props 給子組件,實現(xiàn)子組件向父組件傳遞數(shù)據
在父組件中引入子組件,向子組件中 通過 v-bind( 簡寫為 : ) 綁定一個 test 屬性 ,該 test 屬性對應的值則是 methods 中定義的方法。
<template> <div id="app"> <School :test="test"/> </div> </template> methods: { test(val) { console.log(val,'這是子組件傳遞過來的數(shù)據') }, },
定義子組件,以及子組件事件
<template> <div> <p class="demo" @click="goto">School組件</p> </div> </template>
在子組件中接收該 test 屬性,定義數(shù)據,定義組件方法。其實props 可以直接寫成一個數(shù)組,不去定義類型,默認值以及是否必傳,但是推薦還是寫全一點,這樣編譯的時候會校驗,提高代碼質量
export default ({ // props:['test'], props: { test: { type: Function, default: () => {}, required: true, } }, data() { return { msg:'子組件數(shù)據' } }, methods: { goto() { this.test(this.msg) } }, })
點擊觸發(fā) goto 事件,找到當前 props 中接收的 test 函數(shù) ( props 接收的參數(shù),都被Vue 底層處理過之后放在了 當前組件實例對象上,所以可以直接通過 this.xxx 拿到 )
控制臺上打印了子組件數(shù)據。可以看到子組件傳遞的數(shù)據被打印了,表示父組件中綁定的 test 事件被執(zhí)行了
2、通過 v-on( @ ) 與 $emit 實現(xiàn)子組件向父組件傳遞數(shù)據
App 組件中引入 School 子組件,且綁定 自定義事件 test。
<School @test="test"/> test(val) { console.log(val,'這是子組件傳遞過來的數(shù)據') },
子組件模板、數(shù)據、樣式不變,只是 goto 方法內部邏輯變更
methods: { goto() { this.$emit('test',this.msg) } },
點擊觸發(fā) goto 事件,通過 $emit 觸發(fā) test 事件,根據名稱找到 父組件中的 test 屬性對應的方法,執(zhí)行該方法。結果與 props 傳遞函數(shù)參數(shù)一致
3、通過 ref 以及 $on、$emit 三個 api 實現(xiàn) 父組件通過 自定義事件接收子組件參數(shù)
$on
:監(jiān)聽當前實例上的自定義事件。事件可以由 vm.$emit 觸發(fā)。回調函數(shù)會接收所有傳入事件觸發(fā)函數(shù)的額外參數(shù)。$emit
:觸發(fā)當前實例上的事件。附加參數(shù)都會傳給監(jiān)聽器回調。
App 組件中引入 Schoo 組件,且給 School 子組件添加了 ref 屬性,定義 test 函數(shù)
<School ref='student'/> test(val) { console.log(val,'這是子組件傳遞過來的數(shù)據') },
如果想使用這個方法去獲取子組件數(shù)據,就需要用到 $on() 這個方法?,F(xiàn)在假設,當父組件掛載時,我就要獲取到子組件的值,我就應該在 父組件 的 mounted 生命周期中 使用 this.$refs.xxx來獲取當前組件的實例對象,至于 $on() 這個方法,則是 掛載到 Vue 實例對象的原型上的,所以 組件實例對象 和 Vue 實例對象 都能使用 $on() 。
在這里就是 通過 $on 注冊或者叫創(chuàng)建了一個 qwe 的自定義事件,且該自定義事件的回調函數(shù)是寫在 methods 中的 getname
mounted() { this.$refs.student.$on('qwe', this.test) }
父組件的工作已經完了,現(xiàn)在該看看子組件了。子組件更簡單了,和上面 第二種方法一樣,通過 $emit() 這個方法來觸發(fā)父組件定義的 qwe 方法,且將子組件 數(shù)據傳遞出去。
goto() { this.$emit('test',this.msg) }
當我點擊 School 組件時,執(zhí)行 goto 方法,通過 $emit 觸發(fā)父組件自定義的 qwe 方法,且將參數(shù)傳遞給父組件。
父組件通過 $on 監(jiān)聽 qwe 方法,發(fā)現(xiàn)被觸發(fā)了,執(zhí)行其回調函數(shù) this.test,且 $emit 傳遞的參數(shù),都會當做形參傳遞到回調函數(shù)中
$on 和 v-on 的區(qū)別
這么一看哈,其實我在子組件上使用 v-on( @ ) 和我使用 $on 做到的事情是一樣的啊,那為啥還要來個 $on 這個玩意。
- 第一點:$on 只能監(jiān)聽當前實例上的自定義事件,而 v-on 用在普通元素上時,只能監(jiān)聽原生DOM事件。用在自定義元素組件上時,也可以監(jiān)聽子組件觸發(fā)的自定義事件。
- 第二點:$on 更加靈活,如果我想要我的自定義事件異步綁定,通過 v-on 是無法做到的,因為 v-on 指令在 模板編譯的時候,就被Vue 底層處理過了,在渲染的時候直接就會綁定事件,但是 $on 的自由度更高。
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
element的el-date-picker組件實現(xiàn)只顯示年月日時分效果(不顯示秒)
最近遇到這樣的需求使用element的el-date-picker組件,只顯示時分,不顯示秒,下面小編給大家分享element的el-date-picker組件實現(xiàn)只顯示年月日時分效果,感興趣的朋友一起看看吧2024-08-08解決vue-photo-preview 異步圖片放大失效的問題
這篇文章主要介紹了解決vue-photo-preview 異步圖片放大失效的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07vue實現(xiàn)動態(tài)路由的方法及路由原理解析
這篇文章主要介紹了路由原理及vue實現(xiàn)動態(tài)路由,Vue Router 提供了豐富的 API,可以輕松地實現(xiàn)路由功能,并支持路由參數(shù)、查詢參數(shù)、命名路由、嵌套路由等功能,可以滿足不同應用程序的需求,需要的朋友可以參考下2023-06-06