前言
在vue項目中,不可避免的會在不同組件之間進(jìn)行傳值 ,不同需求下有各式各樣的傳值方式。就比如說,兄弟組件傳值,父子子父之間傳值,路由傳值,ref方式傳值或者是共享狀態(tài)(數(shù)據(jù))等,一些花里胡哨的方式,都有各自使用場景且有可能不經(jīng)常使用導(dǎo)致容易忘記,故總結(jié)記之,方便自己以后更好運(yùn)用自如。
目錄
[TOC]
使用props傳值
- 簡單的示例
父組件:
<template lang="html">
<div class="">
<h1>首頁</h1>
<home1 :msg='str'></home1>
</div>
</template>
<script>
import home1 from './home1'
export default {
data(){
return {
str:'我是在父組件的數(shù)據(jù)通過props傳遞給子組件'
}
},
components: {
home1
}
}
</script>
<style>
</style>
子組件:
<template>
<div id="">
<h2>{{msg}}</h2>
</div>
</template>
<script>
export default {
props: ['msg'],
name: "",
data: () => ({
})
}
</script>
<style scoped>
</style>
小結(jié):通過以上代碼,就可以明顯看出,在子組件vue實例聲明props屬性以及在父元素中子組件進(jìn)行賦值操作,即可實現(xiàn)父子組件傳值。值得注意的是,也可通過在子組件中定義一個函數(shù),在父組件觸發(fā)這個函數(shù),也可達(dá)到父傳子的效果。詳情下料聊
- props實現(xiàn)子組件向父組件傳值,其原理實現(xiàn)如上小結(jié),實現(xiàn)時值得注意的是:
- 在父組件中,傳值的是函數(shù)名,而不是函數(shù)的執(zhí)行結(jié)果
- 在子組件中觸發(fā)函數(shù)時機(jī)時:通過this.函數(shù)名取得父傳子的函數(shù),并傳參(即是子向父傳遞的數(shù)據(jù))執(zhí)行。這樣父可以拿到子的數(shù)據(jù)。
父組件代碼如下:
<template lang="html">
<div class="">
<h1>首頁</h1>
<home1 :fn='parent'></home1>
<!-- 來展示從子組件傳來的值 -->
<h2>{{ num }}</h2>
</div>
</template>
<script>
import home1 from './home1'
export default {
data(){
return {
// 來保存從子組件傳來的值
num:''
}
},
components: {
home1
},
methods: {
parent(data) {
// 如果子組件觸發(fā)函數(shù)會調(diào)轉(zhuǎn)到父組件來執(zhí)行該函數(shù),即把傳遞進(jìn)來的參數(shù)賦值給vue實例中的data數(shù)據(jù)中的num變量中
this.num = data;
}
}
}
</script>
<style media="screen">
</style>
子組件代碼如下:
<template>
<div id="">
<h2>hello</h2>
</div>
</template>
<script>
export default {
props: ['fn'],
name: "",
data: () => ({
str:'我是子組件里面的數(shù)據(jù)要通過props傳遞給父組件'
}),
mounted() {
//do something after mounting vue instance
// 在子組件渲染完畢時,觸發(fā)從父組件傳遞過來的函數(shù)
this.fn(this.str)
}
}
</script>
<style scoped>
</style>
使用路由傳值
路由傳值:主要分為在同一路由下傳值(同一組件)和不同路由跳轉(zhuǎn)傳值(不同組件),其中重要知識點有:
- 路由傳參有兩種情況:編程式傳參和聲明式傳參,格式用法見下代碼實例
- 通過this.$route.params.? 來接收路由參數(shù)(這一般存放小數(shù)據(jù)),而this.$route.query.?來接收存放在路由的數(shù)據(jù),一般是存放大數(shù)據(jù)
- 當(dāng)然如果是同一路由下傳參,要配置路由如格式:
{name:'home',path:'/home/:id',component:Home},...
- 同一路由下傳值實現(xiàn)代碼如下:
<template lang="html">
<div class="">
<h1>首頁</h1>
<!-- 點擊路由鏈接向當(dāng)前路由傳遞參數(shù) -->
<!-- 1.聲明式傳參 -->
<router-link :to="{ name: 'home', params: { id: 'hello'}}">1</router-link>
<!-- 2.編程式參參 -->
<p @click='fn1'>2</p>
<!-- 點擊按鈕獲取當(dāng)前url路徑的參數(shù) -->
<button @click="fn" type="button" name="button">獲取動態(tài)路由參數(shù)</button>
<h4>我是動態(tài)數(shù)據(jù):{{num}}</h4>
<!-- 通過query中值獲得數(shù)據(jù) -->
<h5>{{num1.name}}</h5>
<h5>{{num1.age}}</h5>
</div>
</template>
<script>
// import home1 from './home1'
export default {
data(){
return {
num:'',
// 在路由的query對象存放大量數(shù)據(jù)方便存取
num1:''
}
},
methods: {
// 點擊按鈕獲取當(dāng)前url路徑的參數(shù)的函數(shù)
fn() {
this.num = this.$route.params.id;
this.num1 = this.$route.query;
},
// 點擊’2‘后,進(jìn)行編程式路由跳轉(zhuǎn)并傳遞參數(shù)
fn1() {
this.$router.push(
{name:'home',params:{id:'world'},query:{
name:'zhangsna',
age:23
}}
)
}
},
components: {
// home1
}
}
</script>
<style media="screen">
</style>
- 不同路由下實現(xiàn)傳值:
跳轉(zhuǎn)前路由組件代碼如下:
<template lang="html">
<div class="">
<h1 @click='fn'>首頁</h1>
</div>
</template>
<script>
export default {
data(){
return {
num:''
}
},
methods: {
fn(){
this.$router.push({
name:'car',
query:{
name:'xioahang',
age:23
}
})
}
}
}
</script>
<style media="screen">
</style>
調(diào)轉(zhuǎn)后路由組件代碼如下
<template lang="html">
<div class="car">
<h1>我的購物車</h1>
<h2>{{ msg.name }}</h2>
<h2>{{ msg.age }}</h2>
</div>
</template>
<script>
export default {
data() {
return {
msg:{}
}
},
created() {
//do something after creating vue instance
this.msg = this.$route.query
}
}
</script>
<style media="screen">
</style>
使用ref方式傳值
盡管有props和events,但是仍然需要在JavaScript中直接訪問子組件。為此可以使用ref為子組件指定一個索引ID。
值得注意的是:ref的屬性所對應(yīng)的屬性值是一個固定值,不是一個變量。因為ref不是動態(tài)更新的
用法非常簡單,示例如下:
父組件:
<template lang="html">
<div class="">
<h1>首頁</h1>
<!-- 在子組件書寫ref屬性以及值 -->
<home1 ref='mark'></home1>
<!-- 在父組件中,測試從子組件拿到的值 -->
<h2>通過ref來拿到子組件的數(shù)據(jù)傳遞給 {{num}}</h2>
</div>
</template>
<script>
// 導(dǎo)入子組件
import home1 from './home1'
export default {
data(){
return {
num:''
}
},
methods: {
},
components: {
home1
},
mounted() {
// 向子組件拿到的數(shù)據(jù)賦值給父vue實例中的變量
this.num = this.$refs.mark.str;
// 在父組件中,測試從子組件拿到的函數(shù)
this.$refs.mark.fn();
}
}
</script>
<style media="screen">
</style>
子組件:
<template>
<div id="">
<h2>hello</h2>
</div>
</template>
<script>
export default {
name: "",
data: () => ({
str:'我是子組件里面的數(shù)據(jù),父組件通過ref來向子組件拿值'
}),
methods: {
fn() {
console.log('我是子組件的方法,父組件可通過ref來拿到我這里的值!');
}
}
}
</script>
<style scoped>
</style>
使用BUS傳值
BUS傳值主要運(yùn)用了events事件的原理。實現(xiàn)步驟如下:首先,在定義一個第三方的vue實例并導(dǎo)出,然后通過BUS.$on()來注冊事件,其中里面的函數(shù)中this的指向格外注意,普通函數(shù)this指向BUS,而不是當(dāng)前的vue實例,可使用es6的箭頭函數(shù),它的this指向當(dāng)前的vue實例。最后在傳值的那個組件,使用BUS.$emit()觸發(fā)事件并傳值,即可實現(xiàn)兩個組件之間的傳值。一般用于兄弟組件之間傳值及父子子父之間傳值等
以下實例通過BUS實現(xiàn)父子傳值:
import Vue from 'vue'
export default new Vue()
<template lang="html">
<div class="">
<h1>首頁</h1>
<home1></home1>
<h1>我是通過bus事件傳遞過來的值為:{{num}}</h1>
</div>
</template>
<script>
// 導(dǎo)入Busvue實例
import Bus from '../bus'
import home1 from './home1'
export default {
data(){
return {
num:''
}
},
methods: {
},
components: {
home1
},
created() {
Bus.$on('sendVal',(data) => {
this.num = data
});
}
}
</script>
<style media="screen">
</style>
<template>
<div id="">
<h2>hello</h2>
</div>
</template>
<script>
import Bus from '../bus'
export default {
name: "",
data: () => ({
str:'我是這個子組件中的數(shù)據(jù)'
}),
methods: {
fn() {
}
},
created() {
//do something after creating vue instance
Bus.$emit('sendVal',this.str)
}
}
</script>
<style scoped>
</style>
通過$parent,$children方法來拿值
通過$parent,$children方法調(diào)取層級關(guān)系的組件內(nèi)的數(shù)據(jù)和方法,該方法的弊端,就是增強(qiáng)組件之間的耦合,不利于組件的復(fù)用
使用$parent,$children來進(jìn)行父子子父之間傳值
父組件代碼:
<template lang="html">
<div class="">
<h1>首頁</h1>
<home1></home1>
<p>{{num1}}</p>
</div>
</template>
<script>
import home1 from './home1'
export default {
data(){
return {
num:'我是父組件的數(shù)據(jù)',
num1:''
}
},
methods: {
parentFn(){
console.log('我是父組件的方法');
}
},
components: {
home1
},
mounted() {
// console.log(this.$children);
// 值得注意的是 this.$children 獲取到是一個數(shù)組,并非是一個對象
this.num1 = this.$children[0].$data.str // 獲取子組件的數(shù)據(jù)
this.$children[0].sonFn() // 獲取子組件的方法
}
}
</script>
<style media="screen">
</style>
子組件代碼:
<template>
<div id="">
<h2>hello</h2>
<h4>{{str1}}</h4>
</div>
</template>
<script>
export default {
name: "",
data: () => ({
str:'我是這個子組件中的數(shù)據(jù)',
str1:''
}),
methods: {
sonFn() {
console.log('我是子組件的方法');
}
},
created() {
//do something after creating vue instance
// 獲取父組件的數(shù)據(jù)
this.str1 = this.$parent.num;
// 獲取父組件的方法
this.$parent.parentFn()
}
}
</script>
<style scoped>
</style>
vue原型傳值
vue原型同js對象有著的原型鏈,故向vue組件中存放值與方法,子組件即可通過原型鏈獲取值與方法
import Vue from 'vue'
Vue.prototype.num = 'test prototype'
Vue .prototype.sayFn = function () { console.log('hello world!'); }
使用localStorage或sessionStorage存儲
localStorage、sessionStorage以及cookie存儲,都是js實現(xiàn)本地存儲的方式 。實現(xiàn)方法如下:
保存數(shù)據(jù):
- sessionStorage.setItem(key,value)
- localStorage.setItem(key,value)
讀取數(shù)據(jù):- var v = sessionStorage.getItem(key)
- var v = localStorage.getItem(key)
移除數(shù)據(jù):- sessionStorage.removeItem(key)
- localStorage.removeItem(key)
清除數(shù)據(jù):- sessionStorage.clear()
- localStorage.clear()
利用vue-x方式進(jìn)行傳值
vue-x是vue的共享狀態(tài)(即數(shù)據(jù))的模塊,官網(wǎng)介紹為:Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。
- 一個表示“單向數(shù)據(jù)流”理念的極簡示意:
image
當(dāng)我們的應(yīng)用遇到多個組件共享狀態(tài)時,單向數(shù)據(jù)流的簡潔性很容易被破壞,故使用vuex如下圖所示:
2.其中核心概念有:
* state:存放狀態(tài),即數(shù)據(jù)
* mutations:存放改變state數(shù)據(jù)的同步方法
* actions:存放改變state數(shù)據(jù)的異步方法
* getters:相當(dāng)于計算屬性,避免了直接向state數(shù)據(jù)取值
- 代碼具體實現(xiàn)如下:
首先創(chuàng)建store實例
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state:{
// 共享狀態(tài)
num:0
},
mutations:{
addNum(state,step){
state.num += step;
},
reduceNum(state,step){
state.num -= step;
}
},
actions:{
},
getters:{
getNum(state){
return state.num
}
}
})
在任意組件中,取共享狀態(tài)中數(shù)據(jù)
<template lang="html">
<div class="">
<h1>首頁</h1>
<p>{{getNum}}</p>
<button @click='fn' type="button" name="button">點我增加共享數(shù)據(jù)</button>
<button @click='fn1' type="button" name="button">點我減少共享數(shù)據(jù)</button>
</div>
</template>
<script>
export default {
data(){
return {
num:''
}
},
methods: {
fn(){
this.$store.commit('addNum',1)
},
fn1(){
this.$store.commit('reduceNum',1)
}
},
components: {
},
computed:{
getNum(){
return this.$store.state.num;
}
},
created() {
//do something after creating vue instance
}
}
</script>
<style media="screen">
</style>
生活寄語
愛代碼,愛生活!