SPA(Single Page Application) : a single page application that has only one complete page and does not load the entire page when loaded. When the route changes, it listens for the route change and does not request the page, but only updates the view. Routing describes the mapping between URL and UI, that is, URL changes cause UI updates (without page refresh). VueRouter is provided in the Vue ecosystem to implement single-page front-end routing. There are two common modes for VueRouter: Hash mode and History mode.
Hash pattern
VueRouter default hash mode. Hash is the hash (#) and the following part of the URL. It is used as an anchor to navigate through the page. Changing the HASH in the URL will not be reloaded by the browser. Hash (#) is just a guide to the browser. It is not included in the HTTP request and therefore does not reload the page. The principle of hash mode is to listen for URL changes through the onHashchange event.
The History mode
The history mode takes advantage of HTML5 History’s new pushState() and replaceState() methods and popState events. [Fixed] PopState events are triggered when urls are changed forward or backward via the browser. However, changing the URL with pushState/replaceState or tags does not trigger a PopState event. In addition to the back, Forward, and Go methods, pushState/replaceState also provides the ability to modify the history. However, a request is not sent to the server immediately after the URL is changed.
When you use the history mode, URL like normal URL, for example, http://localhost:8080/about, but this model also need background configuration support. Because our application is a single page of the client application, if there is no correct configuration, the background when the user browser will return 404 direct access to http://localhost:8080/about. So, server Y adds a candidate resource that covers all cases: if the URL doesn’t match any static resource, it should return the same index.html page that your app relies on.
A simple version of the VueRouter implementation
Using the analysis
First let’s look at how the VueRouter is used
- Install the VueRouter through
import VueRouter from 'vue-router'
Use (VueRouter) to make it possible for each component to have store instances
import VueRouter from 'vue-router'
Vue.use(VueRouter)
Copy the code
- Create Router instance, router.js
.const router = new VueRouter({
routes
})
export default router
Copy the code
- Add the instance, main.js, to the root component
import router from './router'
new Vue({
router,
render: h= > h(App)
}).$mount('#app')
Copy the code
- Add routing view, app.vue
<router-view />
Copy the code
- navigation
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<router-link to="/about2">About2</router-link>
Copy the code
Demand analysis
Based on the above usage, we need to implement:
- Implement the VueRouter class and install method.
- Global components: Router-view displays matched components. Router-link redirects components.
- Monitor URL changes: Listen for hashchange or popState events.
- Create a reactive property current that retrieves and displays the corresponding component as it changes.
Create router files and other files in the root directory:
router
|-- index.js
|-- router-link.js
|-- router-view.js
`-- vue-router.js
Copy the code
VueRouter class and install method
// router/vue-router.js
import Link from './router-link'
import View from './router-view'
let Vue
class VueRouter {
constructor (options) {
this.$options = options
// Make use of defineReactive provided by Vue to be reactive. When current changes, dependent components are rerender
Vue.util.defineReactive(this.'current'.'/')
// Monitor URL changes
window.addEventListener('hashchange'.this.onHashChange.bind(this))
window.addEventListener('load'.this.onHashChange.bind(this))
// Create a routing mapping table
this.routeMap = {}
options.routes.forEach(route= > {
this.routeMap[route.path] = route
})
}
onHashChange () {
this.current = window.location.hash.slice(1)
}
}
VueRouter.install = function (_Vue) {
Vue = _Vue
Vue.mixin({
beforeCreate () {
// Ensure that the root instance is executed
if (this.$options.router) {
Vue.prototype.$router = this.$options.router
}
}
})
Vue.component('router-link', Link)
Vue.component('router-view', View)
}
export default VueRouter
Copy the code
The router – link component
// router/router-link.js
export default {
props: {
to: {
type: String.required: true
}
},
render (h) {
return h('a', { attrs: { href: The '#' + this.to } }, this.$slots.default)
// return <a href={'#' + this.to}>{this.$slots.default}</a>}}Copy the code
Routor – the view components
// router/router-view.js
export default {
render (h) {
// Get the component corresponding to path
const { routeMap, current } = this.$router
const component = routeMap[current].component || null
return h(component)
}
}
Copy the code
Instantiate the Router
// router/index.js
import Vue from 'vue'
import VueRouter from './vue-router'
import Home from '.. /views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/'.name: 'Home'.component: Home
},
{
path: '/about'.name: 'About'.component: () = > import(/* webpackChunkName: "about" */ '.. /views/About.vue')}, {path: '/about2'.name: 'About2'.component: () = > import(/* webpackChunkName: "about2" */ '.. /views/About2.vue')}]const router = new VueRouter({
routes
})
export default router
Copy the code