1. 概述
相關定律告訴我們:這個世界上的任何事物之間都會存在一定聯絡,“城門失火,殃及池魚”就是一個很好的例子。因此如果我們能夠儘早發現這些看不見的聯絡,就能很好的解決更多遇見的難題。
言歸正傳,之前我們聊過如何在子元件中去修改主元件傳遞的引數的值,當時是在子元件中重新宣告一個新資料,初始值為父元件傳參的值,然後對子元件的資料進行計算。
今天我們使用事件的方式來實現對父元件的傳參進行修改。
2. 元件間事件通訊
2.1 子元件接收引數並實現自增
<body> <div id="myDiv"></div> </body> <script> const app = Vue.createApp({ data() { return { num : 1 } }, template:` <div> <test :num="num" /> </div> ` }); app.component("test", { props:['num'], methods : { incrNum() { this.num++; } }, template:` <div @click="incrNum" >{{num}}</div> ` }); const vm = app.mount("#myDiv");
這個例子我們們之前聊過,父元件有一個資料 num,父元件將這個引數傳給 test 子元件,子元件使用 props:['num'] 的方式接收後,在事件方法中對其自增
很明顯,自增時會報錯,因為父元件傳過來的 num 是隻讀的,子元件不能對其進行修改。
2.2 子元件中宣告新的資料,將父元件的num作為初始值
const app = Vue.createApp({ data() { return { num : 1 } }, template:` <div> <test :num="num" /> </div> ` }); app.component("test", { props:['num'], data() { return { myNum : this.num } }, methods : { incrNum() { // this.num++; this.myNum++; } }, template:` <div @click="incrNum" >{{myNum}}</div> ` });
這是我們上節課的解決方案,在子元件中宣告 myNum,把num當做初始值,然後自增 myNum,顯示時也顯示 myNum
很明顯,這樣做是可以的
2.3 子元件呼叫父元件的方法
既然子元件無權修改父元件傳過來的引數,那我們就讓父元件自己去修改這個引數
const app = Vue.createApp({ data() { return { num : 1 } }, methods : { handleIncr() { this.num++; } }, template:` <div> <test :num="num" @incrNum="handleIncr" /> </div> ` }); app.component("test", { props:['num'], methods : { incrNum() { this.$emit('incrNum') } }, template:` <div @click="incrNum" >{{num}}</div> ` });
這個例子中,父元件在使用子元件時,繫結了一個事件 incrNum,這個事件會呼叫父元件的 handleIncr 方法,這個方法中對資料 num 進行了自增。
子元件在自己的 incrNum 方法中使用 this.$emit('incrNum') 觸發了父元件的 incrNum 事件,然後該事件呼叫父元件的 handleIncr 方法,對父元件的資料 num 進行修改。
父元件修改了資料 num,這個資料 num 修改後的值會傳遞給子元件,從而實現對 num 引數的修改。
說了這麼一大堆,簡單看就是子元件通過某種手段呼叫了父元件的方法。
經試驗,完全沒用問題,可以修改 num 的值
2.4 子元件呼叫父元件的方法,且傳參
光呼叫還不行,我們還要傳參
const app = Vue.createApp({ data() { return { num : 1 } }, methods : { handleIncr(param1) { this.num += param1; } }, template:` <div> <test :num="num" @incrNum="handleIncr" /> </div> ` }); app.component("test", { props:['num'], methods : { incrNum() { this.$emit('incrNum', 2) } }, template:` <div @click="incrNum" >{{num}}</div> ` });
這個例子中,我們根據傳參的值,決定自增多少。
在 this.$emit('incrNum', 2) 這句程式碼中,除了指明觸發的事件,還傳了一個引數,父元件的 handleIncr(param1) 這個方法,就可以接收這個引數,並使用
2.5 子元件呼叫父元件的方法,且傳多個引數
這次我們要傳多個引數,當然也是可以的
const app = Vue.createApp({ data() { return { num : 1 } }, methods : { handleIncr(param1, param2) { this.num += param2; } }, template:` <div> <test :num="num" @incrNum="handleIncr" /> </div> ` }); app.component("test", { props:['num'], methods : { incrNum() { this.$emit('incrNum', 2, 3) } }, template:` <div @click="incrNum" >{{num}}</div> ` });
這麼傳:this.$emit('incrNum', 2, 3),這麼收:handleIncr(param1, param2),以此類推
2.6 計算邏輯放在子元件中
自增本來是子元件的業務,我們不想把這個邏輯放到父元件中,耦合性太強了,我們可以這麼寫
const app = Vue.createApp({ data() { return { num : 1 } }, methods : { handleIncr(param1) { this.num = param1; } }, template:` <div> <test :num="num" @incrNum="handleIncr" /> </div> ` }); app.component("test", { props:['num'], methods : { incrNum() { this.$emit('incrNum', this.num + 1) } }, template:` <div @click="incrNum" >{{num}}</div> ` });
其實就是傳參時在子元件中計算好了,然後父元件直接賦值就好
2.7 通過 v-model 的方式,修改父元件資料的值
上面的例子中,我們通過子元件呼叫父元件的方法去修改父元件資料的值,耦合性還是有點強,父元件需要去為子元件寫一個方法。
其實還有一個更簡潔的辦法,就是通過 v-model 的方式,來看下面的例子
const app = Vue.createApp({ data() { return { num : 1 } }, template:` <div> <test v-model="num" /> </div> ` }); app.component("test", { props:['modelValue'], methods : { incrNum() { this.$emit('update:modelValue', this.modelValue + 1); } }, template:` <div @click="incrNum" >{{modelValue}}</div> ` });
這個例子中,父元件使用 test 子元件時,使用 v-model="num" 的方式來傳參。
test 子元件接收時,使用 props:['modelValue'] 的方式接收,注意:modelValue 是一個固定寫法。
在子元件的自增方法中使用 this.$emit('update:modelValue', this.modelValue + 1); 的形式去修改 modelValue 的值,注意:update:modelValue 是固定寫法。
2.8 使用 num 替換 modelValue
上面的例子有點不好理解,無緣無故蹦出個 modelValue,父元件明明傳的是 num,為啥我接受要用 modelValue,太奇怪了
下面的例子更易於我們的理解
const app = Vue.createApp({ data() { return { num : 1 } }, template:` <div> <test v-model:num="num" /> </div> ` }); app.component("test", { props:['num'], methods : { incrNum() { this.$emit('update:num', this.num + 1); } }, template:` <div @click="incrNum" >{{num}}</div> ` });
這個例子就好理解多了,首先父元件使用 test 子元件時,使用 v-model:num="num" 進行傳參。
子元件接收時,接收的就是 num,使用 props:['num'] 接收。
最後使用 this.$emit('update:num', this.num + 1); 程式碼對接收到的 num 進行修改。
顯示時顯示的也是 num,{{num}}
這樣寫就清爽很多,父元件沒有 method,子元件相當於自己對接收到的引數 num 進行操作,耦合度降低了很多。
3. 綜述
今天聊了一下 VUE3 的 元件間事件通訊,希望可以對大家的工作有所幫助,下一節我們繼續講元件的相關知識,敬請期待
歡迎幫忙點贊、評論、轉發、加關注 :)
關注追風人聊Java,每天更新Java乾貨。
4. 個人公眾號
追風人聊Java,歡迎大家關注