One, foreword
Recently, I have been working on TOB projects, including multiple TOB projects in one line of business
Before the article has written the realization of micro front-end 👉 TOB system micro front-end practice summary
Also write too many projects exist between the public module how to deal with 👉 vue multi-project public module handling best practices
One of the most interesting and common requirements I recently encountered was 🧐. In the spirit of summarizing as best practices, I wrote this article and welcome your discussion at 🤩
Ii. Project requirements
In the “workbench” page of the base system of the micro front end, a “most frequently visited page” function is implemented. According to the frequency of the user using each sub-application page, the top4 pages of the most frequently visited sub-application by the user are recorded 🤖
(Note: Top4 pages belong to different sub-application pages, and the page of the base system is not within the scope of recording, because the entrance of the base system is shallower than that of the sub-application page, which may be recorded in the most frequently visited page module, and there are other shortcuts on the workbench)
Key points:
- Need to record at least the pageThe url address, and the corresponding pageThe name of the menu
- The url addressNote that some pages are dynamically routed, with parameters, so you need to record the completed URL address, such as
/lego/#/cms-page-manage/template-instance/view? pageId=555&authCode=lego_page_555
- The name of the menu: Usually the page on the first and second level menu will have the corresponding menu name, not the page on the menu, for example
Details page
Unless there is a menu name in the router-mate routing meta information- In our system, there is a corresponding menu name in the router-mate routing meta information of each page because of the unified breadcrumb processing
- If not, you can add, incidentally, the unified breadcrumb to achieve, or add a judgment filter out the page without menu name (bottom), that is, no menu name pages no longer record scope
- The url addressNote that some pages are dynamically routed, with parameters, so you need to record the completed URL address, such as
- Service end record or front-end record, considering the SPA era, service end record is too heavy, front-end useLocalstorage record implementation
- You need to record the number of page visits, and obtain the top4 most frequently accessed pages based on the number of visits
- Record the timestamp of the last visit of the page. For example, the number of visits of the 6 most visited pages is 23(page 1), 17(page 2), 14(page 3), 9(page 4), 9(page 5), 9(page 6). So the fourth page of the top4 is the page number, which should be based on the timestamp, the page with the largest timestamp (i.e. the most recently visited page).
- It is also important to save the page access record to localStorage at what time. Can you do it on the base system without invading the child application? The following technical scheme implementation is detailed
Third, technical implementation
Our technology stack is vUE, so the following implementation is based on VUE, but the idea is universal ~ global front-guard, printing child application routing information
import VueRouter from "vue-router";
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) = > {
console.log(to)
}
Copy the code
The child application prints the following: The base system prints the following: You can see there’s no name, no meta, forKey Point 1
In the base system, the url can be retrieved by routing, but the menu name cannot be retrieved
Why no name, no mate? The routing of the base system is not the same instance as the routing of the child application. Because in the base system, the sub-application routing is /*, it is not clear that this piece of guiding TOB system micro front end practice summary, Qiankun
Scenario 1: the micro front end provides events that trigger events to localstorage in the child application’s global front guard
Pedestal system: Registers global event center, listens for user to open child application page behavior
import Event from 'eventemitter3';
import { setMenuUrl } from "@/utils/menu-url";
const eventCenter = new Event();
// Listen for the user to open the child application page
window.eventCenter.on('GET_SUPAPP_MENU'.({ path, name }) = > {
// Save localstorage operation
setMenuUrl(name, path)
})
Copy the code
Child application system: triggers the user to open the page event in the global front guard
import VueRouter from "vue-router";
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) = > {
if (window.__POWERED_BY_MICRO__) { // In micro front-end mode
// Triggers the user to open the page
window.eventCenter.emit("GET_SUPAPP_MENU", {path: ` /${process.env.VUE_APP_NAME}#${to.fullPath}`.name: to.meta.menu.title}); }}Copy the code
Disadvantages: Invade sub application, need to do n sub application processing
That can not invade the child application to achieve it, see plan two
Scheme 2: Store localstorage in the sub-application container component of the base system by obtaining Document. title
In fact, there is no way to get the page menu name, document.title is ok, that is, the browser title, as shown below
As mentioned above, our system has a name for each page, document.title is also set according to the page name, if not set, you can set on, so that more standard ~
The url of the subsystem is available for the base system, so it can be handled in the sub-application container component of the base system (see: Summary of toB System Micro front-end practice), as shown in the following code
Vue import {setMenuUrl} from "@/utils/menu-url";<script>
export default {
data() {
return {
documentTitle: document.title
};
},
watch: {
$route(val) {
this.handleRouteChange(val); }},beforeRouteEnter(to, from, next) {
next((vm) = > {
const targetNode = document.getElementsByTagName("title") [0];
const config = { attributes: true.childList: true.subtree: true };
const callback = function () {
vm.documentTitle = document.title
};
// Listen for dom node titie changes
const observer = new MutationObserver(callback);
observer.observe(targetNode, config);
vm.handleRouteChange.apply(vm, [to]);
});
},
methods: {
// Listen for route changes
handleRouteChange(val) {
if(this.documentTitle ! = process.env.VUE_APP_INDEX_TITLE && val.fullPath.split("/").length>3) {// Save localstorage operation
setMenuUrl(this.documentTitle, val.fullPath)
}
}
}
}
</scripe>
Copy the code
For key point 2, how to save localstorage
\\ src/utils/menu-url.js
import { storage } from './storage'
export const setMenuUrl = (name, url) = > {
if(! storage.getItem('menuUrl')) {// Common access modules by default
const initMenuUrl = {
url: {
name: "xxx".count: 1.time: new Date().getTime()
}
}
storage.setItem('menuUrl'.JSON.stringify(initMenuUrl))
}
const menuUrl = JSON.parse(storage.getItem('menuUrl'))
if(menuUrl[url]){
menuUrl[url].count++,
menuUrl[url].time = new Date().getTime()
} else {
menuUrl[url] = {
name,
count: 1.time: new Date().getTime()
}
}
storage.setItem('menuUrl'.JSON.stringify(menuUrl))
}
Copy the code
Screenshot of localStorage browser