vue2組件傳值的方法

  • 父子組件通信: props/$emit; ref/$refs;$attrs / $listeners$parent / $children
  • 兄弟組件通信: eventBus;vuex
  • 跨級通信: eventBus;Vuex;$attrs / $listeners

一、props/$emit(父子組件通信)

1.父組件向子組件傳值

通過 props 傳值。
父組件的代碼:

<template>
  <div class="son">
    <child :list="list"></child>
  </div>
</template>
<script>
import child from './child.vue'
export default {
  components: { child },
  data() {
    return {
      list: ['a1', 'b2', 'c3']
    }
  }
}
</script>

子組件的代碼(即 child.vue):

<template>
  <div>
    <span v-for="(item, index) in list" :key="index">{{item}}</span>
  </div>
</template>
<script>
export default {
  props: ['list'],
}
</script>
2.子組件向父組件傳值

$emit綁定一個自定義事件, 當(dāng)這個語句被執(zhí)行時, 就會將參數(shù)arg 傳遞給父組件,父組件通過v-on 監(jiān)聽并接收參數(shù)。
父組件的代碼:

<template>
  <div class="section">
    <child :list="list"  @onEmitIndex="onEmitIndex"></child>
    <p>{{item}} => {{currentIndex}}</p>
  </div>
</template>
<script>
import child from './child.vue'
export default {
  components: { child },
  data() {
    return {
      currentIndex: -1,
      item: '',
      list: ['a1', 'b2', 'c3']
    }
  },
  methods: {
    onEmitIndex(arg) {
      this.currentIndex = arg.index;
      this.item = arg.item;
    }
  }
}
</script>

子組件的代碼(即 child.vue):

<template>
  <div>
    <button v-for="(item, index) in list" :key="index" @click="emitIndex(index, item)">{{item}}</button>
  </div>
</template>
<script>
export default {
  props: ['list'],
  methods: {
    emitIndex(index, item) {
      this.$emit('onEmitIndex', {index, item})
    }
  }
}
</script>

二、ref/$refs(父子組件通信)

ref如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子組件上,引用就指向組件實(shí)例,可以通過實(shí)例直接調(diào)用組件的方法或訪問數(shù)據(jù)。也算是子組件向父組件傳值的一種。

  • vue訪問子組件實(shí)例或子元素
    父組件 parent.vue:
<template>
  <div>
    <button @click="sayHello">sayHello</button>
    <child ref="childForRef"></child>
  </div>
</template>
<script>
import child from './child.vue'
  export default {
    components: { child },
    data () {
      return {
        childForRef: null,
      }
    },
    mounted() {
      this.childForRef = this.$refs.childForRef;
      console.log(this.childForRef.name);
      // this.childForRef.sayHello();
    },
    methods: {
      sayHello() {
        this.childForRef.sayHello()
      }
    }
  }
</script>

子組件 child.vue:

<template>
  <div>child 的內(nèi)容</div>
</template>
<script>
export default {
  data () {
    return {
      name: '我是 child',
    }
  },
  methods: {
    sayHello () {
      console.log('hello');
      alert('hello');
    }
  }
}
</script>

三、eventBus(兄弟組件通信、跨級通信)

eventBus 又稱為事件總線,在 vue 中可以使用它來作為溝通橋梁的概念, 就像是所有組件共用相同的事件中心,可以向該中心注冊發(fā)送事件或接收事件, 所以組件都可以通知其他組件。一般用來兄弟組件和隔代組件傳值。
1.首先需要創(chuàng)建一個事件總線并將其導(dǎo)出, 以便其他模塊可以使用或者監(jiān)聽它。
bus.js:

import Vue from 'vue'
export const bus = new Vue()

2.發(fā)送事件,假設(shè)有 child1、child2 兩個兄弟組件,在 child1.vue 中使用bus.$emit()發(fā)送事件。
parent.vue:

<template>
  <div>
    <child1></child1>
    <child2></child2>
  </div>
</template>
<script>
import child1 from './child1.vue'
import child2 from './child2.vue'
export default {
  components: { child1, child2 }
}
</script>

child1.vue:

<template>
  <div>
    <button @click="additionHandle">+加法器</button>    
  </div>
</template>
<script>
import {bus} from '@/bus.js'
// console.log(bus)
export default {
  data(){
    return{
      num:1
    }
  },
  methods:{
    additionHandle(){
      bus.$emit('addition', {
        num:this.num++
      })
    }
  }
}
</script>

3.在 child2.vue 中使用bus.$on()接收事件。

<template>
  <div>計(jì)算和: <br>child1Num => {{child1Num}}<br>count + child1Num => {{count}}</div>
</template>
<script>
import { bus } from '@/bus.js'
export default {
  data() {
    return {
      child1Num: 0,
      count: 0,
    }
  },
  mounted() {
    bus.$on('addition', arg=> {
      this.child1Num = arg.num;
      this.count = this.count + arg.num;
    })
  }
}
</script>

4.如果想移除事件的監(jiān)聽, 可以像下面這樣操作:

import { bus } from './bus.js'
bus.$off('addition', {})

四、Vuex(兄弟組件通信、跨級通信)

父組件:

<template>
  <div id="app">
    <ChildA/>
    <ChildB/>
  </div>
</template>

<script>
  import ChildA from './ChildA' // 導(dǎo)入A組件
  import ChildB from './ChildB' // 導(dǎo)入B組件

  export default {
    name: 'App',
    components: {ChildA, ChildB} // 注冊A、B組件
  }
</script>

子組件childA:

<template>
 <div id="childA">
   <h1>我是A組件</h1>
   <button @click="transform">點(diǎn)我讓B組件接收到數(shù)據(jù)</button>
   <p>因?yàn)槟泓c(diǎn)了B,所以我的信息發(fā)生了變化:{{BMessage}}</p>
 </div>
</template>

<script>
 export default {
   data() {
     return {
       AMessage: 'Hello,B組件,我是A組件'
     }
   },
   computed: {
     BMessage() {
       // 這里存儲從store里獲取的B組件的數(shù)據(jù)
       return this.$store.state.BMsg
     }
   },
   methods: {
     transform() {
       // 觸發(fā)receiveAMsg,將A組件的數(shù)據(jù)存放到store里去
       this.$store.commit('receiveAMsg', {
         AMsg: this.AMessage
       })
     }
   }
 }
</script>

子組件 childB:

<template>
 <div id="childB">
   <h1>我是B組件</h1>
   <button @click="transform">點(diǎn)我讓A組件接收到數(shù)據(jù)</button>
   <p>因?yàn)槟泓c(diǎn)了A,所以我的信息發(fā)生了變化:{{AMessage}}</p>
 </div>
</template>

<script>
 export default {
   data() {
     return {
       BMessage: 'Hello,A組件,我是B組件'
     }
   },
   computed: {
     AMessage() {
       // 這里存儲從store里獲取的A組件的數(shù)據(jù)
       return this.$store.state.AMsg
     }
   },
   methods: {
     transform() {
       // 觸發(fā)receiveBMsg,將B組件的數(shù)據(jù)存放到store里去
       this.$store.commit('receiveBMsg', {
         BMsg: this.BMessage
       })
     }
   }
 }
</script>

vuex的store.js

import Vue from 'vue'
 import Vuex from 'vuex'
 Vue.use(Vuex)
 const state = {
   // 初始化A和B組件的數(shù)據(jù),等待獲取
   AMsg: '',
   BMsg: ''
 } 
 const mutations = {
   receiveAMsg(state, payload) {
     // 將A組件的數(shù)據(jù)存放于state
     state.AMsg = payload.AMsg
   },
   receiveBMsg(state, payload) {
     // 將B組件的數(shù)據(jù)存放于state
     state.BMsg = payload.BMsg
   }
 }
 
 export default new Vuex.Store({
   state,
   mutations
 })

然后需要在 main.js 中引入 vuex

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store';

Vue.config.productionTip = false

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

五、$attrs/$listeners(父子組件通信、跨級通信)

parent.vue:

<template>
  <div>
    <child-a :name="name" :age="age" :gender="gender" :height="height" title="嘿嘿嘿"></child-a>
  </div>
</template>
<script>
import ChildA from './ChildA'
export default {
  components: { ChildA },
  data() {
    return {
      name: "zhang",
      age: "18",
      gender: "女",
      height: "158"
    };
  }
};
</script>

childA.vue:

<template>
 <div>
   <p>props 接收到的 name: {{ name}}</p>
   <p>childA 的 $attrs: {{$attrs}}</p>
   <child-b v-bind="$attrs"></child-b>
 </div>
</template>
<script>
const childB = () => import("./childB.vue");
export default {
 components: {
   childB
 },
 inheritAttrs: false, // 可以關(guān)閉自動掛載到組件根元素上的沒有在props聲明的屬性
 props: {
   name: String // name作為props屬性綁定
 },
 created() {
   console.log(this.$attrs);
    // { "age": "18", "gender": "女", "height": "158", "title": "嘿嘿嘿" }
 }
};
</script>

childB.vue:

<template>
 <div class="border">
   <p>props 接收到的 age: {{age}}</p>
   <p>childB 的 $attrs: {{$attrs}}</p>
 </div>
</template>
<script>

export default {
 inheritAttrs: false,
 props: {
   age: String
 },
 created() {
   console.log(this.$attrs); 
   // { "gender": "女", "height": "158", "title": "嘿嘿嘿" }
 }
};
</script>
<style scoped>
 .border{border: 1px solid #000;}
</style>

六、$children/$parent(父子組件通信)

parent.vue:

 <template>
  <div>
    <div>{{msg}}</div>
    <child></child>
    <button @click="changeA">點(diǎn)擊改變子組件值</button>
  </div>
</template>

<script>
import Child from './child'
export default {
  components: { Child },
  data() {
    return {
      msg: 'Welcome'
    }
  },

  methods: {
    changeA() {
      this.$children[0].messageA = 'this is new value'
    }
  }
}
</script>

child.vue:

<template>
  <div class="com_a">
    <span>{{messageA}}</span>
    <p>獲取父組件的值為:  {{parentVal}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      messageA: 'this is old'
    }
  },
  computed:{
    parentVal(){
      return this.$parent.msg;
    }
  }
}
</script>

要注意邊界情況,如在 #app 上拿 $parent的是 new Vue() 的實(shí)例,在這實(shí)例上再拿 $parent得到的是 undefined,而在最底層的子組件拿 $children是個空數(shù)組。也要注意得到 $parent 和 $children 的值不一樣,$children的值是數(shù)組,而 $parent 是個對象。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容