不寫這篇文章,我自己都不知道我知道的vue元件傳值的方式竟然有11種之多,其實靜下來想想,常用的也有五六種,先上一張總結圖:
1、父元件傳給子元件
在子元件裡定義一個props,即props:[‘msg’],msg可以是對象也可以是基本資料類型
如果你想定義一個預設值,即 props:{msg: {type: String, default: ‘hello world’}},
需要注意的是這種傳值是單向的,你無法改變父元件的值(當然引用類型例外);而且如果直接修改props的值會報一個警告。
推薦的寫法是在data()裡重新定義一個變量(見Children.vue),并把props指派給它,當然計算屬性也行。
Children.vue
<template>
<section>
父元件傳過來的消息是:{{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’) 觸發,然後在父元件中使用@myEvent監聽
Children.vue
<template>
<section>
<br>
<div @click="clickme">click me</div>
</section>
</template>
<script>
export default {
name: "Children",
components: {},
data() {
return {
childNum:0
}
},
methods: {
clickme(){
// 通過自定義事件addNum把值傳給父元件
this.$emit('addNum',this.childNum++)
}
}
}
</script>
Parent.vue
<template>
<div class="parent">
這裡是計數:{{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、兄弟元件間傳值
運用自定義事件 e m i t 的 觸 發 和 監 聽 能 力 , 定 義 一 個 公 共 的 事 件 總 線 e v e n t B u s , 通 過 它 作 為 中 間 橋 梁 , 我 們 就 可 以 傳 值 給 任 意 組 件 了 。 而 且 通 過 e v e n t B u s 的 使 用 , 可 以 加 深 emit的觸發和監聽能力,定義一個公共的事件總線eventBus,通過它作為中間橋梁,我們就可以傳值給任意元件了。而且通過eventBus的使用,可以加深 emit的觸發和監聽能力,定義一個公共的事件總線eventBus,通過它作為中間橋梁,我們就可以傳值給任意元件了。而且通過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(){
// 通過事件總線發送消息
eventBus.$emit('pushMsg',this.childNum++)
}
}
}
</script>
Children2.vue
<template>
<section>
children1傳過來的消息:{{msg}}
</section>
</template>
<script>
import eventBus from './EventBus'
export default {
name: "Children2",
components: {},
data() {
return {
msg: ''
}
},
mounted() {
// 通過事件總線監聽消息
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上還有一個開源vue-bus庫,可以參考下: https://github.com/yangmingshan/vue-bus#readme
4、路由間傳值
i.使用問号傳值
A頁面跳轉B頁面時使用 this.$router.push(’/B?name=danseek’)
B頁面可以使用 this.$route.query.name 來擷取A頁面傳過來的值
上面要注意router和route的差別
ii.使用冒号傳值
配置如下路由:
{
path: '/b/:name',
name: 'b',
component: () => import( '../views/B.vue')
},
在B頁面可以通過 this.$route.params.name 來擷取路由傳入的name的值
iii.使用父子元件傳值
由于router-view本身也是一個元件,是以我們也可以使用父子元件傳值方式傳值,然後在對應的子頁面裡加上props,因為type更新後沒有重新整理路由,是以不能直接在子頁面的mounted鈎子裡直接擷取最新type的值,而要使用watch。
// 子頁面
......
props: ['type']
......
watch: {
type(){
// console.log("在這個方法可以時刻擷取最新的資料:type=",this.type)
},
},
5、使用$ref傳值
通過$ref的能力,給子元件定義一個ID,父元件通過這個ID可以直接通路子元件裡面的方法和屬性
首先定義一個子元件Children.vue
<template>
<section>
傳過來的消息:{{msg}}
</section>
</template>
<script>
export default {
name: "Children",
components: {},
data() {
return {
msg: '',
desc:'The use of ref'
}
},
methods:{
// 父元件可以調用這個方法傳入msg
updateMsg(msg){
this.msg = msg
}
},
}
</script>
然後在父元件Parent.vue中引用Children.vue,并定義ref屬性
<template>
<div class="parent">
<!-- 給子元件設定一個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(){
// 通過這個ID可以通路子元件的方法
this.$refs.children.updateMsg('Have you received the clothes?')
// 也可以通路子元件的屬性
console.log('children props:',this.$refs.children.desc)
}
},
}
</script>
6、使用依賴注入傳給後代子孫曾孫
假設父元件有一個方法 getName(),需要把它提供給所有的後代
provide: function () {
return {
getName: this.getName()
}
}
provide 選項允許我們指定我們想要提供給後代元件的資料/方法
然後在任何後代元件裡,我們都可以使用
inject
來給目前執行個體注入父元件的資料/方法:
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、祖傳孫 $attrs
正常情況下需要借助父親的props作為中間過渡,但是這樣在父親元件就會多了一些跟父元件業務無關的屬性,耦合度高,借助$attrs可以簡化些,而且祖跟孫都無需做修改
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值是不會傳到子元件的
props:['name'],
data() {
return {}
},
methods: {},
mounted() {
}
}
</script>
Children.vue
<template>
<section>
<p>子元件收到</p>
<p>祖父的名字:{{name}}</p>
<p>祖父的性别:{{sex}}</p>
<p>祖父的年齡:{{age}}</p>
<p>祖父的愛好:{{hobby}}</p>
<button @click="sayKnow">我知道啦</button>
</section>
</template>
<script>
export default {
name: "Children",
components: {},
// 由于父元件已經接收了name屬性,是以name不會傳到子元件了
props:['sex','age','hobby','name'],
data() {
return {}
},
methods: {
sayKnow(){
this.$emit('sayKnow','我知道啦')
}
},
mounted() {
}
}
</script>
顯示結果
父元件收到
祖父的名字:grandParent
子元件收到
祖父的名字:
祖父的性别:男
祖父的年齡:88
祖父的愛好:code
8、孫傳祖
借助$listeners中間事件,孫可以友善的通知祖,代碼示例見7
9、$parent
通過 p a r e n t 可 以 獲 父 組 件 實 例 , 然 後 通 過 這 個 實 例 就 可 以 訪 問 父 組 件 的 屬 性 和 方 法 , 它 還 有 一 個 兄 弟 parent可以獲父元件執行個體,然後通過這個執行個體就可以通路父元件的屬性和方法,它還有一個兄弟 parent可以獲父元件執行個體,然後通過這個執行個體就可以通路父元件的屬性和方法,它還有一個兄弟root,可以擷取根元件執行個體。
文法:
// 獲父元件的資料
this.$parent.foo
// 寫入父元件的資料
this.$parent.foo = 2
// 通路父元件的計算屬性
this.$parent.bar
// 調用父元件的方法
this.$parent.baz()
于是,在子元件傳給父元件例子中,可以使用this.$parent.getNum(100)傳值給父元件。
10、sessionStorage傳值
sessionStorage 是浏覽器的全局對象,存在它裡面的資料會在頁面關閉時清除 。運用這個特性,我們可以在所有頁面共享一份資料。
文法:
// 儲存資料到 sessionStorage
sessionStorage.setItem('key', 'value');
// 從 sessionStorage 擷取資料
let data = sessionStorage.getItem('key');
// 從 sessionStorage 删除儲存的資料
sessionStorage.removeItem('key');
// 從 sessionStorage 删除所有儲存的資料
sessionStorage.clear();
注意:裡面存的是鍵值對,隻能是字元串類型,如果要存對象的話,需要使用 let objStr = JSON.stringify(obj) 轉成字元串然後再存儲(使用的時候 let obj = JSON.parse(objStr) 解析為對象)。
這樣存對象是不是很麻煩呢,推薦一個庫 good-storage ,它封裝了sessionStorage ,可以直接用它的API存對象
// localStorage
storage.set(key,val)
storage.get(key, def)
// sessionStorage
storage.session.set(key, val)
storage.session.get(key, val)
更多請移步:https://github.com/ustbhuangyi/storage#readme
11、vuex
這裡我也不打算介紹這個大名鼎鼎的vuex怎麼用,因為要把它寫清楚篇幅太長了…
如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣備援的。确實是如此——如果您的應用夠簡單,您也許不需要使用 Vuex。