0.13.1 • Published 5 years ago

vue-stateful-router v0.13.1

Weekly downloads
3
License
MIT
Repository
github
Last release
5 years ago

vue-stateful-router

A vue router with the power of history.state

Constructor

HashRouter

import Vue from 'vue'
import { HashRouter } from 'vue-stateful-router'

Vue.use(HashRouter)

// define routes
const routes = [
  // see examples below
]

const router = new HashRouter({ routes })

const app = new Vue({
  router,
  template: `
    <div id="app">
      <router-view />
    </div>
  `,
  // ...
}).$mount()

document.body.appendChild(app.$el)
router.start()

PathRouter

PathRouter is similar to HashRouter, but has a base option. base defines the base path of the app.

import Vue from 'vue'
import { PathRouter } from 'vue-stateful-router'

Vue.use(PathRouter)

const routes = [
  //...
]

const router = new PathRouter({
  routes,

  // default: ''
  // If you want the root path doesn't contain ending slash,
  // you can set the base without ending slash, like '/app'
  base: '/app/'
})

Routes Definition

For example, this is our root element:

<div id="app">
  <router-view name="aside">
  <router-view />
</div>

The <router-view> is a functional component that renders the matched component.

It has a name property. The default value is default.

Let's see the example routes definition:

const routes = [
  // define which component will be mounted into <router-view name="aside">
  {
    name: 'aside',
    component: { /* component definition */ }
  },

  // the default <router-view>
  { path: '/basic', component: { /* component definition */ } },

  // return promise to define async components
  { path: '/async', component: () => import('./AsyncComponent.vue') },

  {
    path: '/prop',

    // pass some props to the component
    props: { foo: 'hello' },

    component: {
      props: ['foo'],
      // ...
    }
  },

  {
    // use : to define params
    path: '/article/:id',

    // props can be a factory function, it receives the current route object as the first argument.
    // see route object definition below to see what info can get.
    props: route => ({
      articleId: route.params.int('id'),
      foo: route.query.string('foo'),
      bar: route.state.bar
    }),

    component: {
      props: ['articleId', 'foo', 'bar'],
      // ...
    }
  },

  {
    // path can be RegExp
    path: /^\/regex\/(\d+)$/,
    component: VFoo,
    // the subexpressions are stored as $1, $2, ...
    props: route => ({ foo: route.params.int('$1') })
  },

  {
    path: '/route-test',

    // only matched if test() returns true
    test(to, from, op) {
      return true
    },

    component: VFoo,
  },

  // define hooks
  {
    path: '/login',

    // beforeEnter hook will be called before confirming the navigation.
    // see router.beforeChange below for details
    beforeEnter(to, from, operation) {

    },

    component: {
      // in-component beforeRouteLeave hook
      // will be called before route leave
      beforeRouteLeave(to, from) {

      },

      // ...
    }
  },


  // use Array to group <router-view> definitions
  [
    // in this group, this aside component will override the default aside <router-view> definition
    {
      name: 'aside',
      component: { /* ... */}
    },

    {
      // in this layout, the default <router-view> will mount a component that has nested <router-view>s
      component: {
        props: ['activeTab'],

        // define two child <router-view>s
        template: `
          <router-view />
          <router-view name="footer" />
        `
      },

      // define some meta
      meta: { activeTab: 'main' },

      // route.meta.activeTab is "foo" when path is "/foo"
      props: route => ({ activeTab: route.meta.activeTab })

      // define child <router-view>s
      children: [
        {
          path: '/foo',
          component: { /* ... */ },

          // parent route meta and child route meta will be merged together
          // if child route meta has same keys as parent, it will override parent ones.
          meta: { activeTab: 'foo' }
        },

        {
          path: '/bar',
          component: { /* ... */},

          // meta can be a factory function, the first argument is the current route object
          meta: route => ({ activeTab: route.query.string('active') })
        },

        // define a catch-all route
        // it must be put at the last of all routes definition
        {
          path: '*',
          component: {
            template: '<h1>404 Not Found</h1>'
          }
        }
      ]
    }
  ]
]

Route Object

A route object contains the information of the matched route. It can be get from route hooks, router.beforeChange(), router.afterChange(), vm.$root.$route, router.current, etc.

{
  path, // router internal path, which has stripped the protocol, host, and base path.
  query, // StringCaster object. https://github.com/jiangfengming/cast-string#stringcaster
  hash, // url hash
  fullPath, // path + query + hash

  // PathRouter: base + path + query + hash
  // HashRouter: '#' + path + query + hash
  url,

  state, // state object
  params, // StringCaster object. https://github.com/jiangfengming/cast-string#stringcaster
  meta // meta collected from route definition
}

Location Object

A location object is used for changing the current address. It can be used in <router-link>, router.push(), router.replace(), router.dispatch(), etc.

{
  path,
  query,
  hash,
  fullPath,
  url,
  state,
  hidden // Boolean. Indicate whether it is a hidden history entry. see history.push() for detail.
}

<router-link>

The <router-link> is a navigation component, it usally renders an <a> element.

Props

to: Location object, or path/fullPath of Location object.

tag: The HTML tag to render. Default: <a>.

action: push, replace or dispatch. Default: push.

APIs

Mose of the APIs are proxied to spa-history.

In the vue instance, you can get the router object from this.$router.

router.current

The current active route object.

router.start(URL string | location)

Start the router.

In browser, if URL/location is not given, the default value is the current address. This argument is mainly for server-side rendering.

router.normalize(URL string | location)

convert the URL string or unnormalized location object to normalized object

if URL/location.path is started with protocal, or location.external is true, location.path is treated as an external path, and will be converted to an internal path.

// PathRouter with base '/foo/bar/'
router.normalize('http://www.example.com/foo/bar/home?a=1#b')
/*
  {
    path: '/home',
    query: new StringCaster(new URLSearchParams('a=1')),
    hash: '#b',
    fullPath: '/home?a=1#b',
    state: {}
  }
*/

// same result as above
router.normalize({
  path: '/foo/bar/home?a=1#b',
  external: true
})

// same result as above
router.normalize('/home?a=1#b')

// same result as above
router.normalize({
  path: '/home',
  query: {
    a: 1
  },
  hash: '#b'
})

// HashRouter
// same result as above
router.normalize('http://www.example.com/app/#/home?a=1#b')

The query property can be of type Object, String and Array. see URLSearchParams() for detail.

router.url(URL string | location)

Convert the internal URL string or location object to an external URL which can be used in href attribute of <a>.

router.url({
  path: '/home',
  query: {
    a: 1
  },
  hash: '#b'
})

// or
router.url('/home?a=1#b')

/*
  result:
  HashRouter: #/home?a=1#b
  PathRouter(with base: '/foo/bar/'): /foo/bar/home?a=1#b
*/

router.push(URL string | location)

Counterpart of window.history.pushState(). Push the location onto the history stack. beforeChange will be called.

router.push('/home?a=1#b')

router.push({
  path: '/home',
  query: {
    a: 1
  },
  hash: '#b'
})

// PathRouter, complete URL
router.push('http://www.example.com/foo/bar/home?a=1#b')

// HashRouter, complete URL
router.push('http://www.example.com/#/home?a=1#b')

You can push a location with state.

router.push({
  path: '/home',
  state: {
    foo: 1,
    bar: 2
  }
})

And you can push a hidden location, which will not change the value of browser's address bar. the hidden location is stored in window.history.state

router.push({
  path: '/login',
  state: {
    foo: 1
  },

  // '/login' won't show in the location bar
  hidden: true,

  // optional. if set, the location bar will show this address instead
  appearPath: '/buy'
})

router.replace(URL string | location)

Counterpart of window.history.replaceState(). Replace the current history entry with the location.

router.dispatch(URL string | location)

Dispatch the route without changing the history session. That is, the location of browser's address bar won't change.

router.setState(state)

Set state of the current route. the state will be merged into router.current.state

router.go(position, { silent = false, state = null } = {})

Counterpart of window.history.go(). Returns a promise which will be resolved when popstate event fired.

silent: if true, beforeChange won't be called.

state: if set, the state object will be merged into the state object of the destination location.

router.back(options)

Same as router.go(-1, options)

router.forward(options)

Same as router.go(1, options)

router.captureLinkClickEvent(e)

Prevent the navigation when clicking the <a> element in the container and the href is an in-app address, router.push() will be called instead.

<div @click="$router.captureLinkClickEvent($event)">
  <a href="/foo">foo</a>
</div>

router.beforeChange(callback)

Add a global beforeChange callback. The callback will be called before confirming the navigation.

Arguments:
  to: Route Object. The location will be changed to.
  from: Route Object. The current location.
  operation:
    push: router.push() is called.
    replace: router.replace() is called.
    init: "to" is the initial page, at this stage, "from.path" is null.
    popstate: user clicked the back or foraward button , or router.go(), router.back(), router.forward() is called.
    dispatch: router.dispatch() is called.

Returns:
  true | undefined: The navigation is confirmed.
  false: Prevent the navigation.
  null: Do nothing.
  location: Redirect to this location.
            You can override the history manipulate action by providing location.action property, values are: 'push', 'replace', 'dispatch'.

Return value can be a Promise.
router.beforeChange((to, from, operation) => {
  // ...
})

router.afterChange(callback)

Add a global afterChange callback. The callback will be called after history has been changed but before async components have been loaded.

Returning false can prevent to load the new page.

router.afterChange((to, from) => {
  // if our SPA has been updated
  if (outdated()) {
    location.reload()
    return false
  }
})

router.onError(callback)

Add a global error callback. The callback will be called when loading async components failed.

router.onError(error => {
  // ...
})

Dependencies

You can use @babel/polyfill and dom4 to meet the requirements.

Or use the polyfill.io service:

<script src="https://polyfill.io/v3/polyfill.min.js"></script>

Example

npm run example

Build

npm run build

License

MIT

0.13.1

5 years ago

0.13.0

5 years ago

0.12.1

5 years ago

0.12.0

5 years ago

0.11.4

5 years ago

0.11.3

5 years ago

0.11.2

5 years ago

0.11.1

5 years ago

0.11.0

5 years ago

0.10.2

5 years ago

0.10.1

5 years ago

0.10.0

5 years ago

0.9.0

5 years ago

0.8.2

5 years ago

0.8.1

5 years ago

0.8.0

5 years ago

0.7.0

6 years ago

0.6.1

6 years ago

0.6.0

6 years ago

0.5.9

6 years ago

0.5.8

7 years ago

0.5.7

7 years ago

0.5.6

7 years ago

0.5.5

7 years ago

0.5.4

7 years ago

0.5.3

7 years ago

0.5.2

7 years ago

0.5.1

7 years ago

0.5.0

7 years ago

0.4.8

7 years ago

0.4.7

7 years ago

0.4.6

7 years ago

0.4.5

7 years ago

0.4.4

7 years ago

0.4.3

7 years ago

0.4.2

7 years ago

0.4.1

7 years ago

0.4.0

7 years ago

0.3.0

7 years ago

0.2.1

7 years ago

0.2.0

7 years ago

0.1.2

7 years ago

0.1.1

7 years ago

0.1.0

7 years ago

0.1.0-dev.2

7 years ago

0.1.0-dev.1

7 years ago

0.1.0-dev.0

8 years ago