Vue組件傳值及頁(yè)面緩存問(wèn)題

一怎炊、父子組件傳值

  • 基本概念
    在Vue中混移,父子組件間的數(shù)據(jù)流向可以總結(jié)為prop向下傳遞,事件向上傳遞冻璃,即父組件通過(guò)prop給子組件下發(fā)數(shù)據(jù)响谓,子組件通過(guò)自定義事件給父組件發(fā)送信息。


    vue父子組件傳值.png

    (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ò)parent,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> 
  1. path -> 是要跳轉(zhuǎn)的路由路徑
  2. name ->路由文件里面配置的name,必須一致遏插,這兩者都可以進(jìn)行路由導(dǎo)航
  3. params -> 是要傳送的參數(shù),參數(shù)可以直接key:value形式傳遞
  4. 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)
    })
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末双揪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子包帚,更是在濱河造成了極大的恐慌渔期,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渴邦,死亡現(xiàn)場(chǎng)離奇詭異疯趟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)谋梭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)信峻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人瓮床,你說(shuō)我怎么就攤上這事盹舞。” “怎么了隘庄?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵踢步,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我丑掺,道長(zhǎng)获印,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任街州,我火速辦了婚禮蓬豁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘菇肃。我一直安慰自己地粪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布琐谤。 她就那樣靜靜地躺著蟆技,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上质礼,一...
    開(kāi)封第一講書(shū)人閱讀 51,115評(píng)論 1 296
  • 那天旺聚,我揣著相機(jī)與錄音,去河邊找鬼眶蕉。 笑死砰粹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的造挽。 我是一名探鬼主播碱璃,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼饭入!你這毒婦竟也來(lái)了嵌器?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谐丢,失蹤者是張志新(化名)和其女友劉穎爽航,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體乾忱,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡讥珍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了窄瘟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衷佃。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖寞肖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情衰腌,我是刑警寧澤新蟆,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站右蕊,受9級(jí)特大地震影響琼稻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜饶囚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一帕翻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧萝风,春花似錦嘀掸、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春揩晴,著一層夾襖步出監(jiān)牢的瞬間勋陪,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工硫兰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诅愚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓劫映,卻偏偏與公主長(zhǎng)得像违孝,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子苏研,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353