SoFunction
Updated on 2025-04-11

How to write a simple Vue Router

Preface

Still the same, if you know how to use a common library, you also need to understand its principles or how to simulate and implement it. Today, you will implement vue-router.

I mentioned some knowledge in this article, so I won't write it step by step here. Please see meHandwritten a simple Vuex

Basic skeleton

  • The way to use plugins in Vue is(plugin), here is the usage of it:

Install the plugin. If the plugin is an object, the install method must be provided. If the plugin is a function, it will be used as the install method. When the install method is called, Vue will be passed in as a parameter. The first parameter of this method is the Vue constructor, and the second parameter is an optional option object.

  • Global mixing

use(mixin)

Global registration is a mixed in, affecting every Vue instance created after registration. You can use blending to inject custom behavior into components, which will affect each Vue instance created later.

  • Routing usage

For example, simple:

//Route arrayconst routes = [
 {
  path: '/',
  name: 'Page1',
  component: Page1,
 },
 {
  path: '/page2',
  name: 'Page2',
  component: Page2,
 },
]

const router = new VueRouter({
 mode: 'history', // model routes,
})

It's passed inmodeandroutesWhen we realize it, we need toVueRouterReceived in the constructor.

When using routing titles:

<p>
 <!-- use router-link Components to Navigate. -->
 <!-- By passing `to` Properties specify link. -->
 <!-- <router-link> By default it will be rendered into one `<a>` Label -->
 <router-link to="/page1">Go to Foo</router-link>
 <router-link to="/page2">Go to Bar</router-link>
</p>
<!-- Routing exit -->
<!-- The component that the route matches will be rendered here -->
<router-view></router-view>

Therefore we need to use( id, [definition] )Register a global component.

After understanding the general situation, we can write a basic skeleton

let Vue = null

class VueRouter {
 constructor(options) {
   =  || 'hash'
   =  || []
 }
}

 = function (_Vue) {
 Vue = _Vue

 ({
  beforeCreate() {
   // Root component   if (this.$options && this.$) {
    this._root = this // Save the current vue instance to _root    this._router = this.$ // Mount the router instance on _router   } else if (this.$parent && this.$parent._root) {
    // For child components, inherit the instance of the parent component and let all components share a router instance    this._root = this.$parent && this.$parent._root
   }
  },
 })

 ('router-link', {
  props: {
   to: {
    type: [String, Object],
    required: true,
   },
   tag: {
    type: String,
    default: 'a', // router-link is rendered to a tag by default   },
  },
  render(h) {
   let tag =  || 'a'
   return <tag href={}>{this.$}</tag>
  },
 })

 ('router-view', {
  render(h) {
   return h('h1', {}, 'Where the view is displayed') // Temporarily set it to h1 tag, it will be changed below  },
 })
}

export default VueRouter

mode

vue-routerThere are two modes, and the default is hash mode.

history mode

pass Add browser history and listen throughpopStateEvents, that is, listen for changes in history to load the corresponding content.

  • popstate event

The popstate event is triggered when the activity history entry changes. If the activated history entry is created by a call to () or is affected by a call to (), the state property of the popstate event contains a copy of the state object of the history entry.

  • ()method

(state, title, url)

This method is used to add a record in the history and receive three parameters, in turn:

  • state: A state object associated with the added record, mainly used for popstate events. When this event is fired, the object is passed into the callback function. In other words, the browser will serialize the object and keep it locally. When reloading this page, you can get the object. If this object is not needed, you can fill in null here.
  • title: The title of the new page. However, all browsers now ignore this parameter, so you can fill in the blank string here.
  • url: The new URL must be in the same domain as the current page. The browser's address bar will display this URL.

hash mode

Use the hash of the URL to simulate a complete URL. , listen for hashchange event, and then load the corresponding content according to the hash value (can be read through attributes).

Continue to add code,

let Vue = null

class HistoryRoute {
 constructor() {
   = null // Current path }
}

class VueRouter {
 constructor(options) {
   =  || 'hash'
   =  || []
   = ()
   = new HistoryRoute() // Current route  () // Initialize the routing function }

 createMap(routes) {
  return ((pre, current) => {
   pre[] = 
   return pre
  }, {})
 }

 initRoute() {
  if ( === 'hash') {
   // First determine whether the user has a hash value when opening it. If not, jump to #/    ? '' : ( = '/')
   ('load', () => {
     = (1)
   })
   ('hashchange', () => {
     = (1)
   })
  } else {
   // history mode    ? '' : ( = '/')
   ('load', () => {
     = 
   })
   ('popstate', () => {
     = 
   })
  }
 }
}

 = function (_Vue) {
 Vue = _Vue

 ({
  beforeCreate() {
   if (this.$options && this.$) {
    this._root = this
    this._router = this.$
    (this, '_route', this._router.history) // Listen to history path changes   } else if (this.$parent && this.$parent._root) {
    this._root = this.$parent && this.$parent._root
   }
   // Return the router instance when accessing this.$router   (this, '$router', {
    get() {
     return this._root._router
    },
   })
   // When accessing this.$route, the current page routing information is returned   (this, '$route', {
    get() {
     return this._root._router.
    },
   })
  },
 })
}

export default VueRouter

router-link and router-view components

 = function (_Vue) {
 Vue = _Vue

 ('router-link', {
  props: {
   to: {
    type: [String, Object],
    required: true,
   },
   tag: {
    type: String,
    default: 'a',
   },
  },
  methods: {
   handleClick(event) {
    // Prevent the default jump of a tag    event &&  && ()
    let mode = this._self._root._router.mode
    let path = 
    this._self._root._router. = path
    if (mode === 'hash') {
     (null, '', '#/' + (1))
    } else {
     (null, '', (1))
    }
   },
  },
  render(h) {
   let mode = this._self._root._router.mode
   let tag =  || 'a'
   let to = mode === 'hash' ? '#' +  : 
   ('render', )
   return (
    <tag on-click={} href={to}>
     {this.$}
    </tag>
   )
   // return h(tag, { attrs: { href: to }, on: { click:  } }, this.$)
  },
 })

 ('router-view', {
  render(h) {
   let current = this._self._root._router. // Current is already a dynamic response   let routesMap = this._self._root._router.routesMap
   return h(routesMap[current]) // Dynamic rendering of corresponding components  },
 })
}

At this point, a simple vue-router has been implemented, and the complete code of the case is attached:

let Vue = null

class HistoryRoute {
 constructor() {
   = null
 }
}

class VueRouter {
 constructor(options) {
   =  || 'hash'
   =  || []
   = ()
   = new HistoryRoute() // Current route  // Initialize the routing function  ()
 }

 createMap(routes) {
  return ((pre, current) => {
   pre[] = 
   return pre
  }, {})
 }

 initRoute() {
  if ( === 'hash') {
   // First determine whether the user has a hash value when opening it. If not, jump to #/    ? '' : ( = '/')
   ('load', () => {
     = (1)
   })
   ('hashchange', () => {
     = (1)
   })
  } else {
   // history mode    ? '' : ( = '/')
   ('load', () => {
     = 
   })
   ('popstate', () => {
     = 
   })
  }
 }
}

 = function(_Vue) {
 Vue = _Vue

 ({
  beforeCreate() {
   // Root component   if (this.$options && this.$) {
    this._root = this // Save the current vue instance to _root    this._router = this.$ // Mount the router instance on _router    (this, '_route', this._router.history) // Listen to history path changes   } else if (this.$parent && this.$parent._root) {
    // For child components, inherit the instance of the parent component and let all components share a router instance    this._root = this.$parent && this.$parent._root
   }
   // Return the router instance when accessing this.$router   (this, '$router', {
    get() {
     return this._root._router
    },
   })
   // When accessing this.$route, the current page routing information is returned   (this, '$route', {
    get() {
     return this._root._router.
    },
   })
  },
 })

 ('router-link', {
  props: {
   to: {
    type: [String, Object],
    required: true,
   },
   tag: {
    type: String,
    default: 'a',
   },
  },
  methods: {
   handleClick(event) {
    // Prevent the default jump of a tag    event &&  && () // Prevent the default jump of a tag    let mode = this._self._root._router.mode
    let path = 
    this._self._root._router. = path
    if (mode === 'hash') {
     (null, '', '#/' + (1))
    } else {
     (null, '', (0))
    }
   },
  },
  render(h) {
   let mode = this._self._root._router.mode
   let tag =  || 'a'
   let to = mode === 'hash' ? '#' +  : 
   return (
    <tag on-click={} href={to}>
     {this.$}
    </tag>
   )
   // return h(tag, { attrs: { href: to }, on: { click:  } }, this.$)
  },
 })

 ('router-view', {
  render(h) {
   let current = this._self._root._router. // Current is already dynamic   let routesMap = this._self._root._router.routesMap
   return h(routesMap[current]) // Dynamic rendering of corresponding components  },
 })
}

export default VueRouter

ps: Personal Technology Blog Github Repository, if you think it's good, welcome star, give me some encouragement and continue writing ~

The above is the detailed content of how to write simple Vue Router. For more information about simple Vue Router, please follow my other related articles!