Vue傳參一籮筐

dongfangyiyu發表於2019-04-03

Vue頁面、元件之間傳參方式繁多,此處羅列出常用的幾種方式,歡迎審閱補充。

一丶路由傳參

這裡的路由傳參以程式設計式router.push(...)為例,宣告式<router-link :to="...">與之類似。此處模擬情景為從componentsA.vue頁面跳轉到componentsB.vue頁面傳參。首先,路由配置資訊如下:

router.js

import Vue from 'vue'
import Router from 'vue-router'

import componentsA from './components/componentsA' //在components下建立componentsA.vue
import componentsB from './components/componentsB' //在components下建立componentsB.vue
Vue.use(Router)

export default new Router({
	routes:[
		{
			path:'/componentsA',
			name:'componentsA',
			component:componentsA
		},
		{
			path:'/componentsB',
			name:'componentsB',
			component:componentsB
		}
	]
})複製程式碼

1.1 路由配置傳參

首先確定自己要傳的引數名,將路由配置修改一下,傳name,age,sex三個引數:

		{
			path:'/componentsB/:name/:age/:sex',
			name:'componentsB',
			component:componentsB
		}複製程式碼

componentsA.vue頁面通過this.$router.push配置與之對應的引數:

componentsA.vue

<template>
	<div>
		<div>我是元件A</div>
		<button @click='routerToB1'>方式一跳轉到元件B</button>
	</div>
</template>
<script>
	export default{
		data(){
			return{
				person:{name:'Gene',age:'18',sex:'male'}
			}
		},
		methods: {
			routerToB1() {
				this.$router.push({
					path:`componentsB/${this.person.name}/${this.person.age}/${this.person.sex}`
				})
			}
		},
	}
</script>
<style>
</style>複製程式碼

然後在componentsB.vue頁面用this.$route.params接收引數:

componentsB.vue

<template>
	<div>
		<div>我是元件B</div>
	</div>
</template>
<script>
	export default{
		created(){
			this.getRouterData()
		},
		methods: {
			getRouterData(){
				const param = this.$route.params
				console.log(param)//{name:'Gene',age:'18',sex:'male'}
			}
		},
	}
</script>
<style>
</style>複製程式碼

點選按鈕"方式一跳轉到元件B",componentsB頁面列印出{name:'Gene',age:'18',sex:'male'},成功獲取到A頁面傳過來的引數,並且位址列顯示為localhost:8889/#/componentsB/Gene/18/male(埠號根據自己設定的來),表明這種傳參方式url會攜帶引數。

1.2 params傳參

首先將剛才路由配置修改部分還原,在componentsA.vue頁面新增按鈕"方式二跳轉到元件B":

componentsA.vue

<template>
	<div>
		<div>我是元件A</div>
		<button @click='routerToB1'>方式一跳轉到元件B</button>
		<button @click='routerToB2'>方式二跳轉到元件B</button>
	</div>
</template>複製程式碼

methods中新增方法routerToB2,使用路由屬性name來確定匹配的路由,使用屬性params來傳遞引數:

componentsA.vue

			routerToB2(){
				this.$router.push({
					name:'componentsB',
					params:{
						exa:'我是傳到元件B的引數'
					}
				})
			},複製程式碼

componentsB.vue保持不變,params傳參方式獲取引數也是通過this.$route.params,點選A頁面新新增的按鈕"方式二跳轉到元件B",在B頁面列印出{exa: "我是傳到元件B的引數"},傳參成功,位址列為localhost:8889/#/componentsB,表明這種方式url不會攜帶引數。

1.3 query傳參

這種方式和params傳參方式類似,在componentsA.vue頁面繼續新增按鈕"方式三跳轉到元件B":

componentsA.vue

<template>
	<div>
		<div>我是元件A</div>
		<button @click='routerToB1'>方式一跳轉到元件B</button>
		<button @click='routerToB2'>方式二跳轉到元件B</button>
		<button @click='routerToB3'>方式三跳轉到元件B</button>
	</div>
</template>複製程式碼

methods中新增方法routerToB3,使用路由屬性name或者path來確定匹配的路由,使用屬性query 來傳參:

componentsA.vue

			routerToB3(){
				this.$router.push({
					name:'componentsB',// path:'/componentsB'
					query:{
						que:'我是通過query傳到元件B的引數'
					}
				})
			}複製程式碼

componentsB.vue頁面通過this.$route.query來獲取引數:

componentsB.vue

			getRouterData(){
				const query = this.$route.query
				console.log(query)//{que: "我是通過query傳到元件B的引數"}
			}複製程式碼

檢視位址列為localhost:8889/#/componentsB?que=我是通過query傳到元件B的引數,顯然這種方式url會攜帶引數。

1.4 小結

  • 路由配置傳參注意書寫格式/:id,獲取引數都是通過$route而不是$router
  • params傳參和query傳參區別類似於postget方法。params傳參位址列不會顯示引數,而query傳參會將引數顯示在位址列中
  • params傳參重新整理頁面引數會丟失,另外兩種不會
  • params傳參對應的路由屬性是name,而query傳參對應的路由屬性既可以是name,也可以是path

二丶使用快取

快取方式即通過sessionStoragelocalStorageCookie方式傳參,這種方式和是不是用Vue無關,因此,不談。

三丶父子元件之間傳值

在components目錄下建立父元件parent.vue和子元件children.vue,在父元件中引入子元件。為了演示方便,在路由配置中加入/parent路徑。

3.1 父元件向子元件傳值 props

parent.vue的子元件標籤上註冊message1,在children.vue中通過props接收message1,如果傳遞的值為變數,則使用v-bind:或直接用:,參考如下:

parent.vue

<template>
	<div>
		<div>我是父元件</div>
		<children message1='我是直接引數' v-bind:message2='msg' :message3='obj'></children>
	</div>
</template>

<script>
	import Children from './children'
	export default{
		components:{
			Children
		},
		data(){
			return{
				msg:'我是父元件的引數'
			}
		},
		created(){
			this.obj = {a:'1',b:'2',c:'3'}
		}
	}
</script>

<style>
</style>
複製程式碼

children.vue

<template>
	<div>
		<div>我是子元件</div>
		<div>{{message1}}</div>
		<div>{{message2}}</div>
		<div>{{message3}}</div>
	</div>
</template>

<script>
	export default{
		props:['message1','message2','message3'],
		created(){
			console.log(this.message3)
		}
	}
</script>

<style>
</style>複製程式碼

在瀏覽器中開啟:

Vue傳參一籮筐

3.2 子元件向父元件傳值 $emit

子元件通過vm.$emit( event, […args] ),觸發當前例項上的事件。附加引數都會傳給監聽器回撥。父元件在子元件標籤上監聽事件獲得引數。

children.vue

<template>
	<div style="margin-top: 100px;">
		<div>我是子元件</div>
		<div>{{message1}}</div>
		<div>{{message2}}</div>
		<div>{{message3}}</div>
		<button @click='ChildToParent'>點我傳愛</button>
	</div>
</template>

<script>
	export default{
		props:['message1','message2','message3'],
		data(){
			return{
				loud:'I love xx'
			}
		},
		methods:{
			ChildToParent(){
				this.$emit('emitToParent',this.loud)
			}
		},
		created(){
			console.log(this.message3)
		}
	}
</script>

<style>
</style>
複製程式碼

parent.vue

<template>
	<div>
		<div>我是父元件</div>
		<div>大聲告訴我你愛誰:{{loveWho}}</div>
		<children @emitToParent='parentSayLove' message1='我是直接引數' v-bind:message2='msg' :message3='obj'></children>
	</div>
</template>

<script>
	import Children from './children'
	export default{
		components:{
			Children
		},
		data(){
			return{
				msg:'我是父元件的引數',
				loveWho:''
			}
		},
		methods:{
			parentSayLove(data){
				this.loveWho = data
			}
		},
		created(){
			this.obj = {a:'1',b:'2',c:'3'}
		}
	}
</script>

<style>
</style>複製程式碼

點選按鈕瀏覽器顯示:

Vue傳參一籮筐

3.3 小結

  • props可以是字串陣列,也可以是物件(可以型別驗證、設定預設值等) ;
  • 使用.native修飾監聽事件,開發中使用了element-ui 的框架標籤時候,使用事件繫結無效。這時候需要使用.native 修飾v-on:event ,可以在框架標籤或元件的根元素 上監聽一個原生事件,例如 <my-component v-on:click.native="doTheThing"></my-component>

四丶非父子(兄弟)元件之間傳值

非父子元件之間傳值,需要定義公共例項檔案bus.js,作為中間倉庫來傳值,不然路由元件之間達不到傳值的效果。在components目錄下新建first.vuesecond.vue以及公共檔案bus.js

bus.js

import Vue from 'vue'
export default new Vue()複製程式碼

first.vuesecond.vue中分別引入bus.js。

	import Bus from '../bus.js'複製程式碼

模擬情景:first.vuesecond.vue傳值。在first.vue通過在事件中新增Bus.$emit( event, […args] )進行傳值,在second.vue中通過Bus.$on(event,callBack)進行監聽。

first.vue

<template>
	<div>
		<div>我是first.vue</div>
		<button @click="firstToSecond">點選傳值給second.vue</button>
	</div>
</template>

<script>
	import Bus from '../bus.js'
	export default{
		data(){
			return{
				msg:'我是first.vue傳到second.vue的引數'
			}
		},
		methods:{
			firstToSecond(){
				Bus.$emit('emitToSecond',this.msg)
			}
		}
	}
</script>

<style>
</style>複製程式碼

second.vue

<template>
	<div>
		<div>我是second.vue</div>
		{{info}}
	</div>
</template>

<script>
	import Bus from '../bus.js'
	export default{
		data(){
			return{
				info:''
			}
		},
		mounted(){
			const that = this;
			Bus.$on('emitToSecond',function(data){
				that.info = data
			})
		}
	}
</script>

<style>
</style>複製程式碼

點選按鈕,瀏覽器中顯示:

Vue傳參一籮筐

小結

兄弟元件之間與父子元件之間的資料互動,兩者相比較,兄弟元件之間的通訊其實和子元件向父元件傳值有些類似,他們的通訊原理都是相同的,例如子向父傳值也是$emit$on的形式,只是沒有Bus,但若我們仔細想想,此時父元件其實就充當了Bus這個事件匯流排的角色。

五丶使用Vuex

何為Vuex,看一下官網的解釋:

Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式儲存管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。

Vue傳參一籮筐

什麼情況下使用Vuex?

Vuex 可以幫助我們管理共享狀態,並附帶了更多的概念和框架。這需要對短期和長期效益進行權衡。

如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣冗餘的。確實是如此——如果您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 store 模式 就足夠您所需了。但是,如果您需要構建一箇中大型單頁應用,您很可能會考慮如何更好地在元件外部管理狀態,Vuex 將會成為自然而然的選擇。

在components目錄下新建vuexA.vuevuexB.vue,模擬場景:vuexA.vuevuexB.vue傳值。

首先我們安裝vuex,npm install vuex --save,在src目錄下建立vuex目錄,然後在vuex目錄下新建index.jsstate.jsgetters.jsactions.jsmutations.js

Vue傳參一籮筐

vuex/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import state from './state.js'
import mutations from './mutations.js'
import getters from './getters.js'
import actions from './actions.js'
Vue.use(Vuex)

export default new Vuex.Store({
	state,
	getters,
	mutations,
	actions
})複製程式碼

在main.js中引入vuex/index.js並注入到Vue中:

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './vuex'
Vue.config.productionTip = false

new Vue({
	store,
	router,
  render: h => h(App),
}).$mount('#app')
複製程式碼

state.js

export default{
	city:'nanjing'
}複製程式碼

vuexA.vue

<template>	
        <div>
		<div>我是vuexA中city引數:{{city}}</div>
		<input type="text" :value="city" @change="change">
	</div>
</template>

<script>
	export default{
		methods:{
			change(e){
				this.$store.dispatch('setCityName',e.target.value)
			}
		},
		computed:{
			city(){
				return this.$store.getters.getCity
			}
		}
	}
</script>

<style>
</style>複製程式碼

vuexB.vue

<template>
	<div>
		<div>我是vuexB中的city引數:{{city}}</div>
	</div>
</template>

<script>
	export default{
		data(){
			return{
				
			}
		},
		computed:{
			city(){
				return this.$store.state.city
			}
		}
	}
</script>

<style>
</style>
複製程式碼

actions.js

export default{
	setCityName({commit,state},name){
		commit('setCity',name)
	}
}複製程式碼

mutations.js

export default{
	setCity(state,name){
		state.city = name//設定新的值
	}
}複製程式碼

getter.js

export default{
	getCity(state){
		return state.city//返回目前城市名稱
	}
}複製程式碼

在瀏覽器中開啟:

Vue傳參一籮筐

修改input中的值:

Vue傳參一籮筐

顯而易見,當vuexA頁面中input值改變時,可同時改變vuexB頁面中的值,即將city引數從vuexA頁面傳到了vuexB頁面,從而實現用vuex在元件中傳值。

vuex更多詳細功能請參考Vuex中文官方文件


全部例項程式碼已上傳至我的GitHub,歡迎訪問Fork。

六丶參考文件

  1. VUE中父子元件傳參
  2. vue通訊、傳值的多種方式
  3. vuex實現兄弟元件之間傳值


相關文章