Vue父子元件通訊小總結

Storm4542發表於2018-09-10

感覺Vue中父子傳參的方式,實在是太多了,於是做一個小總結,只是總結我所知道的。 歡迎吐槽

1.父傳子

基本就用一個方式,props

父親通過在 標籤 中寫入需要傳入的資料。

<!--father.vue-->
<template>
    <div>
        我是爸爸,下面是兒子
        <son title='兒子' :selected='selected'></son>
    </div>
</template>
複製程式碼

兒子在 例項中的 props 選項中獲取

//son.vue
export default {
    name:'son',
    props:{
        selected:{
            type:Boolean
        },
        title:{
            type:String
        }
    }
}
複製程式碼

2.子傳父

# update:my-prop-name 模式

Vue 是單項資料流,所以不允許 兒子 直接修改父親的資料,也不允許兒子直接修改自己的props

假設一個情況,點選兒子,兒子需要改變 selected 的狀態。

兒子方面

觸發點選事件後, 讓兒子觸發一個 update 事件,把新的 selected 傳出去

<!--son.vue-->
<template>
    <div class="son" @click="onClick">
        title:{{title}} selected:{{selected}}
    </div>
</template>
<script>
export default {
  name: "son",
  props: {
    selected: {
      type: Boolean
    },
    title: {
      type: String
    }
  },
  methods: {
    onClick() {
      this.$emit("update:selected", !this.selected); //關鍵點
    }
  }
};
</script>

<style>
.son {
  border: 1px solid red;
}
</style>
複製程式碼

父親方面

在標籤中監聽 update事件,並將傳過來的 $event付給 selected,這樣就完成了一次傳參。

<!--father.vue-->
<template>
    <div>
        我是爸爸,下面是兒子
        <son title='兒子' :selected='selected' @update:selected='selected=$event'></son> 
        <!--關鍵點-->
    </div>
</template>

<script>
import Son from "./son";
export default {
  name: "father",
  components: {
    Son
  },
  data() {
    return {
      selected: true
    };
  }
};
</script>
複製程式碼

簡單方式

.sync 修飾符

<!--father.vue-->
<template>
    <div>
        我是爸爸,下面是兒子
        <son title='兒子' :selected.sync='selected'></son> 
        <!--關鍵點-->
    </div>
</template>
複製程式碼

# $parents API

兒子方面

this.$parent中可以獲取到 父元件 的 data 資料 ,直接進行修改,是不是很刺激。

methods: {
    onClick() {
      this.$parent.selected = !this.$parent.selected;
    }
  }
複製程式碼

雖然刺激,但是,我建議呼叫父元件的函式,來切換狀態。

父親方面

//father.vue
export default {
  name: "father",
  components: {
    Son
  },
  data() {
    return {
      selected: true
    };
  },
  methods: {
    changeSelected() {
      this.selected = !this.selected;
    }
  }
};
複製程式碼

兒子方面

//son.vue 
methods: {
    onClick() {
      this.$parent.changeSelected();
    }
  }
複製程式碼

# EventBus

如果只是一個父親,一個兒子上面的方法非常的簡單實用,但是如果是祖孫三代傳參呢?上面的方法就很麻煩了。

具體怎麼麻煩,可以看一下我的這篇文章,用原始的方法造 tabs輪子:zhuanlan.zhihu.com/p/39601572

廢話不多說,開始用 EventBus做一個簡單的 tabs元件。

#app.vue
<template>
  <div id="app">
    <tab selected='news'>
      <tab-item name='news'>新聞</tab-item>
      <tab-item name='car'>汽車</tab-item>
      <tab-item name=‘code’>程式碼</tab-item>

      <tab-pane name='news'>新聞列表</tab-pane>
      <tab-pane name='car'>汽車列表</tab-pane>
      <tab-pane name=‘code’>程式碼列表</tab-pane>
    </tab>
  </div>
</template>

<script>
import Tab from "./components/tabs.vue";
import TabItem from "./components/tab-item";
import TabPane from "./components/tab-pane";

export default {
  name: "app",
  components: {
    Tab,
    TabItem,
    TabPane
  }
};
</script>
複製程式碼
# tabs.vue
<template>
    <div>
        <slot></slot>
    </div>
</template>

<script>
import TabItem from "./tab-item.vue";
import Vue from "vue";  //引入VUE
export default {
  name: "tab",
  props: {
    selected: {
      type: [Number, String]
    }
  },
  data() {
    return {
      eventBus: new Vue() // 建立 eventBus
    };
  },
  provide() {
    return {
      eventBus: this.eventBus // 提供 eventBus
    };
  },
  mounted() {
    this.eventBus.$emit("update:selected", this.selected); 
      //釋出訊息,告訴大家,現在的selected是啥
  }
};
</script>

<style>
</style>
複製程式碼
# tabs-item.vue
<template>
    <div @click="onClick" :class="{active}">
        <slot/>
    </div>
</template>

<script>
export default {
  name: "tab-item",
  props: {
    name: {
      type: [String, Number]
    }
  },
  inject: ["eventBus"], //注入 eventBus
  data() {
    return {
      active: false
    };
  },
  created() {
    this.eventBus.$on("update:selected", newSelected => {
      this.active = this.name === newSelected;
    }); //接收訊息,如果newselected 和我的 name 相同,那麼我就被選中了
  },
  methods: {
    onClick() {
      this.eventBus.$emit("update:selected", this.name);
        //釋出訊息,如果點選了我,我就告訴大家,我被選中了
    }
  }
};
</script>

<style>
.active {
  color: red;
}
</style>
複製程式碼
# tab-pane.vue
<template>
  <div v-if="active" class="pane">
    <slot/>
  </div>
</template>

<script>
export default {
  name: "tab-pane",
  props: {
    name: {
      type: [String, Number]
    }
  },
  data() {
    return {
      active: false
    };
  },
  inject: ["eventBus"],//注入 eventBus
  created() {
    this.eventBus.$on("update:selected", newSelected => {
      this.active = this.name === newSelected;
    });
      //接收訊息,如果newselected 和我的 name 相同,那麼我就被選中了
  }
};
</script>

<style>
.pane {
  color: red;
}
</style>
複製程式碼

# 靈活運用 provide inject

//father.vue
export default {
    name:'father',
    data(){
        return {
            someThing:'father'
        }
    },
    provide(){
        return {
            father:this
        }
    }
}
複製程式碼
//son.vue
export default {
    name:'son',
    inject:['father'],
    methods:{
        onClick(){
            this.father.someThing = 'son'
        }
    }
}
複製程式碼

相關文章