一:實現子組件與父組件雙向綁定的“sync”:
一般來說,我們實現父子組件值的傳遞通常使用的是【props】和自定義事件【$emit】。父組件通過【props】將值傳給子組件,子組件通過【$emit】將值傳給父組件,父組件通過【$on】獲取子組件傳過來的值,如果說想要實現子組件修改父組件傳過來的值,最容易的就是這種方法了:
//父組件向子組件傳值
<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】獲取子組件的值:
<template> <div> <child-com :value="text" @getChildValue = "getValue"></child-com> </div> </template> <script> export default{ data(){ return { text:"父組件的值", } }, methods:{ getValue(child_value){ this.text = child_value; } } } </script>
這樣,就可以實現子組件修改父組件的值。
不過,這種方法有一個弊端——子組件修改父組件的值需要一個傳遞的過程,或者說,兩個值並不是同步的。
熟悉Vue1.0的朋友應該知道一個叫【.sync】的修飾符,它可以實現父子組件的雙向綁定,不過在Vue2.0被移除了,直到2.3.0版本發布后才重新回歸,所以一些和我一樣從2.0開始使用Vue的朋友很有可能不清楚,事實上,【.sync】可以很輕松的實現子組件同步修改父組件的值:
//父組件
<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:data',"子組件的值") } } } </script>
我們可以看到,對於子組件來說,僅僅是自定義事件名做了一點改變,但是就代碼底層邏輯來說,子組件和父組件真正實現了同步的雙向綁定。
當然,正如文檔所說:
.sync修飾符很方便,但也會導致問題,因為破壞了單向數據流。由於子組件改變 prop 的代碼和普通的狀態改動代碼毫無區別,當光看子組件的代碼時,你完全不知道它何時悄悄地改變了父組件的狀態。這在 debug 復雜結構的應用時會帶來很高的維護成本。
二:自定義指令:“directives”
關於自定義指令文檔其實介紹的比較詳細了,而且還舉了一個非常詳細的例子:自定義指令
自定義指令其實就是Vue為我們提供直接操作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有關的問題卻一籌莫展時,可以想想自定義指令是否有功能可以解決為題。
三: inheritAttrs和attrs
前面我已經提到過了,父組件通過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上顯示的展示了message="123456"。
此時,我們可以通過設置inheritAttrs: false來取消這種默認行為
data(){ return{ ...... } } inheritAttrs: false,
mounted(){
console.log(this.$attrs); //{count:123456}
}
這時再看dom上就沒有message屬性了。然后,我還打印了this.$attrs的值,值為一個包含着count鍵值對的Object。
也就是說,父組件沒有props的屬性值會被保存在一個名為$attrs中供子組件使用,然而這並沒有解決開頭子組件的子組件獲取值的問題。別急,我們只需要在子組件上加個東西就可以了:
<template> <div class="child"> <my-child v-bind="$attrs"></my-child> </div> </template>
這樣,子組件的子組件也可以獲取這個值了。
四:混入——mixins
其實這個功能有些類似於es6中的Object.assign()方法。根據一定的規則合並兩個配置,具體的混入策略可以看官方文檔:mixins混入策略
混入最大的用處是把一些常用的data或者methods等抽出來,比如在我的項目中有許多個模態框,而關閉模態框的代碼邏輯是一模一樣的,為此我沒有必要在多個組件中重復把關閉模態框的邏輯寫入methods中,只需要在外面定義一個mixins,在需要的組件中通過:mixins: [myMin]寫入即可。