一怎炊、父子組件傳值
-
基本概念
在Vue中混移,父子組件間的數(shù)據(jù)流向可以總結(jié)為prop向下傳遞,事件向上傳遞冻璃,即父組件通過(guò)prop給子組件下發(fā)數(shù)據(jù)响谓,子組件通過(guò)自定義事件給父組件發(fā)送信息。
(1) 父組件給子組件傳值
- 父組件通過(guò)屬性傳值省艳,子組件利用props接收值
// 給子組件傳入一個(gè)靜態(tài)的值:
<child title="哈哈" />
// 傳動(dòng)態(tài)的值,需要v-bind綁定:
<child :title="data" />
// 子組件接收值
export default {
props: {
title: {
type: String,
default: 'hello world'
}
}
}
關(guān)于父組件的傳值類型和props更多的定義詳見(jiàn)官網(wǎng) :vue官網(wǎng)
(2)子組件向父組件傳值
<!-- 父組件 -->
<template>
<div class="test">
<test-com @childFn="parentFn"></test-com>
<br/>
子組件傳來(lái)的值 : {{message}}
</div>
</template>
<script>
export default {
// ...
data: {
message: ''
},
methods: {
parentFn(payload) {
this.message = payload;
}
}
}
</script>
<!-- 子組件 -->
<template>
<div>
<input type="text" v-model="message" />
<button @click="click">Send</button>
</div>
</template>
<script>
export default {
// ...
data() {
return {
message: '子組件數(shù)據(jù)'
}
},
methods: {
click() {
this.$emit('childFn', this.message);
}
}
}
</script>
(3)通過(guò)chlidren等方法調(diào)取用層級(jí)關(guān)系的組件內(nèi)的數(shù)據(jù)和方法娘纷。
// 獲取子組件data中的id
const id = this.$children.$data.id
// 獲取父組件data中的id
const id = this.$parent.$data.id
- 注意:獲取父元素data中的id 這樣用起來(lái)比較靈活,但是容易造成代碼耦合性太強(qiáng)跋炕,導(dǎo)致維護(hù)困難
二赖晶、非父子組件間傳值
有很多時(shí)候根據(jù)業(yè)務(wù)需求要在同級(jí)組件或頁(yè)面間傳值,此處提供以下幾種方法作為參考:
(1)通過(guò)router-link進(jìn)行跳轉(zhuǎn)
<router-link
:to="{
path: '/test',
params: {
key: 'value',
},
query: {
key: 'value',
}
}">
<button type="button">跳轉(zhuǎn)</button>
</router-link>
- path -> 是要跳轉(zhuǎn)的路由路徑
- name ->路由文件里面配置的name,必須一致遏插,這兩者都可以進(jìn)行路由導(dǎo)航
- params -> 是要傳送的參數(shù),參數(shù)可以直接key:value形式傳遞
- query -> 是通過(guò) url 來(lái)傳遞參數(shù)的同樣是key:value形式傳遞
跳轉(zhuǎn)頁(yè)面接受參數(shù):
let value1 = this.$route.query.key
let value2 = this.$route.params.key
(2) this.$router.push()
此方法同樣是有path+query和name+params兩種方式:
- this.$router.push({name:'路由命名',params:{參數(shù)名:參數(shù)值,參數(shù)名:參數(shù)值}})
- this.$router.push({path:'跳轉(zhuǎn)路由',query:{參數(shù)名:參數(shù)值,參數(shù)名:參數(shù)值}})
this.$router.push({
path: 'yourPath',
name: '要跳轉(zhuǎn)的路徑的 name,在 router 文件夾下的 index.js 文件內(nèi)找',
params: {
key: 'key',
value: this.msg
}
/*query: {
key: 'key',
value: this.msg
}*/
})
// 接收參數(shù)
export default{
data () {
return {
msg: '',
// 保存?zhèn)鬟f過(guò)來(lái)的index
index: ''
}
mounted() {
this.msg = this.$route.params.value
// this.index = this.$route.query.key
}
}
總結(jié):使用query捂贿,傳輸?shù)闹禃?huì)在url后面以參數(shù)的形式顯示出來(lái),可以刷新頁(yè)面胳嘲,數(shù)據(jù)不變厂僧,但會(huì)是頁(yè)面路由過(guò)長(zhǎng);而params只要一刷新傳遞的參數(shù)就沒(méi)了了牛。
(3)LocalStorage緩存?zhèn)髦?/p>
//保存userid至內(nèi)存
const userId = 1;
localStorage.setItem('storeId',JSON.stringify(userId));
//取颜屠,注意這里取出的是字符串。
this.userId= JSON.parse(localStorage.userId);
注意:簡(jiǎn)單的小項(xiàng)目可以這么做鹰祸,如果項(xiàng)目很大甫窟,建議直接用vuex。
(4)通過(guò)Vuex進(jìn)行傳值
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import data from './modules/data'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
data
},
state: {},
getters: {},
mutations: {},
actions: {},
strict: process.env.NODE_ENV !== 'production', // 嚴(yán)格模式
})
// store/modules/data.js
const state = {
checkedCars: [],
}
const getters = {}
Object.keys(state).forEach(prop => {
getters[prop] = state => state[prop]
})
const mutations = {
loadCheckedCars: (state, payload) => {
state.checkedCars = [].concat(payload)
},
deleteCheckedCar: (state, payload) => {
const result = state.checkedCars.findIndex(item => {
// eslint-disable-next-line no-unused-expressions
item.id === payload.id
})
if (result > -1) {
state.checkedCars.splice(result, 1)
}
},
}
const actions = {}
export default {
state,
getters,
mutations,
actions,
}
(5)發(fā)布訂閱模式(也叫eventBus或事件總線)
在Vue的原型上定義一個(gè)變量eventBus蛙婴,所有所有Vue的實(shí)例或組件都將共享這個(gè)eventBus蕴坪,可以用eventBus來(lái)發(fā)布自定義事件,然后在組件中用eventBus訂閱自定義事件敬锐。就可以實(shí)現(xiàn)傳值。
<body>
<div id="app">
<child :content="'heqi'"></child>
<child :content="'20'"></child>
</div>
<script type="text/javascript">
Vue.prototype.eventBus= new Vue();
var child = {
props: {
content: String
},
template: '<div @click="handleClick">{{content}}</div>',
methods: {
handleClick: function() {
// 使用 this.eventBus.$emit 發(fā)布廣播
this.eventBus.$emit('change', this.content); // 此處參數(shù)可為字符串呆瞻,對(duì)象
}
},
mounted: function() {
// 使用 this.eventBus.$on 訂閱事件
this.eventBus.$on('change', msg => {
this.content = msg;
});
}
beforeDestroy(){
//組件銷毀前移除監(jiān)聽(tīng)
this.eventBus.$off('change');
}
}
var app = new Vue({
el: '#app',
components: {
child
},
data: {
content: 'Hello World'
}
});
</script>
- 注意:當(dāng)使用
this.eventBus.$emit
台夺、this.eventBus.$on
時(shí),this的值不是指向vue的實(shí)例或組件痴脾,而是指向Vue颤介。可以用常規(guī)操作解決:
mounted: function() {
var that = this;
this.eventBus.$on('change', function(msg) {
that.content = msg;
});
}
beforeDestroy(){
//組件銷毀前移除監(jiān)聽(tīng)
this.eventBus.$off('change');
}
詳細(xì)講解可看鏈接
(6)Vue.observable
- Vue.observable為v2.6.0版本中新增的一個(gè)組件通信方案赞赖,讓一個(gè)對(duì)象可響應(yīng)滚朵。Vue 內(nèi)部會(huì)用它來(lái)處理 data 函數(shù)返回的對(duì)象。返回的對(duì)象可以直接用于渲染函數(shù)methods和計(jì)算屬性computed內(nèi)前域,并且會(huì)在發(fā)生改變時(shí)觸發(fā)相應(yīng)的更新辕近。也可以作為最小化的跨組件狀態(tài)存儲(chǔ)器。
創(chuàng)建store.js文件
import Vue from 'vue'
export const state = Vue.observable({
screenCars: {},
})
export const mutations = {
updateScreenCars (payload) {
state.screenCars = Object.assign({}, payload)
},
}
index.vue組件中觸發(fā):
<template>
<div>
<el-button @click="toSave">保存</el-button>
</div>
</template>
<script>
import {state, mutations} from './store.js'
export default {
name: 'table_form',
computed: {
screenCars() {
return state.screenCars
},
},
methods: {
setTest: mutations.updateScreenCars ,
toSave () {
this.setTest({a:1})
},
},
}
</script>
三匿垄、頁(yè)面緩存問(wèn)題
Vue中如何在切換組件過(guò)程中移宅,將狀態(tài)保存到內(nèi)存中,防止DOM重新渲染椿疗,通俗的講就是實(shí)現(xiàn)如何在一個(gè)頁(yè)面輸入部分?jǐn)?shù)據(jù)后到了另一個(gè)頁(yè)面再返回該頁(yè)面漏峰,數(shù)據(jù)還在。
需求分析:Page1中錄入信息届榄,頁(yè)面跳轉(zhuǎn)帶Page2浅乔,然后再返回Page1,之前Page1錄入的信息還存在铝条。
- keepAlive組件
此處結(jié)合router-view,將整個(gè)路由頁(yè)面緩存靖苇,使用$route.meta
的keepAlive屬性:
在APP.Vue文件中 :
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
routes: [
{
path: '/page2',
name: 'Page2',
component: Hello,
meta: {
keepAlive: false // 不需要緩存
}
},
{
path: '/page1’,
name: 'Page1’,
component: Page1,
meta: {
keepAlive: true // 需要被緩存
}
}
]
現(xiàn)在更改需求為:
首頁(yè)是A頁(yè)面
A頁(yè)面跳轉(zhuǎn)到B席噩,B頁(yè)面不需要緩存
B頁(yè)面跳轉(zhuǎn)到C,C頁(yè)面不需要被緩存
C頁(yè)面返回到B顾复,B頁(yè)面需要緩存
B頁(yè)面返回到A班挖,
A再次跳轉(zhuǎn)到B
(1)此時(shí)思路是在每個(gè)路由的beforeRouteLeave(to, from, next)鉤子中設(shè)置to.meta.keepAlive
beforeRouteLeave講解
// B的路由:
{
path: '/',
name: ‘B',
component: B,
meta: {
keepAlive: true // 需要被緩存
}
}
PageA頁(yè)面:
// 重新加載A頁(yè)面
let isRefresh = sessionStorage.getItem('isRefresh’);
if(isRefresh == '1’){
sessionStorage.setItem('isRefresh',null);
window.location.reload();
} else {
sessionStorage.setItem('isRefresh',1);
}
// 并非刷新頁(yè)面,而是重置頁(yè)面數(shù)據(jù)達(dá)到頁(yè)面刷新效果
beforeRouteEnter:function(to,form,next){
next(vm => {
let calculateReload = sessionStorage.getItem('calculateReload’);
if(calculateReload == 'reload’){
sessionStorage.setItem('calculateReload',null);
vm.clearFinancing();vm.load();
} else {
sessionStorage.setItem('calculateReload','reload');
}
})
},
PageB頁(yè)面:
beforeRouteLeave (to, from, next) {
if (to.name === 'CheckedCars' || to.name === 'CarInfo') {
from.meta.keepAlive = true
next()
} else {
to.meta.keepAlive = false
from.meta.keepAlive = false
this.$destroy()
next()
}
},
methods:{
clearFinancing(){
this.financing = {};
},
load(){
this.financing.product_name_write =
this.$route.params.financing.product_name_write;
this.financing.invoice_price = null;
this.financing.annual_pay_times_n = '月';//還款頻率
this.financing.annual_pay_times = 12;//還款頻率
this.financing.lease_charge = 0;//手續(xù)費(fèi)
},
}
(2)用eventBus解決此問(wèn)題
需要注意的一點(diǎn)是發(fā)布訂閱第一次會(huì)無(wú)效芯砸,因?yàn)橛嗛喌慕M件還沒(méi)創(chuàng)建萧芙。解決方法就是首次進(jìn)入pageB頁(yè)面時(shí)接收pageA頁(yè)面params里傳遞的參數(shù)。
// pageA
cars = res.rows
this.$router.push({
name: 'BrowseCars',
params: { rentType: rt, cars, selectResult
})
this.bus.$emit('change', { rentType: rt, cars, selectResult })
}
// pageB
mounted () {
this.rentType = this.$route.params.rentType
this.carsList = this.$route.params.cars // 篩選或推薦車輛
this.carNumber = this.$route.params.cars.length
this.selectResult = this.$route.params.selectResult // 篩選結(jié)果數(shù)
this.bus.$on('change', msg => { // 發(fā)布訂閱方式假丧,但第一次無(wú)效
console.log(msg)
})
}