Vue-Router
Project creation
Let’s create a project
Routing components and related configurations
mian.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h= > h(App)
}).$mount('#app')
Copy the code
App.vue
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
<style>
</style>
Copy the code
Home.vue
<template>
<div class="home">
<h1>This is Home page</h1>
</div>
</template>
<script>
export default {
name: 'Home',}</script>
Copy the code
About.vue
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<script>
export default {
name: 'About',}</script>
Copy the code
The next step is to configure the router/index.js route
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '.. /views/Home.vue'
import About from '.. /views/About.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/'.name: 'Home'.component: Home
},
{
path: '/about'.name: 'About'.component:About
}
]
const router = new VueRouter({
routes
})
export default router
Copy the code
Project start
Now our goal is to code the VueRouter ourselves so that when the project is running it will have the same effect
Handwritten Vue – the Router
Documents to prepare
Now we’ve decided to create our own VueRouter, creating the my-router.js file
Let’s introduce the VueRouter and change it to our my-router.js main.js
import Vue from 'vue'
import App from './App.vue'
import router from './myRouter'// The router pointer changed
Vue.config.productionTip = false
new Vue({
router,
render: h= > h(App)
}).$mount('#app')
Copy the code
myRouter/index.js
import Vue from "vue";
import VueRouter from "./my-router";// The router constructor points to changes
import Home from ".. /views/Home.vue";
import About from ".. /views/About.vue"
Vue.use(VueRouter);
const routes = [
{
path: "/".name: "Home".component: Home,
},
{
path: "/about".name: "About".component:About
},
];
const router = new VueRouter({
routes,
});
export default router;
Copy the code
Demand analysis
To implement vue-Router, the following requirements need to be implemented:
- Vue-router is used as a plug-in, so you implement the VueRouter class and the corresponding install method
- Two components are registered globally: router-view for displaying matched components, and router-link for jumping
- Monitor URL changes: Listen for hashchange or popState events
- Create a corresponding variable, current, that retrieves and displays the corresponding component as it changes
The basic structure
Recall the steps in using vue-Router
- Install the VueRouter and pass again
import VueRouter from 'vue-router'
The introduction of - First,
const router = new VueRouter({... })
, and take router as an attribute value of the parameter,new Vue({router})
- Use (VueRouter) so that each component can have a $Router instance
So VueRouter is a constructor. And since we used vue.use (VueRouter), VueRouter must have the install method. So vue-Router will have the following basic structure
myRouter/my-router.js
class myRouter {
construct() {
}
}
myRouter.install=function(){}export default myRouter
Copy the code
Register router-view and router-link globally
Global registration components are required through Vue.component({… }) API, where the Vue constructor is required. When the plug-in is used, vue.use (VueRouter), the plug-in’s install method is executed and the Vue constructor is passed in as the first argument. We can use this incoming VUE to register components
myRouter/my-router.js
let Vue //Vue is passed in as an argument to the install method, without importing Vue from 'Vue'
class myRouter {
// Save the options
construct(options) {
this.$options=options;
}
}
myRouter.install=function(_Vue){
Vue=_Vue;/ / the Vue was introduced
// Register router-link and router-view globally
XXX this.$slot.default
Vue.component('router-link', {props: {to: {type:String.required:true}},render(h){
return h("a", {
attrs: {
href: "#" + this.to,
},
},[this.$slots.default]); }})Router-view
Vue.component('router-view', {render(h){
return h('div'.'router-view')}}}export default myRouter
Copy the code
Running results:
Add the $Router instance to the Vue component
$router=this; $router=this; Vue. Use (Router) is implemented first; there is no router instance. Unable to mount to Vue prototype chain. To solve this problem, use the mixin method:
myRouter/my-router.js
/ /... MyRouter constructor
myRouter.install=function(_Vue){
Vue=_Vue;
Vue.mixin({
beforeCreate(){
// When beforeCreate executes, the context is already the component instance
// If this is the root instance, its $options will contain the router instance
if(this.$options.router){
Vue.prototype.$router = this.$options.router; }}})/ /... Router-view and router-link are registered
Copy the code
In fact, we know that not only the root component, but every component can share the same $router.
Only the root component is processed here, the child component is not processed, you can refer to the source code. At this point, $router is available in the root component instance, and you can use this.$router in the root component
Listen for URL changes
To simplify the process, this example implements only the hash mode
let Vue
class myRouter {
constructor(options) {
this.$options = options;
Note here that this points to the myRouter instance, which needs to be bound to it
window.addEventListener('hashchange'.this.onHashchange.bind(this))
let initial=window.location.hash.slice(1) | |'/'
// Create a responsive current property so that when the current changes, the router-view will change dynamically
Vue.util.defineReactive(this.'current',initial)
}
onHashchange() {
this.current = window.location.hash.slice(1); }}Copy the code
The key to the above steps is the responsive property current. When it changes, the Router-View will also re-render to achieve the effect of spA-refresh switching routes. This also explains why vue-router is strongly dependent on VUE, because the data response is implemented through VUE
To perfect the router – the view
myRouter.install=function(_Vue){
Vue=_Vue;
Vue.mixin({
//Vue mounts the router instance
beforeCreate(){
if(this.$options.router){
Vue.prototype.$router = this.$options.router; }}})/ /... Register the router - the link
/ / improve the router - the view
Vue.component('router-view', {render(h){
// How to get the router instance
// The router instance is already mounted on the Vue instance
const {$options:{routes},current}=this.$router
// Find the component that matches the route
let component=null
const route=routes.find((item) = >{
return item.path==current
})
if(route){
component=route.component
}
return h(component)
}
})
}
Copy the code
Of course, to simplify the matching process, we can also define a routerMap for matching at initialization, so the overall code is as follows:
let Vue
class myRouter {
//1) Save options
//2) Cache path and route mappings
// Reactive data. Reactive implementation depends on Vue
// current Saves the current URL
// defineReactive Defines a reactive attribute #/about for an obj
// Monitor URL changes
constructor(options) {
this.$options = options;
// Used to match routes
this.routerMap={};//{/:{path: '/', name: 'Home', Component :{... About:}} / {path: '/ about' name: 'about', component: {... }}}
this.$options.routes.forEach((route) = >{
this.routerMap[route.path]=route
})
window.addEventListener('hashchange'.this.onHashchange.bind(this))
let initial=window.location.hash.slice(1) | |'/'
Vue.util.defineReactive(this.'current',initial)
}
onHashchange() {
// console.log(`window.location`, window.location);
// console.log(`this`,this)
this.current = window.location.hash.slice(1);
}
}
myRouter.install=function(_Vue){
Vue=_Vue;
Vue.mixin({
//Vue mounts the router instance
beforeCreate(){
if(this.$options.router){
Vue.prototype.$router = this.$options.router; }}})/ / register the router - the link
Vue.component('router-link', {props: {to: {type:String.required:true}},render(h){
return h("a", {
attrs: {
href: "#" + this.to,
},
},[this.$slots.default]);
}
})
Vue.component('router-view', {render(h){
// How to get the router instance
// console.log(`router-viewthis`,this.$options)
// console.log(`$router`,this.$router)
// const {$options:{routes},current}=this.$router
// let component=null
// const route=routes.find((item)=>{
// return item.path==current
/ /})
// if(route){
// component=route.component
/ /}
const {routerMap,current}=this.$router;
constcomponent = routerMap[current]? routerMap[current].component:null
returnh(component); }})}export default myRouter
Copy the code
View switch successful!!