Recently, I had a problem with using Vue for mobile pages. I went from the list page to the details page, and then back to the list page, jumping to the top of the list every time I went back, no matter where I had scrolled before.

This is definitely not a good experience. The expectation should be to remember the position of the scroll bar and return to the same position each time so that you can continue browsing.

So on the net search solution, search a big circle to see n articles, are not clear. At least I didn’t have a perfect solution by reading an article, so I decided to write a detailed test of the possible solution.

There are three steps:

  • Add keep-alive to router-view
  • Gets and stores the current scrollTop
  • Retrieve and set the scrollTop when you return

More than 100 experienced developers participated in the full stack full platform open source project on Github, 1000+ star. Want to know or participate? The address of the project: https://github.com/cachecats/coderiver

Add keep-alive to router-view

Post the official keep-Alive document first. If you are not familiar with it, you can take a look at the document first.


when wrapping dynamic components, inactive component instances are cached rather than destroyed. So do not let the list page refresh when it is returned from the detail page.

When a component is switched within

, its activated and deactivated lifecycle hook functions are executed accordingly.

The scrollTop value is set in the Activated method. Some articles say that the scrollTop value is obtained in the Deactivated method. However, tests show that the scrollTop value cannot be accurately obtained in the Deactivated method and is always 0. The specific reasons will not be explored for the time being and the problem will be solved first. So get the scrollTop value in the click event function for item.

Get and store the current scrollTop

The page layout is as follows:

The entire page is a

, and there are two tabs below. Our list page is a component, located in the area between the title and the navigation bar.

Layout code:

<div class="wrapper" > <div class="title"> </div> <van-pull-refresh v-model="isRefresh" @refresh="onRefresh" ref="pullRefresh"> <van-list ref="list" class="list" v-model="loadingMore" :finished="finished" Lasted-text =" no more "@load="onLoadMore" > <div class="item-wrapper" V-for ="item in list" :key="item.id" @click="clickItem(item)" ref="item"> <div class="item">{{item}}</div> </div> </van-list> </van-pull-refresh> </div>Copy the code

Use the drop-down refresh and pull-up to load more components in the Vuant-UI.

The ref=”pullRefresh” for the van-pull-refresh component, the ref=”list” for the van-list component, And ref=”item” for each item.

Why give so many? Because there’s a big hole here, and that’s where I’ve been stuck.

We know that the scrollTop property is used to get the scroll position, so let’s print out the scrollTop for each element in turn.

clickItem(item) {
    let wrapperScrollTop = this.$refs.wrapper.scrollTop;
    let pullRefreshScrollTop = this.$refs.pullRefresh.scrollTop;
    let listScrollTop = this.$refs.list.scrollTop;
    let itemScrollTop = this.$refs.item.scrollTop;

    console.log('wrapperScrollTop', wrapperScrollTop);
    console.log('pullRefreshScrollTop', pullRefreshScrollTop);
    console.log('listScrollTop', listScrollTop);
    console.log('itemScrollTop', itemScrollTop);

    this.$router.push({name: "detail".params: {data: item}})
},
Copy the code

Triggered in the click event on item. The resulting log is as follows:

WTF? Only the first wrapperScrollTop has a value, the others are undefined!

I don’t know why, I have been getting the scrollTop of the last three before, but I couldn’t get it for a long time. Why the other three get less than I have not yet understood, know the reason big guy can give advice.

Knowing which element’s scrollTop to get is easy, and the value is just stored.

Because keep-alive is used, the page is cached, so the data in data will not be lost. You can declare a variable scroll in data to store the value of scrollTop. You can also use Vuex.

Modify the clickItem(item) code to store the value of scrollTop.

clickItem(item) {
    let wrapperScrollTop = this.$refs.wrapper.scrollTop;
    let pullRefreshScrollTop = this.$refs.pullRefresh.scrollTop;
    let listScrollTop = this.$refs.list.scrollTop;
    let itemScrollTop = this.$refs.item.scrollTop;

    console.log('wrapperScrollTop', wrapperScrollTop);
    console.log('pullRefreshScrollTop', pullRefreshScrollTop);
    console.log('listScrollTop', listScrollTop);
    console.log('itemScrollTop', itemScrollTop);
    
	// Store the value of scrollTop
    this.scroll = wrapperScrollTop;
   
    this.$router.push({name: "detail".params: {data: item}})
},
Copy the code

Retrieve and set the scrollTop when you return

As mentioned above, the Activated life cycle method is called every time the keep-Alive page is returned, so set the scrollTop to remember the scrolling position.

The code is simple, just one sentence:

activated() {
	this.$refs.wrapper.scrollTop = this.scroll
}
Copy the code

The complete code is as follows:

<template> <div class="wrapper" ref="wrapper"> <div class="title"> </div> <van-pull-refresh v-model="isRefresh" @refresh="onRefresh" ref="pullRefresh"> <van-list ref="list" class="list" v-model="loadingMore" :finished="finished" Lasted-text =" no more "@load="onLoadMore" > <div class="item-wrapper" V-for ="item in list" :key="item.id" @click="clickItem(item)" ref="item"> <div class="item">{{item}}</div> </div> </van-list> </van-pull-refresh> </div> </template> <script> export default { components: {}, created() { }, mounted() { for (let i = 0; i < 15; I ++) {this.list.push(I)}}, data() {return {list: [], loadingMore: false, // Load more IsRefresh: false, // Whether to pull down refresh scroll: 0, } }, activated() { this.$refs.wrapper.scrollTop = this.scroll }, deactivated() { }, methods: { clickItem(item) { let wrapperScrollTop = this.$refs.wrapper.scrollTop; let pullRefreshScrollTop = this.$refs.pullRefresh.scrollTop; let listScrollTop = this.$refs.list.scrollTop; let itemScrollTop = this.$refs.item.scrollTop; console.log('wrapperScrollTop', wrapperScrollTop); console.log('pullRefreshScrollTop', pullRefreshScrollTop); console.log('listScrollTop', listScrollTop); console.log('itemScrollTop', itemScrollTop); this.scroll = wrapperScrollTop; this.$router.push({name: "detail", params: {data: item}}) }, onRefresh() { this.list = []; this.finished = false; setTimeout(() => { for (let i = 0; i < 15; i++) { this.list.push(i) } this.isRefresh = false }, 2000) }, OnLoadMore () {console.log('load more') let newList = []; for (let i = this.list.length; i < this.list.length + 15; i++) { newList.push(i) } this.list = this.list.concat(newList) this.loadingMore = false; if (this.list.length > 50) { this.finished = true } }, } } </script> <style scoped lang="scss"> @import ".. /.. /public/css/index"; .wrapper { width: 100%; height: calc(100vh - 100px); overflow-x: hidden; box-sizing: border-box; margin-bottom: px2rem(50); .title{ font-size: px2rem(20); padding: px2rem(10); } .list { width: 100%; flex: 1; display: flex; flex-direction: column; box-sizing: border-box; .item-wrapper { display: flex; flex-direction: column; font-size: px2rem(16); margin: px2rem(8); padding: px2rem(8); background-color: white; .item { font-size: px2rem(16); padding: px2rem(10); } } } } </style>Copy the code

Ok, so that’s how Vue returns to remember the scrollbar position.


Full stack full platform open source project CodeRiver

CodeRiver is a free project collaboration platform with a vision to connect the upstream and downstream of the IT industry. Whether you are a product manager, designer, programmer, tester, or other industry personnel, you can come to CodeRiver to publish your project for free and gather like-minded team members to make your dream come true!

CodeRiver itself is also a large open source project, committed to creating full stack full platform enterprise quality open source projects. It covers React, Vue, Angular, applets, ReactNative, Android, Flutter, Java, Node and almost all the mainstream technology stacks, focusing on code quality.

So far, nearly 100 top developers have participated, and there are nearly 1,000 stars on Github. Each stack is staffed by a number of experienced gurus and two architects to guide the project architecture. No matter what language you want to learn and what skill level you are at, you can learn it here.

Help every developer grow quickly through high quality source code + blog + video.

The address of the project: https://github.com/cachecats/coderiver


Your encouragement is our biggest power forward, welcome to praise, welcome to send small stars ✨ ~