亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時間:2018年12月02日 09:10:38   作者:前端全棧開發(fā)學(xué)習(xí)  
這篇文章主要介紹了在移動端使用vue-router和keep-alive的方法示例,vue-router與keep-alive提供的路由體驗與移動端是有一定差別的,感興趣的小伙伴們可以參考一下

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

目標(biāo)

問題

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

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

使用環(huán)境

對于代碼能正確運行的環(huán)境,這里嚴(yán)格假定為微信(或是APP中內(nèi)嵌的web頁面),而非通過普通瀏覽器訪問,即:用戶無法通過直接輸入url來跳轉(zhuǎn)路由。在這樣的前提下,路由的跳轉(zhuǎn)是代碼可控的,即對應(yīng)于vue-router的push、replace等方法,而唯一無法干預(yù)的是瀏覽器的回退行為。在這樣的前提下,我們可以假定,任何沒有通過vue-router觸發(fā)的路由跳轉(zhuǎn),是 回退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');

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

keep-alive

includes

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

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

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

afterEach

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

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 的執(zhí)行是晚于路由的設(shè)置的,但組件的 render 是在 nextTick 中執(zhí)行的,也就是說,在keep-alive的render方法判斷是否應(yīng)當(dāng)從緩存中獲取組件時,組件的?;顮顟B(tài)已經(jīng)被我們修改了。

劫持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(當(dāng)然這里需要劫持的方法不止是push,在此僅用push作為示例)和瀏覽器的回退行為用不同的 dir 標(biāo)記,并根據(jù)這個值來維護includes數(shù)組。

然后,將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數(shù)組:

const positions = [];

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

 ...
});

起初我想通過指令來移除事件偵聽(unbind)以及恢復(fù)滾動位置,但發(fā)現(xiàn)使用unbind并不方便,更重要的是指令的幾個生命周期在路由跳轉(zhuǎn)到?;畹捻撁鏁r都不會觸發(fā)。

因此這里我還是使用 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>

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • vue2.0使用Sortable.js實現(xiàn)的拖拽功能示例

    vue2.0使用Sortable.js實現(xiàn)的拖拽功能示例

    本篇文章主要介紹了vue2.0使用Sortable.js實現(xiàn)的拖拽功能示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • vue獲取input輸入值的問題解決辦法

    vue獲取input輸入值的問題解決辦法

    這篇文章主要介紹了vue獲取input輸入值的問題解決辦法的相關(guān)資料,希望通過本文能幫助到大家,讓大家掌握這樣的問題,需要的朋友可以參考下
    2017-10-10
  • vue項目支付功能代碼詳解

    vue項目支付功能代碼詳解

    這篇文章主要介紹了vue項目支付功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-01-01
  • element中el-cascader級聯(lián)選擇器只有最后一級可以多選

    element中el-cascader級聯(lián)選擇器只有最后一級可以多選

    本文主要介紹了element中el-cascader級聯(lián)選擇器只有最后一級可以多選,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • Vue中的v-for列表循環(huán)示例詳解

    Vue中的v-for列表循環(huán)示例詳解

    循環(huán)使用v-for指令,v-for指令需要以site in sites形式的特殊語法,sites是源數(shù)據(jù)數(shù)組并且site是數(shù)組元素迭代的別名,下面這篇文章主要給大家介紹了關(guān)于Vue中v-for列表循環(huán)的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • Vue.js中使用${}實現(xiàn)變量和字符串的拼接方式

    Vue.js中使用${}實現(xiàn)變量和字符串的拼接方式

    這篇文章主要介紹了Vue.js中使用${}實現(xiàn)變量和字符串的拼接方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 詳解Vue 開發(fā)模式下跨域問題

    詳解Vue 開發(fā)模式下跨域問題

    本篇文章主要介紹了Vue 開發(fā)模式下跨域問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • vue日常開發(fā)基礎(chǔ)Axios網(wǎng)絡(luò)庫封裝

    vue日常開發(fā)基礎(chǔ)Axios網(wǎng)絡(luò)庫封裝

    這篇文章主要為大家介紹了vue日常開發(fā)基礎(chǔ)Axios網(wǎng)絡(luò)庫封裝示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • element中一個單選框radio時的選中和取消代碼詳解

    element中一個單選框radio時的選中和取消代碼詳解

    這篇文章主要給大家介紹了關(guān)于element中一個單選框radio時的選中和取消的相關(guān)資料,文中通過圖文以及代碼示例介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考價值,需要的朋友可以參考下
    2023-09-09
  • Vue之Pinia狀態(tài)管理

    Vue之Pinia狀態(tài)管理

    這篇文章主要介紹了Vue中Pinia狀態(tài)管理,Pinia開始于大概2019年,其目的是設(shè)計一個擁有 組合式 API 的 Vue 狀態(tài)管理庫,Pinia本質(zhì)上依然是一個狀態(tài)管理庫,用于跨組件、頁面進行狀態(tài)共享,感興趣的同學(xué)可以參考閱讀
    2023-04-04

最新評論