1. 程式人生 > 實用技巧 >Vue父子傳值

Vue父子傳值

vue父子傳值(一)

參考一:

父元件向子元件傳值:
parent:

<parent>
<child :message="msg"></child>
</parent>

data(){
return {
msg: "this is parent message"
}
}

child:

<div>
<p>{{message}}</p>
</div>

data(){
props:["message"]
}

or

props: {
message: {
type: String, //可指定接收型別,如:Array.
default:"this is default" //可設定預設值
}
}

props: {
message: {
type: Array,
default: ['foo','bar','baz'] //預設值
}
}

注意:parent中的子元件標籤中傳入的是 :message, (v-bind:”message”),如果傳入的是message=”msg”,那麼子元件接收到的是”msg”這個字串,因為message沒有繫結值。

子元件向父元件傳值
由於在vue中子元件不能更改父元件中的內容,所以可以通過子元件觸發事件來傳值給父元件。

child:

<template>
<button v-on:click ='setValue'>setValue</button>
</template>

data(){
return {
value: "sendValue"
}
},
methods:{
setValue:function(){
this.$emit('getdata',this.value); //this.value為向父元件傳遞的資料
}
}

parent:

<div id="app">
<child @getdata="receive" ></child> //自動監聽由子元件"註冊"的 'getdata'事件,然後呼叫receive方法來更改資料
<p>{{value}}</p>
</div>

data(){
return{
value:"default"
}
},
methods: {
receive:function(val) {
this.value = val;
}
}

這時候就可以看到父元件的p標籤中的資料更新了…

非父子元件之間的通訊
有時候兩個非父子關係元件也需要通訊 。在簡單的場景下,可以使用一個空的 Vue 例項作為中央事件匯流排,類似於一個“中轉站”,進行傳送和接收資料。

event.js

import Vue from 'vue'
var bus = new Vue() //建立事件"中轉站"
export default bus

or

import Vue from 'vue'
export default new Vue

a.vue

<button @click="btnclick">content</button >
// 觸發元件 A 中的事件

import eventdata from '.../event.js'
methods: {
btnclick(){
eventdata .$emit('transfer',this.message);
}
}

b.vue

// 在元件B監聽事件
<template>
<div>{{message}}</div>
</template>

import eventdata from '.../event.js'
data(){
return{
message:"default"
}
},
created() {
eventdata .$on('transfer', function(msg){ //接收事件
this.message = 'msg';
});
}

在資料簡單的情況下可以使用中轉或者父元件傳值給子元件的方法進行傳值,在資料比較多而雜的情況下,應該考慮使用專門的狀態管理模式 Vuex外掛來實現元件間的通訊.

參考二:

vue中我們常常用到元件. 那麼元件總體可以分為如下的幾種關係.
父子元件, 爺孫元件, 兄弟元件. 這幾種元件之間是如何通訊的呢?

父子元件通訊
根據vue中的文件可知, 元件的props屬性用於接收父元件傳遞的資訊. 而子元件想要向父元件傳遞資訊, 可以使用$emit事件.
我們定義兩個元件, 一個為父元件名為father, 另外一個為子元件child. 子元件通過props屬性接收父元件傳遞的值, 這個值為fname, 是父元件的名字. 點選子元件的按鈕, 觸發toFather事件, 向父元件傳遞訊息. 父元件做出相應的反應.
將父元件和子元件放入名為app的vue例項中

Vue.component('child', {
props: ['fname'],
template: `
<div class="child">
這是兒子, 我爸爸是{{fname}}
<button @click="$emit('toFather')">點我通知爸爸</button>
</div>
`
})

Vue.component('father', {
data() {
return {
info: '無訊息'
}
},
template: `
<div class="father">
這是父親, {{info}}
<child fname="father" @toFather="getSonMsg"></child>
</div>
`,
methods: {
getSonMsg() {
this.info = '我收到兒子傳來的訊息了'
}
}
})
new Vue({
el: '#app',
})

注意上面的元件定義順序不能換
讓後我們在html檔案中寫入即可

<div id="app">
<father></father>
</div>

爺孫元件通訊
因為vue只是說明了父子元件如何通訊, 那麼爺孫元件是沒有辦法直接通訊的. 但是它們可以分解為兩個父子元件通訊.
即爺爺和父親看成是一個父子元件, 而父親和孫子看成是一個父子元件. 這樣它們之間就可以進行通訊了. 通過父親元件合格橋樑, 可以實現爺孫的通訊. (注意: 爺孫元件是無法直接通訊的)

兄弟元件通訊
兄弟元件通訊即元件之間通訊. 這就要用到觀察者模式了. 因為vue例項的原型全部來自Vue.prototype. 那麼我們就可以了將事件中心繫結到Vue.prototype的某個屬性上, 暫且叫它為bus吧.

let bus = new Vue()
Vue.prototype.bus = bus


我們再定義兩個元件, up元件和down元件, 當點選down元件中的按鈕時, 會給up元件傳遞資訊.

Vue.component('up', {
data() {
return {
msg: '未傳遞訊息'
}
},
template: `
<div class="up">
<p>這是up元件, 下一行為down傳遞的訊息</p>
<p>{{msg}}</p>
</div>
`,
mounted() {
this.bus.$on('send', (msg)=> {
this.msg = (msg)
})
}
})

Vue.component('down', {
template: `
<div class="down">
<p>這是down</p>
<button @click="toUp">點選我向up元件傳遞訊息</button>
</div>
`,
methods: {
toUp() {
this.bus.$emit('send', 'down來訊息了')
}
}
})
new Vue({
el: '#app',
})
並且將兩個元件放入名為app的例項中

<div id="app">
<up></up>
<down></down>
</div>

按鈕被點選後, up元件會接收到訊息

參考三:

Vue 常用的三種傳值方式
1.父傳子
2.子傳父
3.非父子傳值

父子元件的關係
首先,我們要使用Vue的元件傳值,我們要知道元件之間的關係。
父子元件的關係可以總結為 prop 向下傳遞,事件向上傳遞。父元件通過 prop 給子元件下發資料,子元件通過事件給父元件傳送訊息,如下圖所示


什麼是Prop
要實現元件傳值,我們要了解什麼是prop。
Prop是用來傳遞資料的一種自定義屬性。
Prop是單向資料流。所有的 prop 都使得其父子 prop 之間形成了一個單向下行繫結:父級 prop 的更新會向下流動到子元件中,但是反過來則不行。這樣會防止從子元件意外改變父級元件的狀態,從而導致你的應用的資料流向難以理解。
額外的,每次父級元件發生更新時,子元件中所有的 prop 都將會重新整理為最新的值。這意味著你不應該在一個子元件內部改變 prop。如果你這樣做了,Vue 會在瀏覽器的控制檯中發出警告。

父傳子
父元件的內容傳遞給子元件其實很簡單
首先建立倆個Vue的元件,例father.vue,child.vue
在father.vue的元件寫上

<template>
<div>
<span>父元件:</span>
</div>
</template>

記住,我們的template下,只能擁有一個標籤
在child.vue的元件寫上

<template>
<div>
<span>子元件:</span>
</div>
</template>

我們把子元件的內容引入到父元件裡
於是,我們在father.vue匯入

import child from './child.vue' // 引入子元件

然後,我們開始註冊自定義標籤

export default {
name: "father",
components:{
child //這個名字是上面我們引進來的child.vue,倆個名字需相同
}
}

<template>
<div>
<span>父元件:</span>
<child></child>
</div>
</template>
1
2
3
4
5
6
我們開始v-model繫結資料
在data資料裡寫上name

export default {
name: "father",
data() {
return {
name: ''
}
},
components:{
child //這個名字是上面我們引進來的child.vue,倆個名字需相同
}
}

data裡的資料為什麼要return出來呢?
1.不使用return 出來的資料會在專案的全域性可見,會汙染全域性
2.使用return 出來的資料只能在當前元件中使用,不會影響其他元件

當一個元件被定義, data 必須宣告為返回一個初始資料物件的函式,因為元件可能被用來建立多個例項。如果 data 仍然是一個純粹的物件,則所有的例項將共享引用同一個資料物件!通過提供 data 函式,每次建立一個新例項後,我們能夠呼叫 data 函式,從而返回初始資料的一個全新副本資料物件。

我們在元件中繫結data資料的name,在自定義標籤中傳遞要傳遞的值

<template>
<div>
<span>父元件:</span>
<input type="text" v-model="name">
<child :notice="name"></child>
</div>
</template>

最後,在child.vue元件中利用props來接收傳遞來的引數

export default {
name: "child",
data() {
return {}
},
props: ['notice']
}

在上面的模板中運用傳遞來的引數

<template>
<div>
<span>子元件:{{notice}}</span>
</div>
</template>

父傳子所有的程式碼
father.vue

<template>
<div>
<span>父元件:</span>
<input type="text" v-model="name">
<child :notice="name"></child>
</div>
</template>

<script>
import child from './child.vue' // 引入子元件
export default {
name: "father",
data() {
return {
name: ''
}
},
components:{
child //這個名字是上面我們引進來的child.vue,倆個名字需相同
}
}
</script>

<style scoped>

</style>


child.vue的程式碼

<template>
<div>
<span>子元件:{{notice}}</span>
</div>
</template>

<script>
export default {
name: "child",
data() {
return {}
},
props: ['notice']
}
</script>

<style scoped>

</style>



子傳父
首先,我們要點選一個按鈕,使子元件的值傳到父元件。
於是,我們在子元件,寫點選事件。
(這裡在input的標籤上繫結資料,還是和之前的一樣)

<template>
<div>
<span>子元件:</span>
<input type="text" v-model="childvalue"> //雙向繫結childvalue
<input type="button" value="傳值到父親" @click="childclick"> //點選事件
</div>
</template>

export default {
name: "child",
props: ['notice'], //接收父元件傳遞的值
data() {
return {
childvalue:this.notice
}
},
methods: {
childclick() {
this.$emit("childByvalue", this.childvalue) // 利用$emit的方法把值傳遞給父元件
}
}
}

我們在父元件中接收傳遞的值利用的是v-on:,簡寫用@

<child :notice="name" @childByvalue="childByvalue"></child>

在下面的methods寫方法

methods : {
childByvalue (val) {
this.name=val
}
},

這時候細心的同學會發現子傳父可以了,但父傳子不能用了。
這時候就用到了watch來監聽了。
在父元件中監聽傳遞過了的值。

watch:{
notice () {
this.childvalue=this.notice
}
},

這樣父子元件的通訊就完成了。
父元件的完整程式碼

<template>
<div>
<span>父元件:</span>
<input type="text" v-model="name">
<child :notice="name" @childByvalue="childByvalue"></child>
</div>
</template>

<script>
import child from './child.vue' // 引入子元件
export default {
name: "father",
data() {
return {
name: ''
}
},
methods : {
childByvalue (val) {
this.name=val
}
},
components:{
child //這個名字是上面我們引進來的child.vue,倆個名字需相同
}
}
</script>

<style scoped>

</style>



子元件的完整程式碼

<template>
<div>
<span>子元件:</span>
<input type="text" v-model="childvalue">
<input type="button" value="傳值到父親" @click="childclick">
</div>
</template>

<script>
export default {
name: "child",
props: ['notice'],
data() {
return {
childvalue:this.notice
}
},
watch:{
notice () {
this.childvalue=this.notice
}
},
methods: {
childclick() {
this.$emit("childByvalue", this.childvalue)
// 利用$emit的方法把值傳遞給父元件
}
}
}
</script>

<style scoped>

</style>


非父子傳值(兄弟元件傳參)
非父子傳參,需要有共同的父元件。需要定義公共的公共例項檔案,作為中間倉庫。不然達不到傳值效果。
建立bus.js做為公共的倉庫檔案
bus.js內容為

import Vue from 'Vue'
export default new Vue

建立child1.vue,child2.vue
child1.vue內容為

<template>
<div>
<span>child1</span>
<span>{{msg}}</span>
<button @click="childclick">點選</button>
</div>
</template>

<script>
import bus from './bus.js'
export default {
name: "child1",
data () {
return {
msg :'123'
}
},
methods : {
childclick () {
bus.$emit('val',this.msg)
}
}
}
</script>

<style scoped>

</style>


child2的內容為

<template>
<div>
<span>child2</span>
<span>{{cmsg}}</span>
</div>
</template>

<script>
import bus from './bus.js'
export default {
name: "child2",
data () {
return {
cmsg : ''
}
},
mounted () {
let that =this
bus.$on('val',(data)=>{
console.log(data);
this.cmsg=data
})
}
}
</script>

<style scoped>

</style>

在父元件中匯入註冊

import child1 from './child1.vue'
import child2 from './child2.vue'

components:{
child1,
child2
}

<child1></child1>
<child2></child2>

參考四:

父元件是使用 props 傳遞資料給子元件,但如果子元件要把資料傳遞回去,應該怎樣做?那就是自定義事件!

每個vue例項都有觸發事件的方法

  • 使用 $on(eventName) 監聽事件
  • 使用 $emit(eventName) 觸發事件

父元件可以在使用子元件的地方直接用 v-on 來監聽子元件觸發的事件。然後再對應子元件方法執行處觸發事件,兩者缺一不可。

<!-- 父元件 -->
<div id="app">
  <!-- 子元件 -->
  <!-- 父元件直接用 v-on 來監聽子元件觸發的事件。 -->
  <!-- 需跟子元件中的$emit組合使用 -->
  <mycon v-on:son_method="father_method"></mycon>
</div>
// 子元件
Vue.component('mycon', {
  template: '<button v-on:click="son_method">子按鈕</button>',
  methods: {
  	// 按鈕點選時候觸發事件
    son_method: function () {
      this.counter += 1;
 	  console.log("son");
      // 這句話來觸發事件
      // 必須跟模板中的v-on配合使用
      this.$emit('son_method');
    }
  },
});

// 父元件
new Vue({
  el: "#app",
  methods: {
    father_method: function () {
      console.log("father");
    }
  }
});

繫結原生事件(適用於元件)

有時候,你可能想在某個元件的根元素上監聽一個原生事件。可以使用 .native 修飾 v-on 。例如:

<my-component v-on:click.native="doTheThing"></my-component>

使用自定義事件的表單輸入元件

表單輸入元件,使用 v-model 來進行資料雙向繫結。要讓元件的 v-model 生效,它必須:

  • 接受一個 value 屬性
  • 在有新的 value 時觸發 input 事件
<div id="app">
    <input v-model="something">
    <!-- 
		分兩步:
		第一步:通過v-bind給輸入框賦值
		第二步:通過v-on:input事件執行一句something = $event.target.value更改something
     -->
    <input v-bind:value="something" v-on:input="something = $event.target.value">
    <!-- 簡寫 -->
   <input v-bind:value="something" v-on:input="something = arguments[0]"><input>
</div>
new Vue({
  el: "#app",
  data:{
  	something:123
  },
  watch: {
  	something:function() {
  		console.log(234)
  	}
  }
});

非父子元件通訊

在簡單的場景下,使用一個空的 Vue 例項作為中央事件匯流排:

var bus = new Vue()

// 觸發元件 A 中的事件
bus.$emit('id-selected', 1)

// 在元件 B 建立的鉤子中監聽事件
bus.$on('id-selected', function (id) {
  // ...