• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答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
    主站蜘蛛池模板: 国产亚洲综合成人91精品| 国产精品理论片在线观看| 久久免费精品一区二区| 亚洲精品欧美二区三区中文字幕| 欧美日激情日韩精品| 久久性精品| 尤物国精品午夜福利视频| 国产精品免费久久| 精品国产麻豆免费人成网站| 亚洲日韩欧美制服精品二区| 国产精品JIZZ在线观看老狼| 精品久久777| 国产成人精品无码一区二区| 亚洲精品成人网站在线观看 | 亚洲精品在线观看视频| 99久久精品日本一区二区免费 | 久久精品国产影库免费看| 国产精品无码久久综合| 亚洲国产一二三精品无码 | 99精品高清视频一区二区| 精品亚洲aⅴ在线观看| 无码精品国产VA在线观看DVD| 亚洲精品欧美二区三区中文字幕 | 久久精品一本到99热免费| 亚洲国产一成人久久精品| 亚洲日韩一页精品发布| 一区二区三区精品高清视频免费在线播放| 欧美精品VIDEOSEX极品| 欧美日韩国产精品系列| 欧美精品色婷婷五月综合| 蜜桃麻豆www久久国产精品 | 亚洲欧美日韩国产精品一区二区| 欧美日韩国产中文精品字幕自在自线| 精品一区二区三区在线观看| 精品偷自拍另类在线观看丰满白嫩大屁股ass | 亚洲精品视频免费观看| 亚洲精品无码久久久影院相关影片| 亚洲无码精品浪潮| 亚洲国产精品va在线播放| 欧美精品hdvideosex4k| 国产精品无码A∨精品影院|