"This is a page bookmark. When I come back, I remember to roll back to the original."

Posted by warren on Mon, 24 Jan 2022 08:47:58 +0100

Page Bookmarks

Simply put, you scroll through the current page, and when you come back from a trip out, you restore the scrolling position, just like a bookmark in a book.

Then describe your expectations for page bookmarks

  1. When I jump to another page, I come back to recover.
  2. Recovery cannot be positioned too obtrusively directly. It should be an animation.

So start working on fulfilling your expectations

How to achieve "When I jump to another page, come back to recover."

Take a step forward:

  1. Recovery relies on data.
  2. Data is saved even if you need to skip between pages
  3. Save needs to be out of control of the page
  4. Who does "control" need to do it? 🤔???

Simple, that's obviously handed over to the data warehouse 😄.

How to achieve "Recovery cannot be directly positioned too obtrusive, it should be animated."

Next:

  1. "Animation" requires "detail".
  2. "Detail" requires "coherence".
  3. "Coherence" requires "recursion" for this.
  4. Who does "recursion" need to do it? 🤔???

After exploration, the Bom object's requestAnimationFrame That's fine.

Official introduction to requestAnimationFrame:

Tell the browser that you want to perform an animation and ask the browser to update the animation by calling the specified callback function before the next redraw. This method requires a callback function to be passed in as a parameter that will be executed before the browser's next redraw

With 60fps of pictures per second, callback functions are usually executed 60 times per second (except for frame dropping) which is enough to be "coherent". If you don't make any changes, you can do it "delicately" (which is no different from game development).

It must be emphasized here that after reading several articles, many of them made a mistake (what I think)

For example, this sentence:

You seem to be setting interval when you say that. I don't think it's right. It's a logical contradiction.

My understanding: Pages are 60fps a second, then you execute the requestAnimationFrame, and then you execute it only once the next time the screen is drawn, so how consistent is that achieved by recursively executing this function, as the code says. Not deceiving.

Top Code:

export function sineaseOut(t, b, c, d) {
    return c * ((t = t / d - 1) * t * t + 1) + b
}
export function scrollToView(scroller, value) {
    if (!scroller) {
        return
    }

    const scroll = value
    const scrollStart = 0
    let start = null
    const step = (timestamp) => {
        if (!start) {
            start = timestamp
        }
        let stepScroll = sineaseOut(timestamp - start, 0, scroll, 500)
        let total = scroller.scrollTop = scrollStart + stepScroll
        if (total < scrollStart + scroll) {
            requestAnimationFrame(step)
        }
    }
    requestAnimationFrame(step)
}

Make a summary of that

  • Status data is handed over to the data manager Mobx, which sends a global warehouse to do it.

  • The fineness of the animation is achieved by recursively calling the requestAnimationFrame with 60 drawings per second.

You understand everything, then what?

Oh, yes.. Although both can be solved, there are still the most critical problems, "Where can I use it??"?

"Where to use" but very "Feng Shui" oh

If you don't choose the right location, it's like filling your code with pretensions, just for the sake of appearing comfortable. It's like "bloating your face and getting fat".

The most dangerous traps are often gentle

First of all, it's easy to think about the uninstallation and mounting of components on demand, because they really match, which is the biggest temptation, because it can be achieved, but this is not a good way, at least not the best, because if you do, all page components have to write this duplicate logic, which is too annoying. If you add to an item that has already written many pages, you will crash, which is unacceptable.

Grab the line of happiness behind the clouds

When I wanted to go back and forth, after a couple of twists and turns, almost fragrance, I finally thought of an excellent location, that is.

history.listen

At that moment, I was confident that my mouth was slightly raised and steady 😄.

Go directly to the code, I believe the number b comes from everyone's mind, there is no need to say more.

    let history = useHistory();
    let location = useLocation();
    const {
        global: { current, scrollData, changeParams },
    } = store;
    useEffect(() => {
        const { pathname, search } = location;
        changeParams({
            current: decodeURIComponent(pathname + search)
        })
        if (!history._listenCount) {
            history._listenCount++;
            history.listen((locationState, type) => {
                const {
                    global: { current, scrollData, changeParams },
                } = store;
                let node = document.getElementsByClassName('ant-layout-content')[0]
                if (!node) {
                    return
                }
                // node.scrollTop = 0;
                //Key of the latest page, save it
                let newkey = decodeURIComponent(locationState.pathname + locationState.search);
                /* Find out if there are any recorded values */
                let recordValue = scrollData[newkey]
                if (typeof recordValue === 'number') {
                    scrollToView(node, recordValue)
                }
                // Save the value (in the past), old
                let oldKey = current;
                let scrollDataTemp = { ...toJS(scrollData), [oldKey]: node.scrollTop }
                if (type === "POP") {
                    //Node in POP case. ScrollTop has been set to 0
                    changeParams({
                        current: newkey,
                    })
                } else {
                    changeParams({
                        current: newkey,
                        scrollData: scrollDataTemp
                    })
                }
            })
        }
    }, [])

The code is clear, that is, the page has gone, record it, the page comes back, restore it, the solution is so simple and natural.

See the effect

epilogue

By exploring how to implement the page bookmark function, you can better understand a reason. There is more than one way to achieve it. You know what you want, you also know what you should insist on, what you should do, and you are more likely to grasp the happiness line behind the clouds.

Integrating this functionality 🌰

Topics: Javascript ECMAScript React