1, Vue router needs to realize the following functions:
1. vue plug-in:
vue plug-in will call vue The use () method receives a parameter. If the passed parameter is a function, call the function directly; If it is an object, the install method of the object is called. And pass in the vue instance
2. Instance objects router and route
When initializing the Vue instance, the router is passed in, and the Vue instance will generate $route and $router attributes: $route stores the current routing rules and $router stores the routing instance object. You can call some routing related methods.
3. The two components are router view and router link
4. Dynamic routing
cosnt routes = [ { // Use dynamic routing path: '/detail/:id', name: 'Detail', // When props is enabled, the parameters in the URL will be passed to the component // Receive URL parameters through props in the build props: true, // Route lazy loading component: () => import('../views/Detail.vue') } ]
5. Routing parameters
① Obtain data through the current routing rule {{ $route.params.id }},This method strongly depends on routing. When using components, there must be a route to pass parameters. ② Enable in routing rule props ,Routing will URL The parameters in are passed to the corresponding component, and the component receives this parameter props It's OK. This is the same way that parent-child components pass values. It no longer depends on routing. props: ['id']
6. Nested routing
cosnt routes = [ // Nested Route { path: '/', component: Layout, children: [ { path: '', name: 'Index', component: Index }, { // Path can use either a relative path or an absolute path // path: '/detail/:id', path: 'detail/:id', name: 'Detail', props: true, component: () => import('../views/Detail.vue') } ] } ]
7. Programming navigation
this.$router.replace('/login') , This history will not be recorded this.$router.push({ name: 'Detail', params: { id: 1 } }) this.$router.go(-2),If incoming-1,Equivalent to this.$router.back()
2, Hash mode and History mode
1. Differences between Hash mode and History mode:
Differences in manifestations:
The Hash mode has #, and the Hash number is followed by the routing address
The History mode is an ordinary URL, which needs to be supported by the server
Principle difference:
The Hash pattern is based on anchor points and onhashchange events
The History pattern is based on the History API in HTML5
history. Pushstate(), which can only be supported after ie10 (no request will be sent, but the routing address will be changed and recorded in the history)
history.replaceState()
2. History mode
The server should return the index of the single page application except for static resources html
When clicking a hyperlink:
Click the hyperlink to call history Pushstate() changes the address in the browser's address bar, but does not send a request and stores the address in the history. These are done on the client.
When refreshing the browser:
The browser sends a request to the server. The requested address is the address in the address bar. If the server does not process this address, an error will occur; If the server supports History, when the server judges that the current routing address does not exist, it will index the first page of the single page application Html is returned to the browser. After receiving the page, the browser determines the routing address, and then loads the corresponding component content for rendering
Three. Simulation implementation of Vue Router
1. Vue pre knowledge:
Plug in, mixed in, Vue Observable (), slot, render function, runtime, and full version of Vue
2. Implementation principle of Vue Router
Hash mode:
① The # following content in the URL is used as the path address. If only the # following address is changed, the browser will not send a request and will record this address in the browser access history;
② Listen for hashchange events. When the hash is changed, the hashchange event will be triggered and the current routing address will be recorded;
③ Find the corresponding component according to the current routing address and re render.
History mode:
① Through history The pushstate () method changes the address bar, only changes the address and records the routing address without sending a request
② By listening to the pop state event, you can listen to the changes of the browser operation and record the changed address. It will not be triggered when calling pushState or replaceState. The browser's forward and backward buttons or back and forward methods will be triggered
③ Find the corresponding component according to the current routing address and re render
3. Vue Router use case code
// Register plug-ins // Vue.use() internally calls the install method of the incoming object Vue.use(VueRouter) // Create routing object const router = new VueRouter({ routes: [ { name: 'home', path: '/', component: homeComponent } ] }) // Create a Vue instance and register the router object new Vue({ router, render: h => h(App) }).$mount('#app')
4. Realization idea
① Create a vueroter plug-in and use the static method install
Determine whether the plug-in has been loaded
When Vue is loaded, mount the incoming router object on the Vue instance (Note: it is executed only once)
② Create vueroter class
Initialization, options, routeMap, data (simplify operation, create Vue instance as responsive data record current path)
Create a routing map, traverse all routing information, and record the mapping of components and routes in the routeMap object
Create router link and router view components
When the path changes, find the corresponding component in the routerMap object through the current path and render the router view
Register the pop state, hashchange and load events. When the routing address changes, re record the current path
5. Code implementation
① Create vueroter plug-in
static install (Vue) { // When this method is called, the Vue constructor is passed in // 1. Determine whether the current plug-in has been installed if (VueRouter.install.installed) return VueRouter.install.installed = true // 2. Record the Vue constructor to a global variable _Vue = Vue // 3. Inject the router object passed in when creating the Vue instance into the Vue instance // Mixed in, all Vue instances and components will execute this method _Vue.mixin({ beforeCreate() { if (this.$options.router) { // This attribute is only available in the Vue instance option, and the component does not _Vue.prototype.$router = this.$options.router // Initialization component, routing map and event registration are implemented in sections 3, 4 and 5 this.$options.router.init() } } }) }
② Implementation constructor
constructor (options) { // Initialize three properties this.options = options this.routeMap = {} this.data = _Vue.observable({ // The data attribute is responsive and automatically updates the view when the route changes current: '/' }) }
③ Implement createroutemap()
creatRouteMap () { // Create routing map // Traverse all routing rules, parse the routing rules into key value pairs and store them in routeMap this.options.routes.forEach(route => { this.routeMap[route.path] = route.component }) }
④ Implement router link and router view components
// Build versions of Vue include the runtime version and the full version // Runtime version: template template is not supported. It needs to be compiled in advance when packaging // Full version: including runtime and compiler. The volume is about 10KB larger than the runtime version. When the program runs, the template is converted into render function initComponents () { // Create two components, router link and router view _Vue.component('router-link', { props: { to: String }, // 1 - full version of Vue //Need to be in Vue config. Runtimecompiler is configured in JS: true, and the template will be automatically parsed into render function at runtime // template: "<a :href='to'><slot></slot></a>" // 2 - Vue at runtime -- use render function directly render (h) { // The h function receives three parameters. The first one is the target for generating dom elements, the second is some option settings, and the third is the content return h('a', { attrs: { href: this.to }, on: { click: this.handleClick } }, [this.$slots.default]) }, methods: { handleClick(e) { // pushState receives three parameters, 1 - event object, 2 - Web page title, 3 - address of hyperlink jump in history.pushState({}, '', this.to) this.$router.data.current = this.to // Cancel the default behavior of a tag to prevent page refresh from making requests to the server e.preventDefault() } } }) const that = this _Vue.component('router-view', { render (h) { // Find the corresponding component according to the current path. Pay attention to this problem const component = that.routeMap[that.data.current] return h(component) } }) }
⑤ Implement registration events
initEvents() { // For the problem of path change, retrieve the current path and record it in the current in data window.addEventListener('hashchange', this.onHashChange.bind(this)) // Problem with refresh button window.addEventListener('load', this.onHashChange.bind(this)) // Problem with forward and backward buttons window.addEventListener('popstate', this.onHashChange.bind(this)) }
⑥ Implement init()
// It is convenient to initialize when mixing init() { this.creatRouteMap() this.initComponents() this.initEvents() }
be careful:
Projects created by Vue cli use the runtime version of Vue. Cli by default js
If you want to switch to Vue with compiler version JS, you need to modify the Vue cli configuration
Create Vue. From the project root directory config. JS file, add runtimeCompiler
module.exports = { runtimeCompiler: true }
6. Specific source code
let _Vue = null export default class VueRouter { static install (Vue) { // When this method is called, the Vue constructor is passed in // 1. Determine whether the current plug-in has been installed if (VueRouter.install.installed) return VueRouter.install.installed = true // 2. Record the Vue constructor to a global variable _Vue = Vue // 3. Inject the router object passed in when creating the Vue instance into the Vue instance // Mixed in, all Vue instances and components will execute this method _Vue.mixin({ beforeCreate() { if (this.$options.router) { // This attribute is only available in the Vue instance option, and the component does not _Vue.prototype.$router = this.$options.router this.$options.router.init() } } }) } constructor (options) { // Initialize three properties this.options = options this.routeMap = {} this.data = _Vue.observable({ // The data attribute is responsive current: '/' }) } init() { this.creatRouteMap() this.initComponents() this.initEvents() } creatRouteMap () { // Create routing map // Traverse all routing rules, parse the routing rules into key value pairs and store them in routeMap this.options.routes.forEach(route => { this.routeMap[route.path] = route.component }) } // Build version of Vue // Runtime version: template template is not supported. It needs to be compiled in advance when packaging // Full version: includes runtime and compiler, initComponents () { // Create two components, router link and router view _Vue.component('router-link', { props: { to: String }, // 1 - full version of Vue // template: "<a :href='to'><slot></slot></a>" // 2 - during operation render (h) { // The h function receives three parameters return h('a', { attrs: { href: this.to }, on: { click: this.handleClick } }, [this.$slots.default]) }, methods: { handleClick(e) { // pushState receives three parameters, 1 - event object, 2 - Web page title, 3 - address of hyperlink jump in history.pushState({}, '', this.to) this.$router.data.current = this.to // Cancel the default behavior of a tag to prevent page refresh from making requests to the server e.preventDefault() } } }) const that = this _Vue.component('router-view', { render (h) { // Find the corresponding component according to the current path. Pay attention to this problem const component = that.routeMap[that.data.current] return h(component) } }) } initEvents() { // For the problem of path change, retrieve the current path and record it in the current in data window.addEventListener('hashchange', this.onHashChange.bind(this)) // Problem with refresh button window.addEventListener('load', this.onHashChange.bind(this)) // Problem with forward and backward buttons window.addEventListener('popstate', this.onHashChange.bind(this)) } // Retrieve the current path and record it to the current in data onHashChange() { this.data.current = window.location.pathname || '/' } }