一篇文章徹底明白,vue組件傳值

看了很多關於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組件傳值常用的幾種方式,如有錯誤,歡迎指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章