<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        在移動端使用vue-router和keep-alive的方法示例

        來源:懂視網 責編:小采 時間:2020-11-27 22:03:05
        文檔

        在移動端使用vue-router和keep-alive的方法示例

        在移動端使用vue-router和keep-alive的方法示例:對于web開發和移動端開發,兩者在路由上的處理是不同的。對于移動端來說,頁面的路由是相當于棧的結構的。vue-router與keep-alive提供的路由體驗與移動端是有一定差別的,因此常常開發微信公眾號的我想通過一些嘗試來將兩者的體驗拉近一些。 目標 問題
        推薦度:
        導讀在移動端使用vue-router和keep-alive的方法示例:對于web開發和移動端開發,兩者在路由上的處理是不同的。對于移動端來說,頁面的路由是相當于棧的結構的。vue-router與keep-alive提供的路由體驗與移動端是有一定差別的,因此常常開發微信公眾號的我想通過一些嘗試來將兩者的體驗拉近一些。 目標 問題

        對于web開發和移動端開發,兩者在路由上的處理是不同的。對于移動端來說,頁面的路由是相當于棧的結構的。vue-router與keep-alive提供的路由體驗與移動端是有一定差別的,因此常常開發微信公眾號的我想通過一些嘗試來將兩者的體驗拉近一些。

        目標

        問題

        首先一個問題是keep-alive的行為。我們可以通過keep-alive來保存頁面狀態,但這樣的行為對于類似于APP的體驗是有些奇怪的。例如我們的應用有首頁、列表頁、詳情頁3個頁面,當我們從列表頁進入詳情頁再返回,此時列表頁應當是keep-alive的。而當我們從列表頁返回首頁,再次進入列表頁,此時的列表頁應當在退出時銷毀,并在重新進入時再生成才比較符合習慣。

        第二個問題是滾動位置。vue-router提供了 scrollBehavior 來幫助維護滾動位置,但這一工具只能將頁面作為滾動載體來處理。但我在實際開發中,喜歡使用flex來布局頁面,滾動列表的載體常常是某個元素而非頁面本身。

        使用環境

        對于代碼能正確運行的環境,這里嚴格假定為微信(或是APP中內嵌的web頁面),而非通過普通瀏覽器訪問,即:用戶無法通過直接輸入url來跳轉路由。在這樣的前提下,路由的跳轉是代碼可控的,即對應于vue-router的push、replace等方法,而唯一無法干預的是瀏覽器的回退行為。在這樣的前提下,我們可以假定,任何沒有通過vue-router觸發的路由跳轉,是 回退1個記錄 的回退行為。

        改造前

        這里我列出改造前的代碼,是一個非常簡單的demo,就不詳細說了(這里列表頁有兩個列表,是為了展示改造后的滾動位置維護):

        // css
        * {
         margin: 0;
         padding: 0;
         box-sizing: border-box;
        }
        html, body {
         height: 100%;
        }
        #app {
         height: 100%;
        }
        
        // html
        <div id="app">
         <keep-alive>
         <router-view></router-view>
         </keep-alive>
        </div>
        
        // js
        const Index = {
         name: 'Index',
         template:
         `<div>
         首頁
         <div>
         <router-link :to="{ name: 'List' }">Go to List</router-link>
         </div>
         </div>`,
         mounted() {
         console.warn('Main', 'mounted');
         },
        };
        
        const List = {
         name: 'List',
         template: 
         `<div style="display: flex;flex-direction: column;height: 100%;">
         <div>列表頁</div>
         <div style="flex: 1;overflow: scroll;">
         <div v-for="item in list" :key="item.id">
         <router-link style="line-height: 100px;display:block;" :to="{ name: 'Detail', params: { id: item.id } }">
         {{item.name}}
         </router-link>
         </div>
         </div>
         <div style="flex: 1;overflow: scroll;">
         <div v-for="item in list" :key="item.id">
         <router-link style="line-height: 100px;display:block;" :to="{ name: 'Detail', params: { id: item.id } }">
         {{item.name}}
         </router-link>
         </div>
         </div>
         </div>`,
         data() {
         return {
         list: new Array(10).fill(1).map((_,index) => {
         return {id: index + 1, name: `item${index + 1}`};
         }),
         };
         },
         mounted() {
         console.warn('List', 'mounted');
         },
         activated() {
         console.warn('List', 'activated');
         },
         deactivated() {
         console.warn('List', 'deactivated');
         },
        };
        
        const Detail = {
         name: 'Detail',
         template:
         `<div>
         詳情頁
         <div>
         {{$route.params.id}}
         </div>
         </div>`,
         mounted() {
         console.warn('Detail', 'mounted');
         },
        };
        
        const routes = [
         { path: '', name: 'Main', component: Index },
         { path: '/list', name: 'List', component: List },
         { path: '/detail/:id', name: 'Detail', component: Detail },
        ];
        
        const router = new VueRouter({
         routes,
        });
        
        const app = new Vue({
         router,
        }).$mount('#app');
        
        

        當我們第一次從首頁進入列表頁時, mounted 和 activated 將被先后觸發,而在此后無論是進入詳情頁再回退,或是回退到首頁再進入列表頁,都只會觸發 deactivated 生命周期。

        keep-alive

        includes

        keep-alive有一個 includes 選項,這個選項可以接受一個數組,并通過這個數組來決定組件的保活狀態:

        // keep-alive
        render () {
         const slot = this.$slots.default
         const vnode: VNode = getFirstComponentChild(slot)
         const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
         if (componentOptions) {
         const name: ?string = getComponentName(componentOptions)
         const { include, exclude } = this
         if (
         (include && (!name || !matches(include, name))) ||
         (exclude && name && matches(exclude, name))
         ) {
         return vnode
         }
        
         const { cache, keys } = this
         const key: ?string = vnode.key == null
         ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
         : vnode.key
         if (cache[key]) {
         vnode.componentInstance = cache[key].componentInstance
         remove(keys, key)
         keys.push(key)
         } else {
         cache[key] = vnode
         keys.push(key)
         if (this.max && keys.length > parseInt(this.max)) {
         pruneCacheEntry(cache, keys[0], keys, this._vnode)
         }
         }
        
         vnode.data.keepAlive = true
         }
         return vnode || (slot && slot[0])
        }
        
        

        這里我注意到,可以動態的修改這個數組,來使得本來處于保活狀態的組件/頁面失活。

        afterEach

        那我們可以在什么時候去維護/修改includes數組呢?vue-router提供了 afterEach 方法來添加路由改變后的回調:

        updateRoute (route: Route) {
         const prev = this.current
         this.current = route
         this.cb && this.cb(route)
         this.router.afterHooks.forEach(hook => {
         hook && hook(route, prev)
         })
        }
        

        在這里雖然 afterHooks 的執行是晚于路由的設置的,但組件的 render 是在 nextTick 中執行的,也就是說,在keep-alive的render方法判斷是否應當從緩存中獲取組件時,組件的保活狀態已經被我們修改了。

        劫持router.push

        這里我們將劫持router的push方法:

        let dir = 1;
        const includes = [];
        
        const routerPush = router.push;
        router.push = function push(...args) {
         dir = 1;
         routerPush.apply(router, args);
        };
        
        router.afterEach((to, from) => {
         if (dir === 1) {
         includes.push(to.name);
         } else if (dir === -1) {
         includes.pop();
         }
         dir = -1;
        });
        
        

        我們將router.push(當然這里需要劫持的方法不止是push,在此僅用push作為示例)和瀏覽器的回退行為用不同的 dir 標記,并根據這個值來維護includes數組。

        然后,將includes傳遞給keep-alive組件:

        // html
        <div id="app">
         <keep-alive :include="includes">
         <router-view></router-view>
         </keep-alive>
        </div>
        
        // js
        const app = new Vue({
         router,
         data() {
         return {
         includes,
         };
         },
        }).$mount('#app');
        
        

        維護滾動

        接下來,我們將編寫一個 keep-position 指令(directive):

        Vue.directive('keep-position', {
         bind(el, { value }) {
         const parent = positions[positions.length - 1];
         const obj = {
         x: 0,
         y: 0,
         };
         const key = value;
         parent[key] = obj;
         obj.el = el;
         obj.handler = function ({ currentTarget }) {
         obj.x = currentTarget.scrollLeft;
         obj.y = currentTarget.scrollTop;
         };
         el.addEventListener('scroll', obj.handler);
         },
        });
        

        并對router進行修改,來維護position數組:

        const positions = [];
        
        router.afterEach((to, from) => {
         if (dir === 1) {
         includes.push(to.name);
         positions.push({});
         }
        
         ...
        });
        
        

        起初我想通過指令來移除事件偵聽(unbind)以及恢復滾動位置,但發現使用unbind并不方便,更重要的是指令的幾個生命周期在路由跳轉到保活的頁面時都不會觸發。

        因此這里我還是使用 afterEach 來處理路由維護,這樣在支持回退多步的時候也比較容易去擴展:

        router.afterEach((to, from) => {
         if (dir === 1) {
         includes.push(to.name);
         positions.push({});
         } else if (dir === -1) {
         includes.pop();
         unkeepPosition(positions.pop({}));
         restorePosition();
         }
         dir = -1;
        });
        
        const restorePosition = function () {
         Vue.nextTick(() => {
         const parent = positions[positions.length - 1];
         for (let key in parent) {
         const { el, x, y } = parent[key];
         el.scrollLeft = x;
         el.scrollTop = y;
         }
         });
        };
        
        const unkeepPosition = function (parent) {
         for (let key in parent) {
         const obj = parent[key];
         obj.el.removeEventListener('scroll', obj.handler);
         }
        };
        
        

        最后,我們分別給我們的列表加上我們的指令就可以了:

        <div style="flex: 1;overflow: scroll;" v-keep-position="'list1'">
         <!-- -->
        </div>
        <div style="flex: 1;overflow: scroll;" v-keep-position="'list2'">
         <!-- -->
        </div>
        

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        在移動端使用vue-router和keep-alive的方法示例

        在移動端使用vue-router和keep-alive的方法示例:對于web開發和移動端開發,兩者在路由上的處理是不同的。對于移動端來說,頁面的路由是相當于棧的結構的。vue-router與keep-alive提供的路由體驗與移動端是有一定差別的,因此常常開發微信公眾號的我想通過一些嘗試來將兩者的體驗拉近一些。 目標 問題
        推薦度:
        標簽: 使用 VUE 移動
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲熟妇色自偷自拍另类| 情侣视频精品免费的国产| 亚洲AV永久无码精品一百度影院| 国产精品极品美女自在线观看免费 | 亚洲Av熟妇高潮30p| 亚洲综合图色40p| 亚洲春色在线视频| 久久精品私人影院免费看| 91精品免费久久久久久久久| 精品香蕉在线观看免费| 午夜网站免费版在线观看| 亚洲精品欧美综合四区| 亚洲Av无码乱码在线观看性色| 国产L精品国产亚洲区久久| 男女一边桶一边摸一边脱视频免费 | 国产一级黄片儿免费看| 毛片免费在线观看| h片在线免费观看| 亚洲七久久之综合七久久| 色播在线永久免费视频| 久久久久国产成人精品亚洲午夜 | 国产亚洲美日韩AV中文字幕无码成人| 边摸边脱吃奶边高潮视频免费| 中国黄色免费网站| 亚洲国产人成在线观看69网站| 亚洲一区二区久久| 国产精品亚洲综合天堂夜夜| 亚洲爽爽一区二区三区| 亚洲国产亚洲综合在线尤物| 美女被免费网站在线视频免费| 十八禁无码免费网站| 亚洲冬月枫中文字幕在线看 | A片在线免费观看| 成年美女黄网站18禁免费| 中文字幕人成人乱码亚洲电影 | 免费视频成人国产精品网站| 久久91亚洲精品中文字幕| 女人张腿给男人桶视频免费版| 国产高清对白在线观看免费91 | 国产成人1024精品免费| 无码国产精品一区二区免费I6 |