preface
Through B station video and some children’s shoes article combined with GitHub source code reading to understand the principle of routing
After reading vuex state management in the previous chapter, I believe that we are also very interested in routing. The same pattern, the same way, we went to Vue-Router on GitHub
And also straight intosrc
- Components: Route-link component and router-view component implementation
- History: Browser related, hash mode, Basic mode, HTML5 mode, non-browser mode, go, push, replace, back, etc
- Util: Not to mention, tools and methods
- Create-mathcher: This is more important, the method of creating route matches and adding route configuration items
- Create-mathcher-map: Directly related to creating route matches, creating route mapping map tables, and encapsulating route objects
- Index: entry file, which is also the vueRouter constructor entity. The prototype defines go, push, replace, back, and so on
- Install: initialization
As usual, vue.use (“vue-router”) will directly execute the install initialization to install the plug-in.
SRC /index.js the last fragment of the code
VueRouter.install = install
VueRouter.version = '__VERSION__'
if (inBrowser && window.Vue) {
window.Vue.use(VueRouter) // Initialize and install the routing plug-in
}
Copy the code
install
SRC /install.js is not a lot of code, just take a look
import View from './components/view'
import Link from './components/link'
export let _Vue
export function install (Vue) {
if (install.installed && _Vue === Vue) return
install.installed = true
_Vue = Vue
const isDef = v= >v ! = =undefined
const registerInstance = (vm, callVal) = > {
let i = vm.$options._parentVnode
if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
i(vm, callVal)
}
}
// Similar to vuex, the router is mounted on the vue root instance through vue.mixin before the life cycle is created
Vue.mixin({
beforeCreate () {
if (isDef(this.$options.router)) {
this._routerRoot = this
this._router = this.$options.router
this._router.init(this)
Vue.util.defineReactive(this.'_route'.this._router.history.current)
} else {
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
}
registerInstance(this.this) // Register the instance
},
destroyed () {
registerInstance(this) // Destroy the instance}})// Define '$router, $route' with object.defineProperty
$router = this.this._routerroot._router /.route, $router = this.this._routerroot._router /.route
// To make it read-only and not modifiable
Object.defineProperty(Vue.prototype, '$router', {
get () { return this._routerRoot._router }
})
Object.defineProperty(Vue.prototype, '$route', {
get () { return this._routerRoot._route }
})
// Register the global components, RouterView, RouterLink, which we often use
Vue.component('RouterView', View)
Vue.component('RouterLink', Link)
const strats = Vue.config.optionMergeStrategies
// use the same hook merging strategy for route hooks
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}
Copy the code
Install.js is very similar to vuex in that it installs, registers the components, and mounts the instance on the vue root instance through the mixin before the lifecycle is created
VueRouter core
The SRC /index.js vueRouter constructor has a lot of code, so let’s go to the core
Determine the mode according to mode
import { HashHistory } from './history/hash'
import { HTML5History } from './history/html5'
import { AbstractHistory } from './history/abstract'
// constructor defaults to hash. // Constructor defaults to hash
let mode = options.mode || 'hash'
// Whether the history mode this.fallback is supported
this.fallback = mode === 'history'&&! supportsPushState && options.fallback ! = =false
// If not, hash is used by default
if (this.fallback) {
mode = 'hash'
}
// Non-browser operation, corresponding to the non-browser mode in the history directory
if(! inBrowser) { mode ='abstract'
}
this.mode = mode
// Do different processing for the corresponding mode
switch (mode) {
case 'history':
this.history = new HTML5History(this, options.base)
break
case 'hash':
this.history = new HashHistory(this, options.base, this.fallback)
break
case 'abstract':
this.history = new AbstractHistory(this, options.base)
break
default:
if(process.env.NODE_ENV ! = ='production') {
assert(false.`invalid mode: ${mode}`)}}Copy the code
If you look at this, you can analyze it
- VueRouter calls different routing implementations according to the mode
- This. History mainly comes from
history
Module, look at the code entry path above./history/.... After the article useful
, take a look at
The History module
History module, route various pattern implementation module, hash. Js, HTML5.js,sbstract.js……
In this case, we use common routes and common hopspush
Method to analyze the entire process
SRC /index.js vueRouter constructor push line 167
push (location: RawLocation, onComplete? :Function, onAbort? :Function) {
// $flow-disable-line
if(! onComplete && ! onAbort &&typeof Promise! = ='undefined') {
return new Promise((resolve, reject) = > {
this.history.push(location, resolve, reject)
})
} else {
this.history.push(location, onComplete, onAbort)
}
}
Copy the code
If the mode is different, the route implementation will be different. If the mode is different, the route implementation will be different. If the mode is different, the route will be different
Hash. The push of js
import { pushState, replaceState, supportsPushState } from '.. /util/push-state'
/ / 50 linespush (location: RawLocation, onComplete? :Function, onAbort? :Function) {
const { current: fromRoute } = this
this.transitionTo(
location,
route= > {
pushHash(route.fullPath) / / modify the hash
handleScroll(this.router, route, fromRoute, false)
onComplete && onComplete(route)
},
onAbort
)
}
// Switch route line 141 corresponding method pushHash
function pushHash(path) {
if (supportsPushState) {
// Whether to support the Histrory mode
// 'SRC /util/push-state.js' is defined according to the browser and version
pushState(getUrl(path));
} else {
// Modify the Hash value of the current URL
// Each change is recorded in the history stack
window.location.hash = path; }}Copy the code
The push of HTML 5. Js
import { pushState, replaceState, supportsPushState } from '.. /util/push-state'
/ / line 44push (location: RawLocation, onComplete? :Function, onAbort? :Function) {
const { current: fromRoute } = this
this.transitionTo(location, route= > {
pushState(cleanPath(this.base + route.fullPath))
handleScroll(this.router, route, fromRoute, false)
onComplete && onComplete(route)
}, onAbort)
}
Copy the code
htm5 – pushState
src/util/push-state.js
export function pushState (url? : string, replace? : boolean) {
saveScrollPosition()
// Html5 Window History object
const history = window.history
try {
if (replace) {
// repalce
const stateCopy = extend({}, history.state)
stateCopy.key = getStateKey()
history.replaceState(stateCopy, ' ', url)
} else {
// push
history.pushState({ key: setStateKey(genStateKey()) }, ' ', url)
}
} catch (e) {
window.location[replace ? 'replace' : 'assign'](url)
}
}
// Replace adds a flag and continues calling pushState
export function replaceState (url? : string) {
pushState(url, true)}Copy the code
PushHash; pushState; window.loachtion.hash; window.loachtion.hash; While HTML5 simply calls the pushState method and the built-in method of the Window History object, different ways of handling it.
Note: The other go, Replace, ensureURL, getCurrentLocation, and so on are implemented the same way
Well, the implementation principle of the core routing has been generally understood, so the routing matching rules here a brief introduction, I do not go further ha, interested students can click the link below to further study, we go into the createMatcher to createMatcher method
SRC/create - the matcher. Js 16 lines
export function createMatcher(
routes: Array<RouteConfig>, // Route object collection
router: VueRouter // The current route instance is this
) :Matcher {
// Create route mapping createRouteMap Key, key, key method
const { pathList, pathMap, nameMap } = createRouteMap(routes);
// Matching rules
function match(.){... }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} Like {"/home": home} equals {path: component} to map the corresponding component based on the hash path */
Copy the code
Bilibili to further understand the specific implementation of the fast channel VUex + Vue-Router
Welcome to like, a little encouragement, a lot of growth
A link to the
- Front-end visualization platform implementation scheme
- Vue3 10 minutes takes you seconds to vue3
- Vue template compilation principle
- The vue constructor extends
- How does VUEX state management work
- Vue-router source analysis principle
- Vue [how to listen for array changes]
- Handwritten Vue response [object.defineProperty]
- Vue responsive source sharing