preface
This article continues with the implementation of the History route after the previous article covered a simple implementation of the hash route
Without more words, first on demo&& source && project files (htmlRouter folder)
History Routing Principle
History is a new HTML5 standard that is more elegant than Hash, but there are compatibility issues with lower versions of IE.
The pushState and replacestate methods of History can add and modify the History without sending new server requests, so they can be used for front-end route hops.
The Go,back, and Forward methods of History can jump, backward, and forward, and popState events can listen to record changes.
Page structure
Because the a tag will cause the page to jump, the page structure needs to be modified and the plug-in method is used to jump
<ul class="nav-list">
<li class="nav-item"><a onclick="router.push({name: 'monday'})">Monday</a></li>
<li class="nav-item"><a onclick="router.push({name: 'tuesday', query: {name: 'suporka', age: '26'}})">Tuesday</a></li>
<li class="nav-item"><a onclick="router.push({path: '/wednesday'})">Wednesday</a></li>
<li class="nav-item"><a onclick="router.push({path: '/thursday', query: {name: 'suporka', age: '20'}})">Thursday</a></li>
<li class="nav-item"><a onclick="router.replace({name: 'friday'})">Friday</a></li>
</ul>
Copy the code
Implementing the History route
init()
On MDN, this is how popState is introduced
The POPState event is triggered when the active history entry changes. If the active history entry was created by a call to history.pushState (), or is affected by a call to history.replacEstate (), the state property of the popState event contains a copy of the state object for the history entry.
Note that a call to history.pushState() or history.replacEstate () does not trigger a popState event. This event is triggered only when a browser action is taken, such as when the user clicks the browser’s back button (or calls the history.back() or history.forward() methods in Javascript code)
Different browsers handle popState events differently when loading a page. Chrome and Safari usually trigger a PopState event when a page loads, but Firefox does not.
So in the initialization method of the history route, you need to listen for popState and load events
export default class HistoryRouter extends RouterParent {
constructor(routerConfig) {
super(routerConfig);
}
init() {
// refresh Displays the binding between the component and the current route
// bind(this) passes in the instance object, otherwise this pointing to the problem
window.addEventListener('popstate'.this.refresh.bind(this), false);
window.addEventListener('load'.this.refresh.bind(this), false); }}Copy the code
refresh()
In line with hash routing implementation, component control is shown and hidden, except that you can directly use the history function instead of creating a routeHistory to control the jump
refresh() {
let path = window.location.pathname,
currentComponentName = ' ',
nodeList = document.querySelectorAll('[data-component-name]');
// Find the name of the current route
for (let i = 0; i < this._routes.length; i++) {
if (this._routes[i].path === path) {
currentComponentName = this._routes[i].name;
break; }}// Displays the component based on the name of the current route
nodeList.forEach(item= > {
if (item.dataset.componentName === currentComponentName) {
item.style.display = 'block';
} else {
item.style.display = 'none'; }}); }Copy the code
back() && front()
Back up and call the HISTORY API directly, which triggers the PopState event and calls the Refresh method to render the page
back() {
window.history.back();
}
front() {
window.history.forward();
}
Copy the code
push(option)
In vue-router, the current route can be modified by path, name, and can carry query parameters. Therefore, path is preferred. If there is a path, pushState is called to add historical records. If there is no path, find path from routes based on name and call pushState to add history. Since history.pushState() or history.replacEstate () do not trigger popState, we need to call the Refresh method manually
push(option) {
if (option.path) {
// Bind the this pointer so that the function can call the class's methods
pushHistory.call(this, option.path,option.query);
} else if (option.name) {
let routePath = ' ';
// Find the route path based on the route name
for (let i = 0; i < this._routes.length; i++) {
if (this._routes[i].name === option.name) {
routePath = this._routes[i].path;
break; }}if(! routePath) { error('Component name not found');
} else {
pushHistory.call(this, routePath, option.query); }}}// Route jump
function pushHistory(routePath, query) {
let path = getTargetPath(routePath, query);
if(path ! = =window.location.pathname) {
window.history.pushState(path, ' ', path);
this.refresh(); }}function error(message) {
typeof console! = ='undefined' && console.error(`[html-router] ${message}`);
}
// Get the path to jump to
function getTargetPath(path, query) {
if(! query)return path;
let str = ' ';
for (let i in query) {
str += '&' + i + '=' + query[i];
}
return path + '? ' + str.slice(1);
}
Copy the code
replace(option)
Replace and push have basically the same logic, except that instead of calling pushState, the replaceState method is called. So modify the push method to be compatible with replace
replace(option) {
// Indicates that the current state is in replace
this.replaceRouter = true;
this.push(option);
}
push(option) {
if (option.path) {
pushHistory.call(this, option.path, option.query, this.replaceRouter);
} else if (option.name) {
let routePath = ' ';
// Find the route path based on the route name
for (let i = 0; i < this._routes.length; i++) {
if (this._routes[i].name === option.name) {
routePath = this._routes[i].path;
break; }}if(! routePath) { error('Component name not found');
} else {
pushHistory.call(this, routePath, option.query, this.replaceRouter); }}}// Overwrite the route to jump
function pushHistory(routePath, query, replace) {
let path = getTargetPath(routePath, query);
if(path ! = =window.location.pathname) {
if (replace) {
window.history.replaceState(path, ' ', path);
this.replaceRouter = false;
} else window.history.pushState(path, ' ', path);
this.refresh(); }}Copy the code
The demo test
Test code is not written, the same as the previous hash route, the effect is as follows:
But there is a problem here. When the page is refreshed on a route, the following situation occurs
A 404 will appear when you refresh the router, as described in the official vue-Router documentation. Enabling history requires server support!
When you use history mode, the URL looks like a normal URL, such as yoursite.com/user/id, which also looks good…
However, this mode to play well, but also need background configuration support. Because our application is a single-page client application, if the background is not properly configured, when the user accesses oursite.com/user/id directly from the browser, it will return 404, which is not pretty.
So, you add a candidate resource on the server that covers all cases: if the URL doesn’t match any static resource, it should return the same index.html page that your app relies on.
That is the complete content of Simple Routing Implementation. More articles can be viewed in my column. Thank you for watching
More recommended
Advanced_front_end
Daily question
Webpack4 Build Vue application (createVue)
Canvas Advanced (1) Generation of two-dimensional code and scan code recognition
Canvas advanced (2) Write a NPM plug-in to generate a TWO-DIMENSIONAL code with logo
Canvas advanced (3) TS + Canvas rewrite “color discrimination” small game
Canvas advanced (four) to achieve a “scratch-off” game
Canvas advanced (5) to achieve the image filter effect
VUI create log (a) – picture lazy load command implementation
VUI create log (two) – – anti – shake throttling component implementation
Front-end algorithm Topic analysis (1)
Front-end algorithm topic analysis (2)