前言
之前學習vue,對父子組件傳值達成了基本的認識,現在我把它進行系統的整理
父組件向子組件傳值prop
首先在父組件中
<son :msg="我是你爸爸"></son>
在子組件的props中
export default {
props:{
'msg':String
}
}
這裏我還加了一個數據類型的檢測,注意,數據類型是在組件實例創建之前進行驗證的
子組件向父組件傳值$emit
子組件中,需要觸發一個事件,可以是自定義事件,也可以是原生事件,在這裏我們先用自定義事件,原生事件比較複雜,我放在後面說
首先我們在子組件中用$emit觸發自定義事件,這個自定義事件寫在生命週期函數或者是click事件上均可,然後第二個參數是我們要傳給父組件的值
this.$emit('hellodad','爸爸我很想你');
然後我們在父組件中監聽子組件的自定義事件,並在監聽到的時候,觸發happy事件
<son v-on:hellodad="happy"></son>
export default {
methods:{
happy(data){
console.log(data);
console.log('hello,my son');
}
},
components:{
son
}
}
data中就是子組件中打印出來的消息啦。
vm.$attrs
那麼什麼是$attrs
呢,下面是官方定義
包含了父作用域中不作爲 prop 被識別 (且獲取) 的特性綁定 (class 和 style 除外)。當一個組件沒有聲明任何 prop 時,這裏會包含所有父作用域的綁定 (class 和 style 除外),並且可以通過 v-bind="$attrs" 傳入內部組件——在創建高級別的組件時非常有用。
父親給兒子傳了三個屬性
<son
msg1:'1'
msg2:'2'
msg3:'3'
></son>
兒子說,我不要那麼多,要一個就好了,剩下給你孫子吧
<grandson v-bind="$attrs"></grandson>
export default {
props:['msg1']
}
孫子說,氣死了,你怎麼盡挑不要的給我
created(){
console.log(this.$attrs);//{v-bind:{msg2:'2',msg3:'3'}}
}
inheritAttrs
官方解釋
1.默認情況下父作用域的不被認作 props 的特性綁定 (attribute bindings) 將會“回退”且作爲普通的 HTML 特性應用在子組件的根元素上。當撰寫包裹一個目標元素或另一個組件的組件時,這可能不會總是符合預期行爲。通過設置 inheritAttrs 到 false,這些默認行爲將會被去掉。2.而通過 (同樣是 2.4 新增的) 實例屬性 $attrs 可以讓這些特性生效,且可以通過 v-bind 顯性的綁定到非根元素上。
注意:這個選項不影響 class 和 style 綁定。
首先,我們來理解一下第一句話
在父元素中設置
<son msg="son" class="son"></son>
在子元素中不設置props進行接收
export default {
inheritAttrs:false
}
父組件給子組件設置的值就會退化成爲子組件的屬性
在子組件中設置
exportt default{
inheritAttrs:false
}
看,msg屬性消失了,它不會退化爲子組件普通的 HTML 特性了,但是class
和style
則不會。這是因爲,在父組件中不被認作 props 的特性綁定會覆蓋子組件根組件上的同名特性,而class
和style
則會發生合併。
2.然後,我們來理解一下第二句話,因爲有$attrs,我們用祖孫三輩組件來進行解釋
父親
<son
msg1:'1'
msg2:'2'
msg3:'3'
></son>
兒子
<grandson v-bind="$attrs"></grandson>
export default {
props:['msg1']
}
可以看到,這些特性生效,且可以通過 v-bind 顯性的綁定到元素上。至於是不是根元素,其實主要是看你的寫法,如果你是直接在子組件的components
中定義孫子元素,並且把$attrs
綁定在孫子上面,那理解爲非根元素也無可厚非。
.native
使用 v-on 的.native
修飾符,可以在直接監聽組件的根元素的一個原生事件。
<base-input v-on:focus.native="onFocus"></base-input>
我在給router-link
綁定點擊事件的時候,就需要使用.native
修飾符,否則點擊事件不會生效。因爲router-link是一個自定義標籤,他沒有自己的事件和方法,所以我們用.native監聽這個組件根元素的原生事件,就可以觸發點擊事件了。
可是有的時候,在你嘗試監聽一個類似 的非常特定的元素時,這並不是個好主意。比如上述 組件可能做了如下重構,所以根元素實際上是一個
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
這時,父級的 .native
監聽器將靜默失敗。它不會產生任何報錯,但是 onFocus
處理函數不會如你預期地被調用。
$listeners
爲了解決這個問題,Vue 提供了一個 $listeners 屬性,它是一個對象,裏面包含了作用在這個組件上的所有監聽器。例如:
{
focus: function (event) { /* ... */ }
input: function (value) { /* ... */ },
}
下面是$listeners的官方解釋
包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監聽器。它可以通過 v-on="$listeners" 傳入內部組件——在創建更高層次的組件時非常有用。
啥意思呢?我們還是用祖孫三輩舉例
父親和兒子說,請把孫子今天的表現告訴我
<son @actiom="happy"></son>
兒子:幫忙父親監視孫子
<grandson v-on="$listeners"><grandson>
孫子
this.$emit('action',msg);
有的時候,我們還可以用computed覆寫$listeners這個事件監聽器
computed:{
mylisteners:function(){
var _this = this;
return Object.assign({},this.$listens,{
input:function()(event) {
_this.$emit('input', event.target.value)
}
}
}
}
.sync
在有些情況下,我們可能需要對一個 prop 進行“雙向綁定”。不幸的是,真正的雙向綁定會帶來維護上的問題,因爲子組件可以修改父組件,且在父組件和子組件都沒有明顯的改動來源。
這也是爲什麼我們推薦以 update:myPropName 的模式觸發事件取而代之。舉個例子,在一個包含 title prop 的假設的組件中,我們可以用以下方法表達對其賦新值的意圖:
this.$emit('update:title', newTitle)
然後父組件可以監聽那個事件並根據需要更新一個本地的數據屬性。例如:
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
爲了方便起見,我們爲這種模式提供一個縮寫,即 .sync 修飾符:
<text-document v-bind:title.sync="doc.title"></text-document>
所以.sync的作用就是
<text-document v-on:update:tiltle="doc.title=$event"></text-document>
注意帶有 .sync 修飾符的 v-bind 不能和表達式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是無效的)。取而代之的是,你只能提供你想要綁定的屬性名,類似 v-model。