傳值方法:1、利用props實(shí)現(xiàn)父?jìng)髯樱?、子傳父,需要自定義事件,在子組件中用“this.$emit(‘事件名’)”觸發(fā),而父中用“@事件名”監(jiān)聽(tīng);3、兄弟間,通過(guò)公有父元素作為橋接,結(jié)合父子props傳參、子父自定義事件;4、用路由傳值;5、用$ref傳值;6、用依賴(lài)注入傳給后代子孫曾孫;7、利用$attrs;8、借助$listeners中間事件;9、用$parent傳等。
本教程操作環(huán)境:windows7系統(tǒng)、vue3版,DELL G3電腦。
本篇文章帶大家聊聊vue組件傳值的10種方式,常用的也有五六種,先上一張總結(jié)圖:
1、父組件傳給子組件
在子組件里定義一個(gè)props,即props:[‘msg’],msg可以是對(duì)象也可以是基本數(shù)據(jù)類(lèi)型
如果你想定義一個(gè)默認(rèn)值,即 props:{msg: {type: String, default: ‘hello world’}},
若默認(rèn)值是對(duì)象類(lèi)型:props: { msg: { type: Object, default: () => { return { name: ‘dan_seek’ } } }}
需要注意的是這種傳值是單向的,你無(wú)法改變父組件的值(當(dāng)然引用類(lèi)型例外);而且如果直接修改props的值會(huì)報(bào)一個(gè)警告。
推薦的寫(xiě)法是在data()里重新定義一個(gè)變量(見(jiàn)Children.vue),并把props賦值給它,當(dāng)然計(jì)算屬性也行。
Children.vue
<template> <section> 父組件傳過(guò)來(lái)的消息是:{{myMsg}} </section> </template> <script> export default { name: "Children", components: {}, props:['msg'], data() { return { myMsg:this.msg } }, methods: {} } </script>
Parent.vue
<template> <div class="parent"> <Children :msg="message"></Children> </div> </template> <script> import Children from '../components/Children' export default { name: 'Parent', components: { Children }, data() { return { message:'hello world' } }, } </script>
2、子組件傳給父組件
這里需要使用自定義事件,在子組件中使用this.$emit(‘myEvent’) 觸發(fā),然后在父組件中使用@myEvent監(jiān)聽(tīng)
Children.vue
<template> <div class="parent"> 這里是計(jì)數(shù):{{parentNum}} <Children-Com @addNum="getNum"></Children-Com> </div> </template> <script> import ChildrenCom from '../components/Children' export default { name: 'Parent', components: { ChildrenCom }, data() { return { parentNum: 0 } }, methods:{ // childNum是由子組件傳入的 getNum(childNum){ this.parentNum = childNum } } } </script>
Parent.vue
<template> <div class="parent"> 這里是計(jì)數(shù):{{parentNum}} <Children-Com @addNum="getNum"></Children-Com> </div></template><script> import ChildrenCom from '../components/Children' export default { name: 'Parent', components: { ChildrenCom }, data() { return { parentNum: 0 } }, methods:{ // childNum是由子組件傳入的 getNum(childNum){ this.parentNum = childNum } } }</script>
3、兄弟組件間傳值
運(yùn)用自定義事件emit的觸發(fā)和監(jiān)聽(tīng)能力,定義一個(gè)公共的事件總線eventBus,通過(guò)它作為中間橋梁,我們就可以傳值給任意組件了。而且通過(guò)eventBus的使用,可以加深emit的理解。
EventBus.js
import Vue from 'vue' export default new Vue()
Children1.vue
<template> <section> <div @click="pushMsg">push message</div> <br> </section> </template> <script> import eventBus from './EventBus' export default { name: "Children1", components: {}, data() { return { childNum:0 } }, methods: { pushMsg(){ // 通過(guò)事件總線發(fā)送消息 eventBus.$emit('pushMsg',this.childNum++) } } } </script>
Children2.vue
<template> <section> children1傳過(guò)來(lái)的消息:{{msg}} </section> </template> <script> import eventBus from './EventBus' export default { name: "Children2", components: {}, data() { return { msg: '' } }, mounted() { // 通過(guò)事件總線監(jiān)聽(tīng)消息 eventBus.$on('pushMsg', (children1Msg) => { this.msg = children1Msg }) } } </script>
Parent.vue
<template> <div class="parent"> <Children1></Children1> <Children2></Children2> </div> </template> <script> import Children1 from '../components/Children1' import Children2 from '../components/Children2' export default { name: 'Parent', components: { Children1, Children2 }, data() { return { } }, methods:{ } } </script>
github上還有一個(gè)開(kāi)源vue-bus庫(kù),可以參考下: https://github.com/yangmingshan/vue-bus#readme
4、路由間傳值
A頁(yè)面跳轉(zhuǎn)B頁(yè)面時(shí)使用 this.$router.push(‘/B?name=danseek’)
B頁(yè)面可以使用 this.$route.query.name 來(lái)獲取A頁(yè)面?zhèn)鬟^(guò)來(lái)的值
上面要注意router和route的區(qū)別
配置如下路由:
{ path: '/b/:name', name: 'b', component: () => import( '../views/B.vue') },
在B頁(yè)面可以通過(guò) this.$route.params.name 來(lái)獲取路由傳入的name的值
由于router-view本身也是一個(gè)組件,所以我們也可以使用父子組件傳值方式傳值,然后在對(duì)應(yīng)的子頁(yè)面里加上props,因?yàn)閠ype更新后沒(méi)有刷新路由,所以不能直接在子頁(yè)面的mounted鉤子里直接獲取最新type的值,而要使用watch。
<router-view :type="type"></router-view>
// 子頁(yè)面 ...... props: ['type'] ...... watch: { type(){ // console.log("在這個(gè)方法可以時(shí)刻獲取最新的數(shù)據(jù):type=",this.type) }, },
5、使用$ref傳值
通過(guò)$ref的能力,給子組件定義一個(gè)ID,父組件通過(guò)這個(gè)ID可以直接訪問(wèn)子組件里面的方法和屬性
首先定義一個(gè)子組件Children.vue
<template> <section> 傳過(guò)來(lái)的消息:{{msg}} </section> </template> <script> export default { name: "Children", components: {}, data() { return { msg: '', desc:'The use of ref' } }, methods:{ // 父組件可以調(diào)用這個(gè)方法傳入msg updateMsg(msg){ this.msg = msg } }, } </script>
然后在父組件Parent.vue中引用Children.vue,并定義ref屬性
<template> <div class="parent"> <!-- 給子組件設(shè)置一個(gè)ID ref="children" --> <Children ref="children"></Children> <div @click="pushMsg">push message</div> </div> </template> <script> import Children from '../components/Children' export default { name: 'parent', components: { Children, }, methods:{ pushMsg(){ // 通過(guò)這個(gè)ID可以訪問(wèn)子組件的方法 this.$refs.children.updateMsg('Have you received the clothes?') // 也可以訪問(wèn)子組件的屬性 console.log('children props:',this.$refs.children.desc) } }, } </script>
6、使用依賴(lài)注入傳給后代子孫曾孫
假設(shè)父組件有一個(gè)方法 getName(),需要把它提供給所有的后代
provide: function () { return { getName: this.getName() } }
provide 選項(xiàng)允許我們指定我們想要提供給后代組件的數(shù)據(jù)/方法
然后在任何后代組件里,我們都可以使用 inject
來(lái)給當(dāng)前實(shí)例注入父組件的數(shù)據(jù)/方法:
inject: ['getName']
Parent.vue
<template> <div class="parent"> <Children></Children> </div> </template> <script> import Children from '../components/Children' export default { name: 'Parent', components: { Children, }, data() { return { name:'dan_seek' } }, provide: function () { return { getName: this.name } }, } </script>
Children.vue
<template> <section> 父組件傳入的值:{{getName}} </section> </template> <script> export default { name: "Children", components: {}, data() { return { } }, inject: ['getName'], } </script>
7、祖?zhèn)鲗O $attrs
正常情況下需要借助父親的props作為中間過(guò)渡,但是這樣在父親組件就會(huì)多了一些跟父組件業(yè)務(wù)無(wú)關(guān)的屬性,耦合度高,借助$attrs可以簡(jiǎn)化些,而且祖跟孫都無(wú)需做修改
GrandParent.vue
<template> <section> <parent name="grandParent" sex="男" age="88" hobby="code" @sayKnow="sayKnow"></parent> </section> </template> <script> import Parent from './Parent' export default { name: "GrandParent", components: { Parent }, data() { return {} }, methods: { sayKnow(val){ console.log(val) } }, mounted() { } } </script>
Parent.vue
<template> <section> <p>父組件收到</p> <p>祖父的名字:{{name}}</p> <children v-bind="$attrs" v-on="$listeners"></children> </section> </template> <script> import Children from './Children' export default { name: "Parent", components: { Children }, // 父組件接收了name,所以name值是不會(huì)傳到子組件的 props:['name'], data() { return {} }, methods: {}, mounted() { } } </script>
Children.vue
<template> <section> <p>子組件收到</p> <p>祖父的名字:{{name}}</p> <p>祖父的性別:{{sex}}</p> <p>祖父的年齡:{{age}}</p> <p>祖父的愛(ài)好:{{hobby}}</p> <button @click="sayKnow">我知道啦</button> </section> </template> <script> export default { name: "Children", components: {}, // 由于父組件已經(jīng)接收了name屬性,所以name不會(huì)傳到子組件了 props:['sex','age','hobby','name'], data() { return {} }, methods: { sayKnow(){ this.$emit('sayKnow','我知道啦') } }, mounted() { } } </script>
顯示結(jié)果
父組件收到 祖父的名字:grandParent 子組件收到 祖父的名字: 祖父的性別:男 祖父的年齡:88 祖父的愛(ài)好:code
8、孫傳祖
借助$listeners中間事件,孫可以方便的通知祖,代碼示例見(jiàn)7
9、$parent
通過(guò)parent可以獲父組件實(shí)例,然后通過(guò)這個(gè)實(shí)例就可以訪問(wèn)父組件的屬性和方法,它還有一個(gè)兄弟root,可以獲取根組件實(shí)例。
語(yǔ)法:
// 獲父組件的數(shù)據(jù) this.$parent.foo // 寫(xiě)入父組件的數(shù)據(jù) this.$parent.foo = 2 // 訪問(wèn)父組件的計(jì)算屬性 this.$parent.bar // 調(diào)用父組件的方法 this.$parent.baz()
于是,在子組件傳給父組件例子中,可以使用this.$parent.getNum(100)傳值給父組件。
10、sessionStorage傳值
sessionStorage 是瀏覽器的全局對(duì)象,存在它里面的數(shù)據(jù)會(huì)在頁(yè)面關(guān)閉時(shí)清除 。運(yùn)用這個(gè)特性,我們可以在所有頁(yè)面共享一份數(shù)據(jù)。
語(yǔ)法:
// 保存數(shù)據(jù)到 sessionStorage sessionStorage.setItem('key', 'value'); // 從 sessionStorage 獲取數(shù)據(jù) let data = sessionStorage.getItem('key'); // 從 sessionStorage 刪除保存的數(shù)據(jù) sessionStorage.removeItem('key'); // 從 sessionStorage 刪除所有保存的數(shù)據(jù) sessionStorage.clear();
注意:里面存的是鍵值對(duì),只能是字符串類(lèi)型,如果要存對(duì)象的話(huà),需要使用 let objStr = JSON.stringify(obj) 轉(zhuǎn)成字符串然后再存儲(chǔ)(使用的時(shí)候 let obj = JSON.parse(objStr) 解析為對(duì)象)。
這樣存對(duì)象是不是很麻煩呢,推薦一個(gè)庫(kù) good-storage ,它封裝了sessionStorage ,可以直接用它的API存對(duì)象
// localStorage storage.set(key,val) storage.get(key, def) // sessionStorage storage.session.set(key, val) storage.session.get(key, val)