关于vue的scrollBehavior(滚动行为)

咱们在实际开发中会遇到一个问题:
我们在一个很长的列表页往下拉,然后点击列表中的某一个数据进入到详情页查看。此时我们决定返回列表也继续查看列表。
很多情况下,由于列表页的组件已经被销毁,所以我们返回到列表页后页面会置顶,不得不又重新下拉查看列表,这样就做了很多没有必要的操作,也是不符合用户的预期。

用户希望当我查看玩详情页以后返回,返回列表页的位置是刚刚浏览的位置

这种情况有什么好的解决办法呢?

这里带来了3种解决方案:

1.使用<keep-alive> 缓存,即不销毁列表页

APP.js中

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

router.js中

 routes: [
    {
      path: '/',
      name: 'List',
      //component: List
      component: () => import('./views/index/list.vue'),
      meta: {
        keepAlive: true // 需要缓存
      }
    },
    {
      path: '/content/:contentId',
      name: 'content',
      component: () => import('./views/index/content.vue'),
      meta: {
        keepAlive: false // 不需要缓存
      }
    },
]

详情页面不需要缓存,列表页面需要缓存

2.使用路由守卫

原理就是在beforRouterLeave的路由钩子记录当前页面滚动位置

//在页面离开时记录滚动位置,这里的this.scrollTop可以保存在vuex的state或者浏览器本地
beforeRouteLeave (to, from, next) {
    this.scrollTop = document.documentElement.scrollTop || document.body.scrollTop
    next()
  },

//进入该页面时,用之前保存的滚动位置赋值
beforeRouteEnter (to, from, next) {
    next(vm => {
      document.body.scrollTop = vm.scrollTop
    })
  },

这里的this.scrollTop可以保存在vuex的state或者浏览器本地

3.使用vue-router方法scrollBehavior(推荐)

router.js中

const scrollBehavior = function scrollBehavior (to, from, savedPosition) {
  if (savedPosition) {
    // savedPosition 会在你使用浏览器前进或后退按钮时候生效
    // savedPosition: 会记录滚动条的坐标,点击"后退/前进" 时的记录值(x:?,y:?)
    return savedPosition;
  }else {
      return { x: 0, y: 0 }; // 期望滚动的位置
   }
};
const router = new Router({
  routes,
  scrollBehavior,
});

 该方案直接在路由进行处理,兼容每个页面并且页面加载完后并也不会产生1px的滚动位置。

scrollBehavior (to, from, savedPosition)方法接收 to 和 from 路由对象。第三个参数 savedPosition当且仅当 popstate 导航(通过浏览器的 前进/后退 按钮触发)时才可用

参数:

        to:要进入的目标路由对象,到哪里去

        from:离开的路由对象,从哪儿来

        savedPosition: 会记录滚动条的坐标,点击"后退/前进" 时的记录值(x:?,y:?)

滚动行为

我们可以通过 vue-router 自定义路由切换时页面如何滚动。比如,当跳转到新路由时,页面滚动到某个位置;切换路由时页面回到之前的滚动位置。
当创建路由实例时,我们只需要提供一个 scrollBehavior 方法:

const router = createRouter({
  history: createWebHashHistory(),
  routes: [...],
  scrollBehavior (to, from, savedPosition) {
    // return 期望滚动到哪个的位置
  }
})

scrollBehavior 函数接收 to 和 from 路由对象。第三个参数 savedPosition,只有当这是一个 popstate 导航时才可用(点击浏览器的后退/前进按钮,或者调用 router.go() 方法)

滚动到固定距离

该函数可以返回一个 ScrollToOptions 位置对象:

const router = createRouter({
  scrollBehavior(to, from, savedPosition) {
    // 始终滚动到顶部
    return { top: 0 }
  },
})

滚动到元素位置

可以通过 el 传递一个 CSS 选择器或一个 DOM 元素。在这种情况下,top 和 left 将被视为该元素的相对偏移量。

const router = createRouter({
  scrollBehavior(to, from, savedPosition) {
    // 始终在元素 #main 上方滚动 10px
    return {
      // el: document.getElementById('main'),
      el: '#main',
      top: -10,
    }
  },
})

滚动到锚点位置

const router = createRouter({
  scrollBehavior(to, from, savedPosition) {
    if (to.hash) {
      return {
        el: to.hash,
      }
    }
  },
})

滚动到之前的位置

在按下浏览器 后退/前进 按钮,或者调用 router.go() 方法时,页面会回到之前的滚动位置:

const router = createRouter({
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return { top: 0 }
    }
  },
})

注意:如果返回一个 false 的值,或者是一个空对象,则不会发生滚动。我们还可以在返回的对象中添加 behavior: 'smooth' ,让滚动更加丝滑

延迟滚动

有时候我们不希望立即执行滚动行为。例如当页面做了过渡动效,我们希望过渡结束后再执行滚动。要做到这一点,我们可以返回一个 Promise

const router = createRouter({
  scrollBehavior(to, from, savedPosition) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve({ left: 0, top: 0 })
      }, 500)
    })
  }
})

猜你喜欢

转载自blog.csdn.net/muzidigbig/article/details/131709194