关于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:?)

                { x: number, y: number }

      { selector: string, offset? : { x: number, y: number }} (offset 只在 2.6.0+ 支持)

滚动行为

我们可以通过 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, behavior: 'smooth' }
    }
  },
})

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

scrollIntoView() 

解决方案2:

如果你想要在特定的按钮点击事件中实现平滑滚动,你可以使用 scrollIntoView 方法。

scrollIntoView()方法将调用它的元素滚动到浏览器窗口的可见区域顶部。 

element.scrollIntoView(); // 等同于 element.scrollIntoView(true)
element.scrollIntoView(alignToTop); //布尔参数。接受布尔值主要还是为了兼容不支持平滑滚动(老版)的浏览器
element.scrollIntoView(scrollIntoViewOptions); //对象参数

 参数:

alignToTop:
        当传入参数true时,相当于{behavior: ‘auto’, block: ‘start’, inline: ‘nearest’}
        当传入参数false时,相当于{behavior: ‘auto’, block: ‘end’, inline: ‘nearest’}
        当未传入参数时,默认值为:{behavior: ‘auto’, block: ‘start’, inline: ‘nearest’}


scrollIntoViewOptions:一个包含下列属性的对象。

behavior定义过渡动画,默认值为auto。
        auto,表示没有平滑的滚动动画效果。
        smooth,表示有平滑的滚动动画效果。

block定义垂直方向的对齐,默认值为start。
        start,表示顶端对齐。
        center,表示中间对齐。
        end,表示底端对齐。
        nearest:如果元素完全在视口内,则垂直方向不发生滚动。
注:如果元素未能完全在视口内,则根据最短滚动距离原则,垂直方向滚动父级容器,使元素完全在视口内。

inline定义水平方向的对齐,默认值为nearest。
        start,表示左端对齐。
        center,表示中间对齐。
        end,表示右端对齐。
        nearest:如果元素完全在视口内,则水平方向不发生滚动。
注:如果元素未能完全在视口内,则根据最短滚动距离原则,水平方向滚动父级容器,使元素完全在视口内。

<template>
  <div class="box">
    <div class="left">
      <p @click="test('id1')">第一段内容</p>
      <p @click="test('id2')">第二段内容</p>
    </div>
    <div class="right">
      <div class="content" id="id1">我是第一段内容</div>
      <div class="content" id="id2">我是第二段内容</div>
    </div>
  </div>
</template>
 
<script setup lang="ts">
const test = (data: any) => {
  document?.getElementById(data)?.scrollIntoView({
    behavior: "smooth", //smooth:平滑,auto:直接定位
    block: "start",
    inline: "start",
  });
};
</script>
 
<style scoped lang="scss">
.box {
  width: 50vw;
  height: 50vh;
  display: flex;
  overflow: hidden;
  border: 1px solid gray;
 
  .left {
    width: 100px;
    height: 100%;
    border-right: 2px solid gray;
    p {
      height: 40px;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      border: 1px solid #ccc;
    }
  }
 
  .right {
    flex: auto;
    overflow: auto;
    .content {
      width: 100%;
      height: 1000px;
      border-top: 2px solid blue;
      padding: 20px;
      box-sizing: border-box;
    }
  }
}
</style>

<template>
  <button @click="scrollToContact">Go to Contact</button>
  <div ref="contact">Contact Section</div>
</template>
 
<script>
export default {
  methods: {
    scrollToContact() {
      this.$refs.contact.scrollIntoView({ behavior: 'smooth' });
    }
  }
}
</script>

在这个例子中,当按钮被点击时,页面会平滑滚动到 "Contact Section" 这个元素。

解决方案3:

你也可以使用 window.scrollTo 方法来实现页面的平滑滚动。

methods: {
  scrollToTop() {
    window.scrollTo({
      top: 0,
      behavior: 'smooth'
    });
  }
}

 在这个例子中,当调用 scrollToTop 方法时,页面会平滑滚动到页面顶部。

注意:behavior: 'smooth' 选项只有在 window.scrollToElement.scrollIntoView() 和 scrollTo 方法中有效。如果你尝试在其他地方使用它,例如在 window.scrollBy 中,它将不会生效。

延迟滚动

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

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

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue中,要缓存table滚动条的位置,你可以使用以下步骤: 1. 首先,在Vue的data中定义一个变量,用于存储滚动条的位置,比如scrollPosition。 2. 在table元素上添加一个scroll事件监听器,当滚动事件触发时,将滚动条的位置更新到scrollPosition中。 3. 在Vue的生命周期钩子函数中,比如created或mounted中,通过获取缓存中的滚动位置,并将其赋值给scrollPosition。 4. 在Vue的updated钩子函数中,将scrollPosition中存储的滚动位置重新应用到table元素上,以恢复滚动条的位置。 下面是一个示例代码: ```vue <template> <div> <table ref="table" @scroll="saveScrollPosition"> <!-- 表格内容 --> </table> </div> </template> <script> export default { data() { return { scrollPosition: 0 } }, created() { // 从缓存中获取滚动位置,并赋值给scrollPosition this.scrollPosition = localStorage.getItem('scrollPosition') }, mounted() { // 应用滚动位置到table元素上 this.$refs.table.scrollTop = this.scrollPosition }, updated() { // 更新滚动位置 this.$refs.table.scrollTop = this.scrollPosition }, methods: { saveScrollPosition() { // 监听滚动事件,并将滚动位置保存到scrollPosition中 this.scrollPosition = this.$refs.table.scrollTop // 将滚动位置保存到缓存中 localStorage.setItem('scrollPosition', this.scrollPosition) } } } </script> ``` 在这个示例中,我们使用localStorage来保存滚动位置,以便在页面刷新或重新加载后能够恢复滚动位置。你也可以使用其他方式来存储和读取滚动位置,比如vuex或cookie等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值