简体   繁体   中英

How to open new page and scroll to id leaving the URL unaffected?

I have an gatsby project. On one page I have an Link (provided from gatsby lib, an anchor basically). When I press on that Link I want it to open the new page and scroll to a certain div on Page 2. BUT only if you come to page 2 trough the Link. If I were to refresh page 2, it want it to not scroll to that div.

Also I want the URL on page 2 not to have any hashtags included.

In my Links to property I have added #target (which is the ID of the div on page 2). This works great except that the URL will have #search in it. I would like it to stay at "/hall/fun" .

Then we have a really messy solution I have tried but one I dont want to explore if I dont have to:

I have tried having the scroll function in an useEffect on page 2. But then it scrolls all the time. The idea was to then have an onClick on the Link on page 1 to update an clickedState from the initial state false to true. The page 2 component gets the true value from clickedState and carries on to run the scroll function. But that seems like so much work for something so little.

The Link on page 1

    <Link className="aTag" to='/hall/fun#search'>

My scroll function on page 2

let Page2 = props => {

  const myTargetRef = useRef(null)

  useEffect(() => {
    myTargetRef.current.scrollIntoView({behavior:"smooth", block:"start"})
  }, [])

  return (
        <div
          onChange={e => setKeyValue(e.target.value)}
          value={keyValue}
          ref={myTargetRef}
        />
  )
}

I only get half an solution with either of these answers. Either the url has an hashtag or it scrolls all the time with the function in useEffect.

Thanks to @technicallynick Ive found a good solution:

In my "page 2" component, i just replace the url without the characters including and following the hashtag.

  useEffect(() => {
    const hashtag = window.location.hash
    if (hashtag) {
      const currentURL = window.location.href
      const newURL = currentURL.split("#")[0]
      window.history.replaceState("", "Lunch", newURL)
    }
  })

This solves my problem although feels a bit like an small hack. But I will accept this as an answer if noone else has an suggestion?

You can pass in state that your target page listens to, then use a scrollTo to scroll the browser to the target:

import React, { useLayoutEffect } from "react"
import { Link } from "gatsby"

const SomeComponent = () => (
  <Link
    to="/some/path"
    state={{ targetFragment: "scroll-to-me" }}
  />
)

const YourPageComponent = ({ location: { state: { targetFragment }}}) => {
  useScrollTo(targetFragment)

  return (
    <div>Hello, world!</div>
    <div>Hello, world!</div>
    <div id="scroll-to-me">Target Me!</div>
  )
}

const useScrollTo = id => {
  useLayoutEffect(() => {
    if (id) {
      const el = document.getElementById(id)
      const top = window.scrollY + el.getBoundingClientRect().top
      window.scrollTo({ top, behavior: "smooth" })
    }
  }, [id])
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM