一:實現子元件與父元件雙向繫結的【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 @getChildValue = "getValue"></child-com>
</div>
</template>
<script>
export default{
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:value',"子元件的值")
}
}
}
</script>複製程式碼
(感謝@糖小面兒 ,@asuishi ,@李佳毅 指出文中this.$emit('update:data',"子元件的值")
的錯誤。)
我們可以看到,對於子元件來說,僅僅是自定義事件名做了一點改變,但是就程式碼底層邏輯來說,子元件和父元件真正實現了同步的雙向繫結。
當然,正如文件所說:
.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上顯示的展示了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>複製程式碼
這樣,子元件的子元件也可以獲取這個值了。
四:混入——mixins:
其實這個功能有些類似於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:
首先感謝評論區大佬們的提醒,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'],}複製程式碼
這塊兒內容我也是剛看文件,感興趣的朋友可以仔細看看文件,自己敲一遍看看。