import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) const Home = { template: '<div class="home">home</div>' } const Foo = { template: '<div class="foo">foo</div>' } const Bar = { template: ` <div class="bar"> bar <div style="height:1500px"></div> <p id="anchor" style="height:500px">Anchor</p> <p id="anchor2" style="height:500px">Anchor2</p> <p id="1number">with number</p> </div> ` } // scrollBehavior: // - only available in html5 history mode // - defaults to no scroll behavior // - return false to prevent scroll const scrollBehavior = function (to, from, savedPosition) { if (savedPosition) { // savedPosition is only available for popstate navigations. return savedPosition } else { const position = {} // scroll to anchor by returning the selector if (to.hash) { position.selector = to.hash // specify offset of the element if (to.hash === '#anchor2') { position.offset = { y: 100 } } // bypass #1number check if (/^#\d/.test(to.hash) || document.querySelector(to.hash)) { return position } // if the returned position is falsy or an empty object, // will retain current scroll position. return false } return new Promise(resolve => { // check if any matched route config has meta that requires scrolling to top if (to.matched.some(m => m.meta.scrollToTop)) { // coords will be used if no selector is provided, // or if the selector didn't match any element. position.x = 0 position.y = 0 } // wait for the out transition to complete (if necessary) this.app.$root.$once('triggerScroll', () => { // if the resolved position is falsy or an empty object, // will retain current scroll position. resolve(position) }) }) } } const router = new VueRouter({ mode: 'history', base: __dirname, scrollBehavior, routes: [ { path: '/', component: Home, meta: { scrollToTop: true }}, { path: '/foo', component: Foo }, { path: '/bar', component: Bar, meta: { scrollToTop: true }} ] }) new Vue({ router, template: ` <div id="app"> <h1>Scroll Behavior</h1> <ul> <li><router-link to="/">/</router-link></li> <li><router-link to="/foo">/foo</router-link></li> <li><router-link to="/bar">/bar</router-link></li> <li><router-link to="/bar#anchor">/bar#anchor</router-link></li> <li><router-link to="/bar#anchor2">/bar#anchor2</router-link></li> <li><router-link to="/bar#1number">/bar#1number</router-link></li> </ul> <transition name="fade" mode="out-in" @after-leave="afterLeave"> <router-view class="view"></router-view> </transition> </div> `, methods: { afterLeave () { this.$root.$emit('triggerScroll') } } }).$mount('#app')