Let’s cut the crap and get an article on how it works and how it works
Let’s review vue’s little brother MOE first.
I’ve been abused lately, and I’m not doing so well. If wrong, hope to advise, Thanksgiving!
The use and handwriting of vuex
Vue -router (Hash mode)
1. Start with use
1.1 basis
1.1.1 Dynamic Routing
Dynamic routing means that paths like good/001 and good/002 can all be mapped to the same component
Configure the route writing method
[{path: '/good/:id',}]Copy the code
When the path matches this route, the: argument is placed in $router.params of the current component instance, that is, we can get the: argument of the current path in the component
Chestnut :(note that the root component leaves a hole in the display of this component)
<template>
<div>
Good
{{$route.params.id}}
</div>
</template>
Copy the code
Of course, many times it is necessary to get the parameters passed in the URL. The back).
<template>
<div>
Good
{{$route.params.id}}
{{$route.query}}
</div>
</template>
Copy the code
1.1.2 Nested routines by
So if we’ve been on the product page, now we’re going to go to the product details
Its path assumption is… good/01/details
const routes = [{
path: '/good/:id'.component: Good,
children: [{
path: 'details'.component: Details
}]
}]
Copy the code
1.1.3 Programmed navigation
Router
is used as a router link in components. It works better in templates, but what about js?
In this case, we will use an API=>this.$router.push.
The push method is usually named after a push operation. This is no exception, and it adds a new record to the history stack.
You can think of it as having a history stack of urls
When a route is matched, its address is pushed into the history stack. So when you click the back button, you will automatically go back to the previous page
also calls this API internally, and they are equivalent
Chestnut:
this.$router.push('good/1') //http://localhost:8080/#/good/1
this.$router.push({path:'/good/2'})
//http://localhost:8080/#/good/2
this.$router.push({name:'good'.params: {id:3}})
// Add a name to the routing rule configuration
const routes = [{
name: 'good'.path: '/good/:id'.component: Good,
children: [{
path: 'details'.component: Details
}]
}]
//http://localhost:8080/#/good/3
Copy the code
Note that params is ignored if path is provided
Let’s look at two more apis
router.replace
Router. push adds another record to history and reverses it. Router. replace replaces the current record at the top of the history stack.
The difference between them is that after using the push method to jump, click back can return; Have completely lost it
this.$router.replace({path:'/good02'})
Copy the code
router.go(n)
This is easier. How many steps forward or backward along history?
this.$router.go(1)
this.$router.go(-1)
Copy the code
1.1.4 Named Routes and Named Views
After routing
A named route is a route given a name when configuring rules.
const routes = [{
name: 'good'.path: '/good/:id'.component: Good,
children: [{
path: 'details'.component: Details
}]
}]
Copy the code
Two matches in a component
<router-link :to="{name:'good',params:{id:4}}"> jump < / router - the link >this.$router.push({name:'good'.params: {id:5}})
Copy the code
Named view
For example, if I match an INDEX route, the index page should at least have a header and a body. That means we have to put at least two pits in its parent component
Let’s look directly at chestnuts
{
path: '/'.components: {
test01: Test01,// The key is the pit name
test02: Test02,
default: Test03// No name is default, matching the pit with no name attribute}}Copy the code
The component pit can be specified by name
<router-view name="test01"></router-view>
<router-view name="test02"></router-view>
<router-view />
Copy the code
1.1.5 Redirection and Alias
It’s easier to just look at chestnuts
redirect
// The simplest
{ path: '/good'.redirect: '/'Component: Good}// You can also specify a name
{ path: '/good'.redirect: { name: 'index'}, component: Good}// Can also be a method that takes a directory route as an argument
{ path: '/good'.redirect: to= > {
const { params } = to
if (params.id === 1) {
return '/'}, Component: Good}Copy the code
The alias
{ path: '/good'.alias: '/goodAlias'Component: Good}Copy the code
1.1.6 Route Component Parameter Transfer
How did we pass in the reference?
We use dynamic routing, and route.params
{
path: '/good/:id'.component: Good,
}
Copy the code
{{$route.params.id}}
Copy the code
But:
So let’s take a look at the new approach
Add a new props property to the configuration. Note that the props value can be more than booleans
{
name: 'good'.path: '/good/:id'.component: Good,
props: true
},
Copy the code
Component, using parent-child communication. In the props
<template>
<div>Commodity {{id}}<router-view/>
</div>
</template>
<script>
export default {
props: ['id']}</script>
Copy the code
1.2 the guards
1.2.1 Global Guard
Global front guard
Each guard method receives three arguments
-
To: indicates the route to be entered
-
From: indicates the outgoing route
-
Next: It is a method that must be called. It takes the following parameters
-
Not pass, that is, next(). After the current hook executes, proceed to the next hook (if any)
-
Next (‘/’) equivalent month next({path:’/’}), similar to programmatic navigation, go to the root path (or other address)
-
Next (error), (note that this error is an instance of error) the navigation is terminated and the error is passed to the callback registered with router.onerror ().
-
A chestnut is not allowed to enter good/1
router.beforeEach((to, from, next) = > {
if (to.name === 'good' && to.params.id === '1') {
console.log('You can't come to this place.');
next({ path: '/'})}else {
next()
}
})
Copy the code
Global post-hook
Unlike the front guard, it does not accept the next function in its methods
router.afterEach((to, from) = > {
// ...
})
Copy the code
1.2.2 Route Exclusive Guard
When configuring routing rules, you can directly define them
{
name: 'good'.path: '/good/:id'.component: Good,
props: true.beforeEnter: (to, from, next) = > {
if (to.name === 'good' && to.params.id === '2') {
console.log('Neither 2')
next({ path: '/'})}else {
next()
}
}
},
Copy the code
1.2.3 Guards within components
beforeRouteEnter
<template>
<div>
</div>
</template>
<script>
export default {
beforeRouteEnter (to, from, next) {
if(to.name==='good'&&to.params.id==='3') {console.log('3 doesn't work either. ')
next({path:'/'})}else{
next()
}
}
}
</script>
Copy the code
Here are some things to note:
This method is called before the navigation is confirmed, i.e. the current route has not been entered. The component for the current route has not yet been created, so you can’t get the component instance in this method
However, if you must take the current component instance in this method. There is a way
You can pass a callback to the next method that takes the current component instance. Of course, since the instance is available, the callback method must be called during navigation validation. The return value of this callback is taken as the argument to next
chestnuts
beforeRouteEnter (to, from, next) {
next(vm= >{
console.log(vm); })}Copy the code
As long as the guard’s next method supports the pass-through callback, the component is already created when the next two methods are called and there is no need to bother fetching instances. The next two are chestnuts from the official website
beforeRouteUpdate
beforeRouteUpdate (to, from, next) {
this.name = to.params.name
next()
}
Copy the code
beforeRouteLeave
beforeRouteLeave (to, from, next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes! ')
if (answer) {
next()
} else {
next(false)}}Copy the code
Navigation is important
Let’s look at some of the order in which these hooks are called
Let’s verify that
The above is the case of routing from one route to another, so the starting point is the exit hook within the component.
For simplicity here, I’ll go straight into a route as chestnut
Let’s get the hooks set up
/ / configuration
{
name: 'good'.path: '/good/:id'.component: Good,
props: true.beforeEnter: (to, from, next) = > {
console.log('Configuring beforeEnter')
next()
}
},
// Global hook
router.beforeEach((to, from, next) = > {
console.log('Global Guard')
next()
})
router.beforeResolve((to, from, next) = > {
console.log('Global resolution')
next()
})
router.afterEach((to, from) = > {
console.log('Global post' + to + from)// HERE I also don't want to print to, esLint can't pass without printing
})
/ / components
beforeRouteEnter(to, from, next) {
console.log("Component in front");
next((vm) = > {
console.log("Component front callback");
console.log(vm);
});
},
beforeRouteUpdate(to, from, next) {
console.log("Updates within components");
next();
},
beforeRouteLeave(to, from, next) {
console.log("Component in-back");
next();
},
Copy the code
start
The URL is changed from http://localhost:8080/#/good/2 to http://localhost:8080/#/good/3. For the trigger beforeRouteUpdate
The global parse hook is not described earlier, and it is just the same as the global guard
1.3 To explain some other common knowledge
1.3.1 Lazy Route Loading
The traditional way of writing this is that whether or not the component definition is used is to come in first. This will increase the volume of the packaging (because some of it may not be used)
Lazy loading writing:
{
name: 'good'.path: '/good/:id'.component: () = >
import ('.. /components/test01.vue'),
// props: true,
// beforeEnter: (to, from, next) => {
// console.log(' configuring beforeEnter')
// next()
// }
},
Copy the code
1.3.2 Other tips
Things like data acquisition, and scrolling behavior can be taken a look at
The timing of the data retrieval, whether it’s in the lifecycle hook of the current component after entering the route or in the route guard before entering the route, is something that we usually use
The scrolling action is triggered by the browser’s forward/back buttons
2. Implement a simplified version of routing
Let’s first analyze what’s going on in the routing configuration file
First, vue.use (VueRouter), indicating that VueRouter is a plug-in. So it needs to provide an install method internally (in the case of an object) (if it is a function, this function is called Install). The internal install method is also called, passing Vue as an argument
Here we create a routing configuration rule, which is an array passed in as a construction parameter when new VueRouter is created
Take a look at the entry file main.js
Place one of the route objects instantiated above as an option in the new Vue constructor option
On the whole
class MyRouter {
constructor(options) {
this.$options = options
}
}
// An install method needs to be implemented
MyRouter.install = function(vue) {}Copy the code
What we need to do in the install method is to put the routing instance we made during the routing configuration into the prototype of the Vue when new Vue
This is definitely a mix-up, but we only want to tie the routing instance to the Vue prototype when the root instance is created, so now we have to compare the root instance with the normal component instance.
As you can see at a glance, the root instance has a Router object in its construction options, which is our Router instance
Then we can get the Router instance with $options.router in a lifecycle hook and put it into the Vue prototype
vue.mixin({
beforeCreate() {
if (this.$options.router) {
vue.prototype.$router = this.$options.router
}
},
})
Copy the code
Create two routing componentsrouter-link
androuter-view
Note that the template syntax can only be used under the compiler version; only the JSX or H functions can be used here
Router-link creates an A link. It has a feature href, so it requires the parent component to pass the parameter. At the same time, the content of the slot is also indispensable
vue.component('router-link', {
props: ['to'].render(h) {
return h('a', {
attrs: {
href: The '#' + this.to
}
}, this.$slots.default)
},
})
Copy the code
Router-view: after the HASH value of the URL changes, the router will re-match the new hash value with each path in the route configuration, and render its corresponding component once the match is found
The component instance takes the Router instance (vue prototype), the Router instance takes its $options (constructor passed), and finally the routes rule
Note that the hash value this.$router.current is ugly because it is intended to be reactive. Since we want to make sure that this function is called every time the URL hash changes, I’ll just dump the update to vUE
vue.component('router-view', {
render(h) {
let component = null
this.$router.$options.routes.forEach(route= > {
if (route.path === this.$router.current.current) {
console.log(111)
component = route.component
}
})
return h(component)
}
})
Copy the code
Save the hash value and listen for hash change events
Note that you can get the vue from the install method, but you can’t get it from the MyRouter class.
Declare a variable Vue at install
Reactive problem, we use Vue’s data option, the data option of the initialization of the data is reactive (regardless of the array)
Another simple note is window.addeventListener (‘hashchange’, this.onhashchange.bind (this))
Without this, it is obvious that this.onHashChange is a default binding that points to undefined (in strict mode), so the following onHashChange methods cannot store hashes through this.current.current
let Vue
class MyRouter {
constructor(options) {
this.$options = options
let currentHash = window.location.hash.slice(1) | |'/'
this.current = new Vue({
data: {
current: currentHash
}
})
window.addEventListener('hashchange'.this.onHashChange.bind(this))}onHashChange() {
this.current.current = window.location.hash.slice(1)}}Copy the code
A simple route to this point is done
Wrote last
Hope this article can give you a little help.
Looking forward to our next encounter