props
&& emit
v-model
$children
&& $parent
$listeners
&& $attrs
.sync
父組件經過 props
傳遞數據給子組件,子組件經過 emit
發送事件傳遞數據給父組件。這是最經常使用的父子組件通訊方式,符合單向數據流,即子組件不能直接修改 props, 而是必須經過發送事件的方式告知父組件修改數據。因爲是經常使用的方式,在這也很少囉嗦了。html
v-model
實現的通訊其本質上仍是上面的props
和emit
方式,使用v-model
更像是一種語法糖。文檔介紹vue
先舉個栗子:vuex
// 這是父組件
<template>
<div>
<child v-model="msg"></child>
<p>{{msg}}</p>
</div>
</template>
<script>
import child from "../components/Child";
export default {
data() {
return {
msg: "hello"
};
},
components: { child }
};
</script>
複製代碼
// 這是子組件
<template>
<div>
<input :value="value" @input="$emit('input',$event.target.value)">
</div>
</template>
<script>
export default {
props: ["value"]
};
</script>
複製代碼
父組件使用子組件時,使用v-model
綁定父組件msg
數據,這會在子組件裏解析成名爲 value
的 prop 和名爲 input
的事件,因此子組件裏的props
選項裏必須寫成value
,在$emit
事件裏也需寫成input
事件。此時當你在子組件輸入時,就會改變父組件的msg
值。api
上面說了,props選項裏必須寫value
,事件也必須是input
。這是默認狀況下的解析,其實咱們也能夠自定義 props 和 event,使用model
選項,文檔介紹。文檔中以複選框爲例,修改 props 和 event:數組
model: {
prop: 'checked',
event: 'change'
}
複製代碼
$children
&& $parent
方式這兩個是vue提供的api,見名知意,在父組件裏使用 $children
訪問子組件,在子組件裏使用$parent
訪問父組件。bash
舉個簡單栗子:ide
// 這是子組件
<template>
<div>
{{$parent.msg}} // 子組件顯示父組件數據
</div>
</template>
<script>
export default {
data() {
return {
child_msg: "我是子組件數據"
};
},
mounted() {
this.$parent.test(); // 子組件執行父組件方法
}
};
</script>
複製代碼
// 這是父組件
<template>
<div>
<child/>
</div>
</template>
<script>
import child from "../components/Child";
export default {
data() {
return {
msg: "我是父組件的數據"
};
},
components: { child },
methods: {
test() {
console.log("我是父組件的方法,被執行");
}
},
mounted() {
console.log(this.$children[0].child_msg); // 執行子組件方法
}
};
</script>
複製代碼
【注意】 $children
是數組,因此當只有一個子組件時,使用[0]
獲取。當有多個子組件時,它並不保證順序,也不是響應式的。ui
$listeners
方式初看此api的定義,我也是似懂非懂:this
包含了父做用域中的 (不含 .native 修飾器的) v-on 事件監聽器。它能夠經過 v-on="$listeners" 傳入內部組件——在建立更高層次的組件時很是有用spa
文檔這裏也描述了它的使用方法: 文檔介紹
在查看一些博客時,要麼拿官方例子,要麼一大堆介紹,其實我看的也是一臉懵逼。後來本身慢慢試着用了下,也大概明白它是幹嗎的。個人理解:在多層嵌套組件的業務中,使用$listeners
可使用更少的代碼來完成事件通訊。
仍是以代碼來講明,以下圖,咱們來實現組件B 到 父組件 的通訊,
通常嵌套層級太多時,咱們可能就會考慮vuex,但只傳遞數據,而不作中間處理,有點大材小用,因此如上圖這樣的,咱們可能仍是使用emit
方式來通訊,無非多傳一層,多寫點代碼。那麼如今,有了$listeners
,咱們能夠更方便的來實現,我儘可能用最少的代碼來實現下:
就從最下面的B組件開始,它有一個按鈕,點擊時觸發實例上的事件getFromB
// 組件B
<template>
<div>
<button @click="handleClick">B組件按鈕</button>
</div>
</template>
<script>
export default {
methods: {
handleClick() {
this.$emit("getFromB");
}
}
};
</script>
複製代碼
A組件 包裹 B組件,至關因而父組件與B組件的中轉站,在不用$listeners
時,咱們可能會在這裏再觸發一個事件,如今不須要這樣了,咱們這樣:
// 組件A
<template>
<div>
<child-b v-on="$listeners" />
</div>
</template>
<script>
import childB from "../components/ChildB";
export default {
components: {
childB
},
mounted() {
console.log(this.$listeners);
}
};
</script>
複製代碼
只須要加一句v-on="$listeners"
便可。好奇的咱們也能夠 mounted 時打印一下$listeners
。
父組件,顯而易見,咱們直接綁定getFromB
事件便可:
// 父組件
<template>
<div>
<child-a v-on:getFromB="fromB"/>
</div>
</template>
<script>
import childA from "../components/ChildA";
export default {
components: { childA },
methods: {
fromB() {
console.log("B組件觸發");
}
}
};
</script>
複製代碼
這就是$listeners
的簡單用法,說到這裏,你應該意識到,當組件嵌套不少層時,不借助 vuex,咱們也能夠較方便地實現通訊了。
說到這裏,我還要提一個api,就是$attrs
。它與$listeners
的關係就比如 props 與 emit 的關係,用來向底層組件傳遞屬性。先貼上它的定義:
包含了父做用域中不做爲 prop 被識別 (且獲取) 的特性綁定 (class 和 style 除外)。當一個組件沒有聲明任何 prop 時,這裏會包含全部父做用域的綁定 (class 和 style 除外),而且能夠經過 v-bind="$attrs" 傳入內部組件——在建立高級別的組件時很是有用。
咱們回想下,若是使用 props 向孫組件傳遞數據時,在中間組件裏,咱們是要一層層使用 props 選項來接收,而後再傳遞的。那麼$attrs
的做用就是在沒到目標子組件時,不使用props接收數據,直到到達須要數據的組件時,再使用props接收。
在我看別的博客時,都是這兩個api一塊兒說的,代碼比較多,爲了清晰,我把上面代碼多餘的代碼刪掉,只演示$attrs
的使用:
父組件傳遞一個屬性toB
,意爲是給B組件用的:
// 父組件
<template>
<div>
<child-a toB="hello"/>
</div>
</template>
<script>
import childA from "../components/ChildA";
export default {
components: { childA }
};
</script>
複製代碼
A組件使用v-bind="$attrs"
便可,不須要 props 接收,實際上也不能夠接收,看定義
// 組件 A
<template>
<div>
<child-b v-bind="$attrs" />
</div>
</template>
<script>
import childB from "../components/ChildB";
export default {
components: { childB }
};
</script>
複製代碼
B組件是咱們的最後子組件,它用到toB
屬性,因此使用 props 選項接收了
<template>
<div>
<p>父組件傳來數據:{{toB}}</p>
</div>
</template>
<script>
export default {
props: ["toB"]
};
</script>
複製代碼
從這個簡單的例子,咱們能夠知道,當組件嵌套層級不少時,屬性傳遞變得不要太方便。最後還要提一個inheritAttrs
選項,它通常配合$attrs
使用,這裏我就再也不多說了。文檔介紹
.sync
方式此方法其實用的也很多,它在 Vue 1.x 裏的做用是對一個 prop 進行「雙向綁定「。但在 Vue 2 以後是隻容許單向數據流的,因此如今即便它看起來像是真正的「雙向綁定」,本質上也只是做爲一個編譯時的語法糖存在而已。
舉個計數器的例子:
// 父組件
<template>
<div>
{{num}}
<child-a :count.sync="num" />
</div>
</template>
<script>
import childA from "../components/ChildA";
export default {
data() {
return {
num: 0
};
},
components: { childA }
};
</script>
複製代碼
// 子組件
<template>
<div>
<div @click="handleAdd">ADD</div>
</div>
</template>
<script>
export default {
data() {
return {
counter: this.count
};
},
props: ["count"],
methods: {
handleAdd() {
this.$emit("update:count", ++this.counter);
}
}
};
</script>
複製代碼
嗯,看起來彷佛更有逼格。
這麼看下來,除了$children
和 $parent
是直接獲取的,其餘都跟 props 和 emit 息息相關。具體怎麼用,本身看着辦唄。
最後,新年快樂!