国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答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 選項,這個選項可以接受一個數組,并通過這個數組來決定組件的?;顮顟B:

// 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])
}

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

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方法判斷是否應當從緩存中獲取組件時,組件的?;顮顟B已經被我們修改了。

劫持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并不方便,更重要的是指令的幾個生命周期在路由跳轉到?;畹捻撁鏁r都不會觸發。

因此這里我還是使用 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
主站蜘蛛池模板: 欧美精品久久久久久久久大尺度 | 亚洲福利网站 | 午夜日韩久久影院 | 国产一区二区精品久久 | 一区二区三区欧美视频 | 99久久精品国产综合一区 | 久久久久无码国产精品一区 | 亚洲素人在线 | 欧美a在线视频 | 日韩av线上| 国产日韩欧美 | 欧美1区2区3区 | 精品在线观看免费 | 国产视频首页 | 国产高清一区二区 | 国产高清视频 | 韩日视频在线观看 | 国内精品久久久久久中文字幕 | 国产一区在线观看视频 | 国产成人一区二区三区视频免费蜜 | 在线观看视频亚洲 | 日韩啪 | 国产激情一区二区三区 | 亚洲一区二区三区精品视频 | 国产一区亚洲二区三区毛片 | 亚洲天堂欧美 | 91麻豆免费观看 | 欧美亚洲另类综合 | 久久精品一级 | 特级全黄一级毛片视频 | 在线观看香蕉视频 | 亚洲欧美日韩精品专区卡通 | 久久精品日日躁夜夜躁欧美 | 国产网站免费在线观看 | 欧美高清在线不卡免费观看 | 亚洲欧美色欧另类欧 | 久久国产成人午夜aⅴ影院 久久国产精品成人免费古装 | 国产精品久久久久久一区二区 | 欧美日韩高清不卡免费观看 | 亚洲综合图片小说区热久久 | 国产 欧美 日韩 在线 |