Search code examples
vue.jsurlvue-routervuejs3router

Force vue 3 router to got to the same route twice - recognize it as a new event


I use vue 3

I have a view that loads components inside it. Each time you click a text, router.push is called , and loads a component, with some params

click here
<h3 @click="handleClick('intro', 'abc')" >intro</h3>  
to load component here
<router-view></router-view>

the click is handled as such

  setup(){
     
    const router = useRouter();

    const handleClick = (part, term)=>{ 
      router.push({name:part, params: {term}}).catch(err => {}); 
    } 

    return{handleClick}
    
  } 

so router.push loads in <router-view> another smaller component (named intro), according to the router of the app, that is set like so

path: '/book',
name: 'book',
component: book,
children:[
  {
    path: 'intro/:term',
    name: 'intro',
    component: Intro
  }, 
]

The component is loaded inside the view and the url is like /book/intro/abc

inside the intro component, to handle the change in the route and scroll down the abc id , I do

const route = useRoute();
let id = false; 
let mounted = ref(false);

//grab the term from route, to set it as id and if component is mounted, scroll to id
watchEffect(()=>{
  id = route.params.term; 
  let el = document.getElementById(id);
  if (mounted && el) {
    el.scrollIntoView({behavior: "smooth"});
    id = false;
  }
}) 

//check if mounted and if also id that came from route exists, scroll to id
onMounted(() => {
  mounted = true;
  let el = document.getElementById(id);
  if (id && el) { 
    el.scrollIntoView({behavior: "smooth"});
    id = false;
  }
}) 

ISSUE This works and is based on the route, to load the component and also set the id where it will scroll to.

But if I scroll to an id, then scroll randomly in the page and then click the same id to scroll, it will NOT scroll to that id again, because the id does not change, so route does not fire another event.

example : The url is /book/intro/abc. If I scroll randomly and then click the abc , url is the same, no event is fired, it will not scroll back to abc again.

How do I fix this? I want to avoid having hashtags or queries or questionmarks in my urls. Ideally I want "clean" urls like /book/part/term and I want to load that part indicated by the url, inside the view, not having all the parts loaded inside the view, as a super long text .

EDIT I also want to avoid reloads

Thanks


Solution

  • You can watch the whole route object and force the router change with the force option.

    /* In the template */
    <router-link :to="{ path: 'some-path', force: true }">link</router-link>
    
    // In the script
    const route = useRoute()
    watch(() => route, () => {
      console.log('route changed')
    }, {
      deep: true
    })