vue使用keep-alive保持滾動條位置的實現

前言

下班前,20分鐘,發一篇。。。
簡單介紹,使用keep-alive的時候,返回前一頁,沒有保持滾動條位置。
事實上,就算不使用keep-alive,位置也沒有被記錄。
可是,在不使用keep-alive的時候,頁面內容會刷新,因此就隨他去了……就是這麼任性……html

思路

官方有推薦一個scrollBehavior,連接,可是上面標註,只在history.pushState的瀏覽器生效,不知道是否是隻能開啓history.pushState纔可使用,看了下實現,挺不友好的,仍是本身搞一個吧。。。vue

實現思路是這樣的,首先給路由增長一個對象meta:瀏覽器

meta: {
    keepAlive: true,
    scrollTop: 0,
}

keepAlive是否須要保持頁面,scrollTop記錄頁面的滾動位置。
而後在app.vue增長以下入口:app

<keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>

這樣就啓用keep-alive了。
而後在全局main.ts增長一個全局路由控制:ide

router.beforeEach((to: Route, from: Route, next: () => void) => {    
    if (from.meta.keepAlive) {
    const $content = document.querySelector('#content');
    const scrollTop = $content ? $content.scrollTop : 0;
    from.meta.scrollTop = scrollTop;
  }
  next();
});

很簡單,離開的時候判斷當前頁是否須要保持頁面,若是須要,記錄頁面主容器content的滾動位置,寫入路由。
而後,每次進入保持好的頁面,讀取滾動條位置scrollTop,修改主容器的scrollTop,就搞定了:函數

public activated() {
    const scrollTop = this.$route.meta.scrollTop;
    const $content = document.querySelector('#content');
    if (scrollTop && $content) {
      $content.scrollTop = scrollTop;
    }
}

看起來很簡單哦。佈局

遺留問題

一、是否是每一個頁面均可以記錄滾動條位置呢?ui

其實不是的,有的頁面,內部有js交互,好比tab交互,不一樣的tab,頁面可滾動的高度不一致,若是不保持頁面狀態而統一記錄滾動位置,有可能致使滾動條的位置錯位。

二、能不能把activated這一步寫到全局的main.ts或者state去呢?this

有想過這點,可是目前來講,沒找到實現的方法。
首先,若是經過router來控制,作不到,全局路由控制只能在頁面加載前監聽,取不到載入頁的元素。
若是寫在一個通用的全局函數去控制,好比定義一個state,當頁面加載完的時候設置,那須要定義一個mixins來處理,可是對這個mixins不太熟悉,暫時還不知道該怎麼作,可能有時間找個方法搞定它。

沒有啦……code

後記

今天抽時間看了下官方的scrollBehavior,其實仍是很簡單的,可是我用不上,,,
緣由是官方使用的滾動條,針對的是元素是#app,可是很遺憾,個人頁面佈局決定了,個人滾動條應該給#content元素。

<div id="app">
  <div class="wrap">
    <div id="header">
    <div id="content">
    <div id="footer">
    ...

因此scrollBehavior只可否決了。
回到mixins,今天也嘗試了一下,可是VSC提示我,在mixin中的activated方法找不到this.$route這個屬性:

類型「VueConstructor<Vue> | ComponentOptions<Vue, DefaultData<Vue>, DefaultMethods<Vue>, DefaultComputed, PropsDefinition<Record<string, any>>, Record<string, any>>」上不存在屬性「$route」。
  類型「VueConstructor<Vue>」上不存在屬性「$route」。

固然,就算提示找不到$route,實際上仍是找到了的。
可是這裏又有一個問題,mixin會在當前頁每個組件中都執行一次,在N個組件中會對滾動條操做N次,感受有點冗贅,不太喜歡。
暫時找不到更好的實現方式了,只能在須要記錄的頁面單獨實現activated...

搞定

下班前,總算搞定了。不廢話,上代碼:
自定義一個mixins:

//mixin.ts
import Vue from 'vue';
import Component from 'vue-class-component';

@Component
export default class MyMixin extends Vue {
  public activated() {
    const scrollTop = this.$route.meta.scrollTop;
    const $content = document.querySelector('#content');
    if (scrollTop && $content) {
      $content.scrollTop = scrollTop;
    }
  }
}

在須要記錄scrollTop的頁面引入這個mixins:

// home.vue
import { Component, Mixins } from 'vue-property-decorator';
import MyMixin from '@/global/mixin';

@Component
export default class Home extends Mixins(MyMixin) {
  // todo ...
}

關鍵在於Mixins,在沒有使用Mixins以前,咱們引入的是Vue,組件繼承的也是Vue,如今引入Mixins,組件直接繼承Mixins,而後把咱們自定義的mixins傳遞進去,就能夠在本頁掛載自定義的Mixins了。這麼處理,基本完成了記錄滾動條的功能,OK~

相關文章
相關標籤/搜索