通常來講,咱們實現父子組件值的傳遞一般使用的是【props】和自定義事件【$emit】。父組件經過【props】將值傳給子組件,子組件經過【$emit】將值傳給父組件,父組件經過【$on】事件獲取子組件傳過來的值,若是說想要實現子組件修改父組件傳過來的值,最容易的就是這種方法了:
javascript
//父組件向子組件傳值
<template>
<div> <child-com :value="text"></child-com> </div> </template>
<script>
export default{
data(){
return{
text:"父組件的值",
}
}
}
</script> 複製代碼
//子組件向父組件傳值
<template>
<div @click="post"></div>
</template>
<script>
export default{
methods:{
post(){
this.$emit('getChildValue',"子組件的值")
}
}
}
</script>複製代碼
此時父組件能夠經過【$on】獲取子組件的值:
html
<template>
<div> <child-com @getChildValue = "getValue"></child-com> </div> </template>
<script>
export default{
methods:{
getValue(child_value){
this.text = child_value;
}
}
}
</script>複製代碼
這樣,就能夠實現子組件修改父組件的值。vue
不過,這種方法有一個弊端——子組件修改父組件的值須要一個傳遞的過程,或者說,兩個值並非同步的。java
熟悉Vue1.0的朋友應該知道一個叫【.sync】的修飾符,它能夠實現父子組件的雙向綁定,不過在Vue2.0被移除了,直到2.3.0版本發佈後才從新迴歸,因此一些和我同樣從2.0開始使用Vue的朋友頗有可能不清楚,事實上,【.sync】能夠很輕鬆的實現子組件同步修改父組件的值:es6
//父組件
<template>
<div>
<child-com :value.sync="text" ></child-com>
</div>
</template>
<script>
export default{
data(){
return {
text:"父組件的值",
}
},
}
</script>
==============================================================================================================
//子組件修改父組件的值
<template>
<div @click="post"></div>
</template>
<script>
export default{
methods:{
post(){
this.$emit('update:value',"子組件的值")
}
}
}
</script>複製代碼
(感謝@糖小面兒 ,@asuishi ,@李佳毅 指出文中this.$emit('update:data',"子組件的值")
的錯誤。)vuex
咱們能夠看到,對於子組件來講,僅僅是自定義事件名作了一點改變,可是就代碼底層邏輯來講,子組件和父組件真正實現了同步的雙向綁定。api
固然,正如文檔所說:瀏覽器
.sync修飾符很方便,但也會致使問題,由於破壞了單向數據流。因爲子組件改變 prop 的代碼和普通的狀態改動代碼毫無區別,當光看子組件的代碼時,你徹底不知道它什麼時候悄悄地改變了父組件的狀態。這在 debug 複雜結構的應用時會帶來很高的維護成本。
關於自定義指令文檔其實介紹的比較詳細了,並且還舉了一個很是詳細的例子:自定義指令bash
自定義指令其實就是Vue爲咱們提供直接操做dom的一些列方法,雖然大部分開發時間都會面向數據,但說不許何時確實須要操做dom自己。dom
就我而言,自定義指令最大的用處就是能夠引用一些第三方的代碼插入到Vue項目中,好比有一個操做dom的函數:
//固然,真實狀況第三方的代碼要複雜的多
function changeColor(dom){
dom.style.backgroundColor = "red";
}複製代碼
咱們能夠註冊一個全局的指令來爲須要執行changeColor方法的dom提供指令:
Vue.directives('color',{
bind:function(el){
changeColor(el)
}
})複製代碼
這樣,若是須要這個dom改變顏色的話,只須要這樣便可:
<div v-color>改變顏色</div>複製代碼
當平常開發遇到跟dom有關的問題卻束手無策時,能夠想一想自定義指令是否有功能能夠解決爲題。
前面我已經提到過了,父組件經過props能夠向子組件傳值,但在平常的開發中,還有一種狀況很常見,就是父組件給子組件傳值,這個值還要從子組件傳給它的子組件,因此,咱們可能會看到這樣的代碼:
//父組件
<div>
<child :text="text"></child>
</div>
//子組件
<div>
<my-child :text="text"></my-child>
</div>
//子組件的子組件
<div>
<div>{{text}}</div>
</div>複製代碼
這樣作是很是麻煩並且不易於維護的,一般狀況下,咱們可使用vuex來解決。不過,不復雜的項目中若是僅僅爲這一個問題就引入vuex其實是不必的,Vue提供了【inheritAttrs】和【attrs】兩個功能來解決這樣的問題:
//父組件
<template>
<div>
<child :text="text" :count="count"></child>
</div>
</template>
<script>
export default{
data(){
return {
text:"父組件的值",
count:123456,
}
}
}
</script>複製代碼
//子組件
<template>
<div>{{text}}</div>
</template>
<script>
export default{
props:["text"]
}
</script>複製代碼
注意,這裏父組件的count屬性僅僅掛在子組件上,並無使用。此時咱們打開瀏覽器,能夠看到子組件的dom上顯示的展現了count="123456"。
此時,咱們能夠經過設置inheritAttrs: false來取消這種默認行爲:
data(){
return{
......
}
}
inheritAttrs: false,
mounted(){
console.log(this.$attrs); //{count:123456}
}複製代碼
這時再看dom上就沒有count屬性了。而後,我還打印了this.$attrs的值,值爲一個包含着count鍵值對的Object。
也就是說,父組件沒有props的屬性值會被保存在一個名爲$attrs中供子組件使用,然而這並無解決開頭子組件的子組件獲取值的問題。別急,咱們只須要在子組件上加個東西就能夠了:
<template>
<div class="child"> <my-child v-bind="$attrs"></my-child> </div> </template>複製代碼
這樣,子組件的子組件也能夠獲取這個值了。
其實這個功能有些相似於es6中的Object.assign()方法。根據必定的規則合併兩個配置,具體的混入策略能夠看官方文檔:mixins混入策略
混入最大的用處是把一些經常使用的data或者methods等抽出來,好比在個人項目中有許多個模態框,而關閉模態框的代碼邏輯是如出一轍的,爲此我沒有必要在多個組件中重複把關閉模態框的邏輯寫入methods中,只須要在外面定義一個mixins,在須要的組件中經過:mixins: [myMin]寫入便可。
var mixin = {
methods: {
close: function () {
this.showModal = false; //關閉模態框
},
}
}
var vm = new Vue(
mixins: [mixin],
.......
})
複製代碼
首先感謝評論區大佬們的提醒,provide/inject
方法要比inheritAttrs/attrs
更適合用來作父組件給子組件或孫組件傳值,先發一個文檔的連接:provide/inject
//父組件使用provide
<template> <div class="parent"> <child-component></child-component> </div> </div></template>
<script>export default { ...... provide: { parent: "父組件的值" }, components:{ child-component, }, ......</script>
//此時能夠在子組件經過這種方式獲取父組件中「parent」的值:
//子組件中
export default { mounted(){ console.log(this.parent); //"父組件的值" }, inject: ['parent'],}複製代碼
這塊兒內容我也是剛看文檔,感興趣的朋友能夠仔細看看文檔,本身敲一遍看看。