<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                > ## **keep-alive組件實戰應用** ### **頁面緩存** 在Vue構建的單頁面應用(SPA)中,路由模塊一般使用vue-router。vue-router不保存被切換組件的狀態,它進行push或者replace時,舊組件會被銷毀,而新組件會被新建,走一遍完整的生命周期。 但有時候,我們有一些需求,比如跳轉到詳情頁面時,需要保持列表頁的滾動條的高度,等返回的時候依然在這個位置,這樣可以提高用戶體驗。在Vue中,對于這種“頁面緩存”的需求,我們可以使用keep-alive組件來解決這個需求。 ### **使用方式** keep-alive是個抽象組件(或稱為功能型組件),實際上不會被渲染在DOM樹中。它的作用是在內存中緩存組件(不讓組件銷毀),等到下次再渲染的時候,還會保持其中的所有狀態,并且會觸發activated鉤子函數。因為緩存的需要通常出現在頁面切換時,所以常與router-view一起出現: ~~~ <keep-alive> <router-view/> </keep-alive> ~~~ 如此一來,每一個在router-view中渲染的組件,都會被緩存起來。 ### **生命周期** ~~~ <div id="app"> <input type="button" value="切換到第1個組件" @click="tabComponent(1)"> <input type="button" value="切換到第2個組件" @click="tabComponent(2)"> <input type="button" value="切換到第3個組件" @click="tabComponent(3)"> <keep-alive> <component :is="current"></component> </keep-alive> </div> <script> // 第一個組件 const custom1 = Vue.component('custom1', { template: `<div @click="changeBg">我是第1個組件</div>`, methods: { changeBg(ev) { ev.target.style.background = 'orange' } } }) // 第二個組件 const custom2 = Vue.component('custom2', { template: `<div>我是第2個組件</div>`, created: function() { // 初始化執行一次,不再執行了 console.log('created') }, activated: function() { // 如果用keep-alive包裹后,需要每次進來完成一些數據的操作,請在這個鉤子里 console.log('activated') }, deactivated: function() { // 離開觸發 console.log('deactivated') } }) // 第三個組件 const custom3 = Vue.component('custom3', { template: `<div>我是第3個組件</div>` }) new Vue({ el: '#app', data: { current: custom1 }, methods: { tabComponent(index) { if (index === 1) { this.current = custom1 } else if(index ===2) { this.current = custom2 } else { this.current = custom3 } } } }) </script> ~~~ ### **實戰案例一** 第一個需求:從列表頁通過路由跳轉到詳情頁,當從詳情頁返回到列表頁的時候,要能夠保存列表頁滑動的高度 #### **第一步:** ~~~ <keep-alive> <router-view/> </keep-alive> ~~~ #### **第二步:** ~~~ export default { data () { return { dataList: [], scroll: 0 // 第一步:初始值 } }, created () { // 這里可以是ajax請求 }, mounted () { window.addEventListener('scroll', this.handleScroll) // 第二步:DOM掛載后添加事件 }, // 第三步:獲取頂部距離 methods: { handleScroll () { this.scroll = document.documentElement && document.documentElement.scrollTop console.log(this.scroll) } }, // 第四步:activated 為keep-alive加載時調用 activated () { if (this.scroll > 0) { window.scrollTo(0, this.scroll) this.scroll = 0 window.addEventListener('scroll', this.handleScroll) } }, // 第五步:組件退出時關閉事件 防止其他頁面出現問題 deactivated () { window.removeEventListener('scroll', this.handleScroll); } } ~~~ #### **第三步:演示** 當你從列表跳到詳情以后,然后再從詳情返回到列表,就可以返回到離開列表時候的位置了 ![](https://i.vgy.me/Uwbjne.gif) > 問題:既然我們用keep-alive包裹了所有的組件,那么出現一個問題,詳情頁的數據始終是第一次請求的,因為被緩存起來了,該怎么辦呢? #### **問題演示** ![](https://i.vgy.me/5LFn8S.gif) #### **解決方案:** 當引入keep-alive的時候,頁面第一次進入,鉤子的觸發順序created-> created-> activated,退出時觸發deactivated。 當再次進入(前進或者后退)時,只觸發activated。 這就帶來一個問題,之前在項目中使用created在頁面加載時獲取數據,使用后方法不再生效。 根據上面的解釋,將created替換為activated即可: ~~~ export default { data () { return { detailData: {} } }, created () { // Axios.get('https://api.it120.cc/small4/shop/goods/detail?id=' + this.$route.query.id).then(res => { // let { data } = res.data // this.detailData = data // }) }, activated () { Axios.get('https://api.it120.cc/small4/shop/goods/detail?id=' + this.$route.query.id).then(res => { let { data } = res.data this.detailData = data }) } } ~~~ #### **解決后的效果演示** ![](https://i.vgy.me/4p9pfB.gif) 詳情頁緩存的數據和新數據有閃爍問題,請大家自行解決,不算什么問題我覺得 > 問題:如果說我們的詳情頁很高的話,會出現一個問題,請看圖片演示 #### **問題演示** ![](https://i.vgy.me/jD7kKV.gif) 當我們從列表跳轉到詳情頁可以看到我們的商品圖片沒有顯示出來,其實并不是沒有顯示,而是我們想請頁的滾動條有了高度導致的,該怎么解決呢? #### **解決方案** ~~~ router.afterEach((to, from, next) => { window.scrollTo(0, 0) }) ~~~ 重置scroll的坐標,上面這段代碼確實解決了, > 問題:但是帶來了新的問題,我返回商品列表頁面也返回到了頂部,好吧!這也不是我想要的效果,肯定需要記住用戶瀏覽時的位置啊,拆東墻補西墻的感覺。 #### **解決方案** 比較簡單的方法,就是在詳情頁加上如上代碼 ~~~ methods: { scrollToTop () { window.scrollTo(0, 0) } }, activated () { Axios.get('https://api.it120.cc/small4/shop/goods/detail?id=' + this.$route.query.id).then(res => { let { data } = res.data this.detailData = data }) this.scrollToTop() } ~~~ 每次進入詳情頁讓頁面滾動到最頂部,問題得以解決! > 你還可以使用router路由進行控制,使用router提供的`scrollBehavior`方法,官網自行解決吧,應該沒什么難度!!!,有難度告訴我,我來寫一個簡單易懂的示例!!!O(∩_∩)O哈哈~ ***** ### **實戰案例二** ``` <keep-alive> <router-view /> </keep-alive> ``` 如此一來,每一個在router-view中渲染的組件,都會被緩存起來。 如果只想渲染某一些頁面/組件,可以使用keep-alive組件的include/exclude屬性。include屬性表示要緩存的組件名(即組件定義時的name屬性),接收的類型為string、RegExp或string數組;exclude屬性有著相反的作用,匹配到的組件不會被緩存。假如可能出現在同一router-view的N個頁面中,我只想緩存列表頁和詳情頁,那么可以這樣寫: ``` <keep-alive :include="['ListView', 'DetailView']"> <router-view /> </keep-alive> ``` 上面include的寫法不是常用的,因為它固定了哪幾個頁面緩存或不緩存,假如有下面這個場景: * 現有頁面:首頁(A)、列表頁(B)、詳情頁(C),一般可以從:A->B->C; * B到C再返回B時,B要保持列表滾動的距離; * B返回A再進入B時,B不需要保持狀態,是全新的。 很明顯,這個例子中,B是“條件緩存”的,C->B時保持緩存,A->B時放棄緩存。其實解決方案也不難,只需要將B動態地從include數組中增加/刪除就行了。 #### **實現條件緩存:全局的include數組** ##### **1. 在Vuex中定義一個全局的緩存數組,待傳給include:** ~~~ /** *Created by SmallFour on 2019/8/17/10:21 */ import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { keepAliveComponents: ['List'] // 緩存數組;默認緩存list }, mutations: { // 緩存 keepAlive (state, component) { console.log(component) !state.keepAliveComponents.includes(component) && state.keepAliveComponents.push(component) }, // 不緩存 noKeepAlive (state, component) { const index = state.keepAliveComponents.indexOf(component) index !== -1 && state.keepAliveComponents.splice(index, 1) } } }) export default store ~~~ ##### **2. 在父頁面中定義keep-alive,并傳入全局的緩存數組:** ~~~ <template> <div id="app"> <keep-alive :include="keepAliveComponents"> <router-view/> </keep-alive> </div> </template> <script> export default { name: 'App', computed: { keepAliveComponents () { return this.$store.state.keepAliveComponents } } } </script> ~~~ ##### **3. 緩存:在路由配置頁中,約定使用meta屬性keepAlive,值為true表示組件需要緩存。在全局路由鉤子beforeEach中對該屬性進行處理,這樣一來,每次進入該組件,都進行緩存:** ~~~ const router = new Router({ mode: 'history', routes: [ { path: '/', name: 'Index', component: Index, meta: { title: '首頁' } }, { path: '/list', name: 'List', component: List }, { path: '/detail/:id?', name: 'Detail', component: Detail, meta: { title: '詳情頁', keepAlive: true // 這里指定detail組件需要被緩存 } } ] }) router.beforeEach((to, from, next) => { // 在路由全局鉤子beforeEach中,根據keepAlive屬性,統一設置頁面的緩存性 // 作用是每次進入該組件,就將它緩存 if (to.meta.keepAlive) { next() router.app.$store.commit('keepAlive', to.name) } next() }) ~~~ ##### **4. 取消緩存的時機:對緩存組件使用路由的組件層鉤子beforeRouteLeave。因為list->index->list時不需要緩存list,所以可以認為:當B的下一個頁面不是detail時取消list的緩存,那么下次進入list組件時list就是全新的:** ~~~ beforeRouteLeave (to, from, next) { // 如果下一個頁面不是詳情頁(C),則取消列表頁(B)的緩存 if (to.name !== 'Detail') { this.$store.commit('noKeepAlive', from.name) } next() } ~~~ ##### **5. 效果演示** 因為list的條件緩存,是list自己的職責,所以最好把該業務邏輯寫在B的內部,而不是index中,這樣不至于讓組件之間的跳轉關系變得混亂。 #### **實現條件緩存:另一種方式** **沒有實測,邏輯上沒問題** 在父組件中,使用兩個router-view并進行條件渲染: ``` // App.vue <div id="app"> <keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"></router-view> </div> ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看