DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Top 5 Gantt Chart Libraries for Vue.js
  • Building Enterprise-Grade Real-Time IoT Dashboards with Vue 3, MQTT, and Kafka
  • SelfService HR Dashboards with Workday Extend and APIs
  • How We Reduced LCP by 75% in a Production React App

Trending

  • From 24 Hours to 2 Hours: How We Fixed a Broken BI System With Apache Airflow
  • Building AI-Powered Java Applications With Jakarta EE and LangChain4j
  • Building Threat Intelligence Pipelines Using Python, APIs, and Elasticsearch
  • How to Parse Large XML Files in PHP Without Running Out of Memory
  1. DZone
  2. Coding
  3. JavaScript
  4. Don't Forget Browser Button UX In Your Vue.js App

Don't Forget Browser Button UX In Your Vue.js App

A Vue.js whiz explains how to create different kinds of browser navigation using this powerful JavaScript framework. Read on for more!

By 
Anthony Gore user avatar
Anthony Gore
·
Updated Feb. 10, 20 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
10.9K Views

Join the DZone community and get the full member experience.

Join For Free

when building single-page applications many vue developers forget about ux for browser button navigation. they mistakenly assume that this kind of navigation is the same as hyperlink navigation when in fact it can be quite different.

unlike hyperlink navigation, if a user goes forward and back between pages they expect the page to still look like it did when they return or they'll consider the ux "weird" or "annoying."

for example, if i were browsing a thread on hacker news and i scroll down to a comment and collapse it, then i clicked through to another page, then i clicked "back," i'd expect to still be scrolled down to the comment and for it to still be collapsed!

image title

in a vue.js app, though, this is not the default behavior; scroll position and app data are not persisted by default. we need to consciously set up our app to ensure we have a smooth and predictable ux for the browser navigation buttons.

configuring vue router

vue router's role in the optimal back and forward ux is in controlling scroll behavior . a user's expectations with this would be:

  • when moving back and forward, return to the previous scroll position.
  • when navigating by links, scroll to the top.

we can achieve this by adding a scrollbehavior callback to our router configuration. note that savedposition is made available when using the browser back and forward buttons and not when using hyperlinks.

const scrollbehavior = (to, from, savedposition) => {
  if (savedposition) {
    return savedposition
  } else {
      position.x = 0
      position.y = 0
    }
    return position
  }
}

const router = new vuerouter({
  mode: 'history',
  scrollbehavior,
  routes: []
})

more comprehensive scroll behavior settings can be found in this example .

state persistence

even more critical than scroll behavior is persisting the state of the app. for example, if a user makes a selection on page 1, then navigates to page 2, then back to page 1, they expect the selection to be persisted.

in the naive implementation below, foo 's checked state will not persist between route transitions. when the route changes, vue destroys foo and replaces it with home , or vice versa. as we know with components, the state is created freshly on each mount.

const foo = vue.component('foo', {
  template: '<div @click="checked = !checked">{{ message }}</div>',
  data () {
    return { checked: false }; 
  }
  computed: {
    message() {
      return this.checked ? 'checked' : 'not checked';
    }
  }
});

const router = new vuerouter({
  mode: 'history',
  scrollbehavior,
  routes: [
    { path: '/', component: home },
    { path: '/bar', component: foo }
  ]
});

this would be equivalent to uncollapsing all the comments you collapsed in hacker news when you navigate back to an article's comments, i.e. very annoying!

keep-alive

the special keep-alive component can be used to alleviate this problem. it tells vue not to destroy any child components when they're no longer in the dom, but instead, keep them in memory. this is useful not just for a route transition, but even when v-if takes a component in and out of a page.

<div id="app">
  <keep-alive>
    <router-view></router-view>
  </keep-alive>
</div>

the advantage of using keep-alive is that's it's very easy to setup; it can be simply wrapped around a component and it works as expected.

vuex

there's a scenario where keep-alive will not be sufficient: what if the user refreshes the page or clicks back and forward to another website? the data would be wiped and we're back to square one. a more robust solution than keep-alive is to use the browser's local storage to persist component state.

since html5, we've been able to use the browser to store a small amount of arbitrary data. the easiest way to do this is to first set up a vuex store. any data that needs to be cached between route transitions or site visits go in the store. later we will persist it to local storage.

let's now modify our example above to use vuex to store foo 's checked state:

const store = new vuex.store({
  state: {
    checked: false
  },
  mutations: {
    updatechecked(state, payload) {
      state.checked = payload;
    }
  }
});

const foo = vue.component('foo', {
  template: '<div @click="checked">{{ message }}</div>',
  methods: {
    checked() {
      this.$store.commit('updatechecked', !this.$store.state.checked);
    }
  },
  computed: {
    message() {
      return this.$store.state.checked ? 'checked' : 'not checked';
    }
  }
});

we can now get rid of the keep-alive as changing the page will no longer destroy the state information about our component as vuex persists across routes.

local storage

now, every time the vuex store is updated, we want to store a snapshot of it in local storage. then when the app is first loaded we can check if there's any local storage and use it to seed our vuex store. this means that even if we navigate to another url we can persist our state.

fortunately, there's a tool for this already: vuex-localstorage . it's really easy to setup and integrate into vuex. below is everything you need to get it to do what was just described:

import createpersist from 'vuex-localstorage';

const store = new vuex.store({
  plugins: [ createpersist({
    namespace: 'test-app',
    initialstate: {},
    expires: 7 * 24 * 60 * 60 * 1000
  }) ],
  state: {
    checked: false
  },
  mutations: {
    updatechecked(state, payload) {
      state.checked = payload;
    }
  }
});

back and forward ux vs. hyperlink ux

you may want to differentiate behavior between the back and forward navigation and hyperlink navigation. we expect data in the back and forward navigation to persist, while in hyperlink navigation it should not.

for example, returning to hacker news, a user would expect comment collapse to be reset if you navigate with hyperlinks back to the front page and then back into a thread. try it for yourself and you'll notice this subtle difference in your expectation.

in a vue app, we can simply add a navigation guard to our home route where we can reset any state variables:

const router = new vuerouter({
  mode: 'history',
  scrollbehavior,
  routes: [
    { path: '/', component: home, beforeenter(to, from, next) {
      store.state.checked = false;
      next();
    } },
    { path: '/bar', component: foo }
  ]
});
app Vue.js

Published at DZone with permission of Anthony Gore. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Top 5 Gantt Chart Libraries for Vue.js
  • Building Enterprise-Grade Real-Time IoT Dashboards with Vue 3, MQTT, and Kafka
  • SelfService HR Dashboards with Workday Extend and APIs
  • How We Reduced LCP by 75% in a Production React App

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook