Vue-router implementation principle
By updating the view without rerequesting the page, THE JS can sense the URL change, and by doing so, the JS can dynamically modify the currently displayed component. The router-link tag in vUE dynamically updates the component shown here based on the Url change. In SPA single-page applications, there is no need to request HTML again for each jump; HTML is only requested once. Dynamically replace the components within the APP tag.
The single-page application of VUE is based on routing and components, which are used to set access paths and map paths to components
How is router-link dynamically replaced with a component
Several modes
Vue-router provides three operating modes:
- Hash: Uses the URL hash value for routing. Default mode.
- History: Relies on the HTML5 History API and server configuration.
- Support all JavaScript runtime environments, such as node.js server side
Hash pattern
Hash is what follows the # in the browser URL and contains the #. A hash is an anchor point in the URL that represents a location in the web page. Simply changing the part after the # will only load the content at that location, not reload the page.
That is, # is used to direct browser actions and is completely useless on the server side. HTTP requests do not contain #. Each change after # adds a record to the browser’s access history. Use the back button to go back to the previous position. So Hash mode renders different data for the specified DOM position by changing the anchor value.
Hash mode testing
window.addEventListener("hashchange",cb,false)
function cb(){
console.log("hashchanged")};window.location.hash=5; // hashchanged
window.location.hash=6; // hashchanged
Copy the code
Hash mode simulation implementation
The primary version
You need to manually modify the hash in the URL to trigger the hashchange event. To perform the corresponding callback
class Routers{
constructor(routersList){
// Route list object, used to store all routes and corresponding callbacks
this.routersList = routersList || {};
// When the page is initialized, it listens for the load event and executes the callback for the current hash
window.addEventListener('load'.this.refresh,false);
// There is a Bug that when the hash changes, the callback is not executed immediately, but the page needs to be refreshed again. This is equivalent to the callback of the load event all the time.
window.addEventListener('hashchange'.this.refresh,false);
}
refresh(){
this.currentUrl = location.hash.slice(1) | |'/a' || '/'; // '/a
// Performs a callback for the current route
this.routersList[this.currentUrl] && this.routersList[this.currentUrl](); }};var routersList = {
"a": (a)= > { console.log('a')},"b": (a)= > { console.log('b')}}var routers = new Routers(routersList);
Copy the code
With the above code, I have implemented a simple hash route. When we manually modify the hash, the corresponding callback function is executed.
So, the problem is, in our project, we don’t modify the hash manually, so we need to provide a method that when the user interacts, we call the corresponding hash modification and render the page. We will not expand the rendered page in this article. This paper focuses on the implementation of hash routing
Transition version
Add a push method that modifies the hash and performs its callback
class Routers{
constructor(routersList){
// Route list object, used to store all routes and corresponding callbacks
this.routersList = routersList || {};
// When the page is initialized, it listens for the load event and executes the callback for the current hash
window.addEventListener('load'.this.refresh,false);
window.addEventListener('hashchange'.this.refresh,false);
}
push(hash,cb){
this.routersList[hash] = cb || (() = >{});window.location.hash=hash;
//this.refresh();
}
refresh(){
this.currentUrl = location.hash.slice(1) | |'/a' || '/'; // '/a
// Performs a callback for the current route
this.routersList[this.currentUrl] && this.routersList[this.currentUrl](); }}var routersList = { "a": (a)= > { console.log('a')},"b": (a)= > { console.log('b')}};var routers = new Routers(routersList);
routers.push('c', () = > {console.log('c')});
routers.push('d', () = > {console.log('d')}); // Push both callbacks, but only the callback for the final hash is executed. The previous c callback is not executed
console.log(routersList); // {a: ƒ, b: ƒ, c: ƒ, d: ƒ}
Copy the code
The intermediate version
It’s increased, forward and backward. Depend on initialization data. There is no refinement of the history array when moving forward or backward.
You need to think about the real history and how the list of routing objects is generated. And storage mode.
class Routers{
/** The constructor is easy to test. The default input is two objects * @ input route list objects, including hash and its corresponding callback, such as {"a": () => {console.log('a')}, "b": () => { console.log('b') }... } * @ Output route list array, default store hash history ["a","b"] * */
constructor(routersList,hashHistory){
// Route list object, used to store all routes and corresponding callbacks
this.routersList = routersList || {};
// An array to store hash history
this.hashHistory = hashHistory || [];
// The current hash index, which by default points to the end of the hash history array, +1 for forward and -1 for backward
this.currentHashIndex = this.hashHistory.length- 1;
// When the page hash value
//this.currentHash = "";
// When the page is initialized, it listens for the load event and executes the callback for the current hash
window.addEventListener('load'.this.refresh,false);
// When the page hash is modified, it listens for the hashchange event and executes the callback corresponding to the current hash
window.addEventListener('hashchange'.this.refresh,false);
}
/** * 1. Use the current hash index +1 to obtain the next index. And modify hash to the next index * 2. Call refresh to perform the callback * */ by listening on hashchange
go(){
this.currentHashIndex++;
console.log('Next Hash index'.this.currentHashIndex)
If the current index of the route is smaller than the history array, the current index can be reduced by 1, and an error is reported.
if(this.currentHashIndex < this.hashHistory.length){
location.hash = this.hashHistory[this.currentHashIndex]
}else{
// When moving forward, the current index is increased by 1, but there is no corresponding route, so we need to subtract 1. Otherwise, when we reach the boundary of this step, we need to call back twice to take effect.
this.currentHashIndex = this.currentHashIndex - 1;
throw new Error("There are no forward routes in the routing array."); }}/** * 1. Add a new hash and callback * 2. And jump to the new hash, calling refresh to perform the callback * */ by listening on hashchange
push(hash,cb){
// Add hash to hashHistory array
this.hashHistory.push(hash);
// Add hash and corresponding callback to the routerList object
this.routersList[hash] = cb || (() = >{});// Change the current page hash to the new hash
window.location.hash=hash;
// Update the current index to the index with the history length changed. Points to the last hash
this.currentHashIndex = this.hashHistory.length- 1;
}
/** * 1. Use the current hash index -1 to obtain the previous index. And change the hash to the previous index * */
back(){
// If the current hash index is less than 0, set it to 0;
if(this.currentHashIndex <= 0) {this.currentHashIndex = 0;
throw new Error("At the top of hashHistory")}else{
this.currentHashIndex = this.currentHashIndex - 1;
}
console.log('Current Hash index'.this.currentHashIndex)
location.hash = this.hashHistory[this.currentHashIndex]
}
/** * 1. Obtain the hash in the Url and perform the callback for the current hash ** /
refresh(){
this.currentUrl = location.hash.slice(1) | |'/'; // '/a
// Performs a callback for the current route
this.routersList[this.currentUrl] && this.routersList[this.currentUrl](); }}var routersList = { "a": (a)= > { console.log('a')},"b": (a)= > { console.log('b')}};var hashHistory = ["a"."b"]
var routers = new Routers(routersList,hashHistory);
routers.push('c', () = > {console.log('c')});
console.log(routers); RoutersList: {routersList: {routersList: {routersList: {... }, hashHistory: Array(3), currentHashIndex: 2}
// Use the instance go and back methods to move forward and backward without passing parameters
routers.go()
routers.back()
// Remember bounds
Copy the code
This version does not store the history of all forward and backward hash accesses. We need to add history to the hashHistory during go and back.
This version, which simulates only forward and backward, does not fully record the browser’s real history.
Improved Intermediate Version
You need to think about the real history and how the list of routing objects is generated. And storage mode.
Copy the code
Hash route summary
- Implement keypoints, an array that maintains route history and holds all hashes
- A key-value pair object that maintains hash and callback
- The current index (which by default points to the end of the history array), increment, and decrement are used to move forward and backward
Hash routing needs to be improved
- Keep it consistent with the browser history
- The historical record needs to be changed, both forward and backward.
- In the example above, we just move forward and backward with the history and callback objects fixed
The History mode
The HTML5 History Api allows you to change the URL of a page without refreshing the entire page,
window.history.pushState({},""."www.aa.com");
// The page is not refreshed, but the URL is changed to
/ / from https://juejin.im/editor/drafts/5dd68d6d6fb9a05a51701491
/ / change to https://juejin.im/editor/drafts/www.aa.com
Copy the code
Vue-router Indicates the application mode
- Download NPM I vue-router-s
- Import VueRouter from ‘vue-router’ in main.js;
- Install vue.use (VueRouter);
- Let router = new VueRouter({routes:[{path:’/home’, Component: home}]});
- Pass its routing object to an instance of Vue. Add router: Router to options
- Leave a pit in app.vue
Vue-router Indicates other attributes
scrollBehavior
The scrollBehavior method receives to and FROM routing objects. The third parameter savedPosition is available if and only if popState navigation (triggered by the browser’s forward/back buttons).
const router = new VueRouter({
routes: [...]. , scrollBehavior (to,from, savedPosition) {
// return is expected to scroll to the position}})Copy the code
Simulate the “scroll to anchor” behavior
scrollBehavior (to, from, savedPosition) {
if (to.hash) {
return {
selector: to.hash
}
}
}
Copy the code
Combined with keepAlive, if keepAlive, to save the location of the stay
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
if (from.meta.keepAlive) {    from.meta.savedPosition = document.body.scrollTop;
}
return { x: 0.y: to.meta.savedPosition || 0}}}Copy the code
Related compatibility issues
After the keep-alive tag is used, some Android devices return incorrect cache page positions
Scroll to the specified location
- Get the distance of page scroll left and up
To be compatible with all browsers, encapsulate a function to get how far the page is curled up and how far it is curled left
function getScroll(){
return {
left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0.top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0
};
}
Copy the code
Copy the code
conclusion
- Both hash and History modes are urls that update pages without refreshing.
- The history mode will run on the server and requires the support of the backend.
Pay attention to the point
- In history mode, add a candidate resource on the server that covers all cases: if the URL does not match any static resource, it should return the same index.html page that your app relies on:
export const routes = [
{path: "/".name: "home".component:Home}
{path: "/a".name: "a".component: A},
{path: "/login".name: "login".component: Login},
{path: "*".redirect: "/"}]
Copy the code
- In history mode, front-end routes must have the same back-end routes.
Think about some
- Vue route why not use a tag, -> page refresh
The source address
Github.com/AndyRoyal/v…