看了很多關於vue組件傳值的文章,於是想把文章總結一下,把關於vue組件傳值好好聊聊,歡迎大家指正。
組件之間傳值主要分兩種
1、父子組件:props方法、ref方法、children和parent方法、 emit方法
2、非父子組件:公共bus.js、attrs/listeners、vuex
一、父子組件傳值
1、props方法
父組件嵌套的子組件中,使用v-bind:msg=‘xxxx’進行對象的綁定,子組件中通過定義props接收對應的msg對象
父組件
<template>
<div>
<child v-bind:msg="msg" ></child>
</div>
</template>
<script>
// 引入子組件
import child from './child'
export default {
components: {
child,
},
data () {
return {
msg: '父組件傳給值'
}
},
}
</script>
子組件
<template>
<div>
<h5>{{msg}}</h5>
</div>
</template>
<script>
export default {
// 要接受父組件傳遞的參數,在 props 中添加了元素之後,就不需要在 data 中再添加變量了
props: {
msg: {
type: String
},
},
}
</script>
2、$ref方法
使用ref方法獲取指定的子組件,使父組件輕鬆獲取子組件的值,
父組件
<template>
<div>
<p>{{msg2}}</p>
<child ref="child"></child>
</div>
</template>
<script>
// 引入子組件
import child from './child'
export default {
components: {
child
},
data() {
return {
msg2: this.$refs.child.msg2
}
}
}
</script>
子組件
<template>
<div>
<h5>{{msg2}}</h5>
</div>
</template>
<script>
export default {
data(){
return{
msg2: "子組件傳給父組件"
}
}
}
</script>
3、children,parent方法
使用 parent 查找當前組件的父組件。
使用 this.$children 查找當前組件的直接子組件,可以遍歷全部子組件, 需要注意 $children 並不保證順序,也不是響應式的,故不推薦使用。
父組件
<template>
<div>
<h1>{{msg2}}</h1>
<child :msg2="msg2"></child>
</div>
</template>
<script>
// 引入子組件
import child from './child'
export default {
components: {
child
},
data() {
return {
msg: "父組件傳給子組件",
msg2: ""
}
},
mounted(){
// 注意,this.$children[0].msg2只能在mounted生命週期下面才能獲取,否則會報錯
this.msg2 = this.$children[0].msg2
}
}
</script>
子組件
<template>
<div>
<h5>{{msg}}</h5>
</div>
</template>
<script>
export default {
data(){
return{
msg2: "子組件傳給父組件",
msg: this.$parent.msg
}
}
}
</script>
4、emit方法
子組件使用emit觸發父組件的自定義事件:
vm.$emit( event, arg ) //觸發當前實例上的事件
vm.$on( event, fn ) //監聽event事件後運行 fn
父組件
<template>
<div>
<h1>{{msg2}}</h1>
<child @eventName="changeMsg"></child>
</div>
</template>
<script>
// 引入子組件
import child from './child'
export default {
components: {
child
},
data() {
return {
msg2: "父組件的值",
}
},
methods:{
//changeMsg是自定義方法名,msg是子組件傳過來的參數
changeMsg(msg){
this.msg2 = msg
}
}
}
</script>
子組件
<template>
<div>
<button @click="open">請點擊</button>
</div>
</template>
<script>
export default {
data(){
return{
msg: "子組件傳給父組件"
}
},
methods: {
open(){
//eventName是父組件的自定義方法名,this.msg是傳過去的參數
this.$emit('eventName', this.msg)
}
}
}
</script>
二、非父子組件傳值
1、公共的bus.js
1、兄弟之間傳遞數據需要藉助於事件車,通過事件車的方式傳遞數據。
2、創建一個Vue的實例,讓各個兄弟共用同一個事件機制。
3、傳遞數據方,通過一個事件觸發bus.$emit(方法名,傳遞的數據)。
4、接收數據方,通過mounted(){}觸發bus.$on (方法名,function(接收數據的參數){用該組件的數據接收傳遞過來的數據}),此時函數中的this已經發生了改變,可以使用箭頭函數。
bus.js
import Vue from 'vue'
export default new Vue
公共組件存放兄弟組件
<template>
<div>
<list1></list1>
<list2></list2>
</div>
</template>
<script>
import list1 from './list1'
import list2 from './list2'
export default {
components:{
list1,
list2
}
}
</script>
兄弟組件1
<template>
<div>
<h1>{{msg}}</h1>
<button @click="trans">把值傳給小弟</button>
</div>
</template>
<script>
import bus from "./bus"
export default {
data() {
return {
msg: "大哥組件的值傳給小弟",
}
},
methods:{
trans(){
bus.$emit('eventName', this.msg)
}
}
}
</script>
兄弟組件2
<template>
<div>
<h5>{{msg}}</h5>
</div>
</template>
<script>
import bus from "./bus"
export default {
data() {
return {
msg: "小弟組件的值",
}
},
mounted(){
bus.$on('eventName', val =>{
this.msg = val;
})
}
}
</script>
2、attrs和listeners的使用
在很多開發情況下,我們只是想把A組件的信息傳遞給C組件,如果使用props 綁定來進行信息的傳遞,雖然能夠實現,但是代碼並不美觀。
在vue2.4中,爲了解決該需求,引入了attrs 和listeners , 新增了inheritAttrs 選項。
在版本2.4以前,默認情況下父作用域的不被認作props的屬性,將會“回退”且作爲普通的HTML特性應用在子組件的根元素上。
$attrs
包含了父作用域中不被認爲 (且不預期爲) props 的特性綁定 (class 和 style 除外)。當一個組件沒有聲明任何 props 時,這裏會包含所有父作用域的綁定 (class 和 style 除外),並且可以通過 v-bind=”$attrs” 傳入內部組件——在創建更高層次的組件時非常有用。
$listeners
包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監聽器。它可以通過 v-on=”$listeners” 傳入內部組件——在創建更高層次的組件時非常有用。
inheritAttrs
默認情況下父作用域的不被認作 props 的特性綁定 (attribute bindings) 將會“回退”且作爲普通的 HTML 特性應用在子組件的根元素上。當撰寫包裹一個目標元素或另一個組件的組件時,這可能不會總是符合預期行爲。通過設置 inheritAttrs 到 false,這些默認行爲將會被去掉。而通過 (同樣是 2.4 新增的) 實例屬性 $attrs 可以讓這些特性生效,且可以通過 v-bind 顯性的綁定到非根元素上。
A組件
<template>
<div id="app">
<!-- 此處監聽了兩個事件,可以在B組件或者C組件中直接觸發 -->
<child1 :p-child1="child1" :p-child2="child2" v-on:test1="onTest1" v-on:test2="onTest2"></child1>
</div>
</template>
<script>
import Child1 from './Child1.vue'
export default {
data() {
return {}
},
components: { Child1 },
methods: {
onTest1() {
console.log('test1 running...')
},
onTest2() {
console.log('test2 running')
}
}
}
</script>
B組件
<template>
<div class="child-1">
<p>in child1:</p>
<p>props: {{pChild1}}</p>
<p>$attrs: {{$attrs}}</p>
<hr />
<!-- C組件中能直接觸發test的原因在於 B組件調用C組件時 使用 v-on 綁定了$listeners 屬性 -->
<!-- 通過v-bind 綁定$attrs屬性,C組件可以直接獲取到A組件中傳遞下來的props(除了B組件中props聲明的) -->
<child2 v-bind="$attrs" v-on="$listeners"></child2>
</div>
</template>
<script>
import Child2 from './Child2'
export default {
props: ['pChild1'],
data() {
return {}
},
inheritAttrs: false,
components: { Child2 },
mounted() {
this.$emit('test1')
}
}
</script>
C組件
<template>
<div class="child-2">
<p>in child2:</p>
<p>props: {{pChild2}}</p>
<p>$attrs: {{$attrs}}</p>
<hr />
</div>
</template>
<script>
export default {
props: ['pChild2'],
data() {
return {}
},
inheritAttrs: false,
mounted() {
this.$emit('test2')
}
}
</script>
3、vuex
vuex是我們開發中最常用的一種跨組件傳值方式,下期我們單獨聊聊vuex。以上就是vue組件傳值常用的幾種方式,如有錯誤,歡迎指正。