“This is the 12th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”
Antecedents feed
From the previous article, how does vue-Router find vUE components to render? Vue -router Matcher: Route is processed when the vue-router finds a vue component to render. RouteRecordNormalized routing records
This article describes how Matcher handles the alias part of route, the redirection and alias of vue-Router documents
Note: The matcher analysis and source code in this article correspond to vuE-Router4, which is vuE3 version of the router
{route: “/”, Redirect: “/test”} {route: {path: “/”, Redirect: “/test”}[route,route,...]
The alias processing
Refer to the vue-router document-alias documentation for an introduction to the alias handling API
Anyway, this is what the alias ends up doing
const route = {
path: "/users".component: User,
// My English is too poor
alias: "/humans".children: {{path: ' '.component: UserList, alias: ['/people'.'list']}}}Copy the code
The route above matches the path below
// - /users
// - /people
// - /users/list
// - /humans/list
// - /humans
Copy the code
So how does an alias exist on vue-Router? How does it work? The vue-router does two things with aliases. The router does two things with aliases
- Adding an Alias Route
- Recursively update named subroutes
How does vue-Router solve these two problems
Adding an Alias Route
In the router/SRC/matcher/index. The ts 86 to normalizedRecords (routes) standardized version of the array, a number of network stations, is actually in order to facilitate we add an alias, so the default alias, Refer to the following data structure description
/ / the source code
const routes = { path: "/users".alias: "/humans" };
// Vue-router is processed
const normalizedRecords = [{ path: "/users" }, { path: "/humans" }];
Copy the code
Vue-router is also very simple to add an alias route, a for loop, like the following
if ("alias" in record) {
const aliases =
typeof record.alias === "string"? [record.alias] : record.alias! ;for (const alias of aliases) {
normalizedRecords.push({
// alias route: RouteRecordNormalized}); }}Copy the code
Note a small detail, look at the source code below
const aliases =
typeof record.alias === "string"? [record.alias] : record.alias! ;Copy the code
Alias is actually an optional attribute in the route interface _RouteRecordBase. Alias is undefined, so it must have a null value, meaning record. Alias must have a value, Don’t may be null or undefined, but actually even record. The alias = undefined | | null, vue – the router is running but complains, Const alias of aliases {//… }
If there is a parent route, the parent route will need to keep the value of originalRecord. This is actually related to updating the parent route recursively
normalizedRecords.push(
assign({}, mainNormalizedRecord, {
components: originalRecord
? originalRecord.record.components
: mainNormalizedRecord.components,
path: alias,
aliasOf: originalRecord ? originalRecord.record : mainNormalizedRecord,
}) as typeof mainNormalizedRecord
);
Copy the code
Vue-router has one neat design feature that can be explained here
for (const normalizedRecord of normalizedRecords) {
matcher = createRouteRecordMatcher(normalizedRecord, parent, options);
if (originalRecord) {
originalRecord.alias.push(matcher);
} else {
originalMatcher = originalMatcher || matcher;
}
originalRecord = originalRecord || matcher;
}
Copy the code
Const routes = {path: “/users”, alias: “/humans”}; For example, for a data structure from the source code above, originalRecord means “/users”.
const normalizedRecords = ["/users"."/humans"];
Copy the code
Its purpose is to make “/ users to generate the Matcher needs and”/humans “(alias) generated by the Matcher, namely originalRecord. Alias. Push (Matcher); This step, “/ user” as normalizedRecord traversed is no originalRecord for the first time, and then through the | | assignment, | | actually can be called selection operator, it will choose the first is true value, for example
console.log(false || 1); / / 1
console.log(1 || false); / / 1
Copy the code
So first traversal, traverse the original “/ users,” originalRecord = undefined | | matcherByUser, The second traversal is originalRecord = matcherByUser | | matcherByHuman, so can the whole traversal of the original will be pointing to “/ users”
Recursively update named subroutes
The recursive update alias subpath uses the multi-tree traversal algorithm (leetCode has a detailed solution, as well as Labuladong). If you extract the source code, you can see that vue-Router4’s recursion comes from the same root as the multi-tree traversal framework
function addRoute() {
for (const normalizedRecord of normalizedRecords) {
if ("children" in mainNormalizedRecord) {
const children = mainNormalizedRecord.children;
for (let i = 0; i < children.length; i++) { addRoute(); }}}}// Multi-tree traversal framework
const traverse = (root) = > {
if (root === null) {
return;
}
for (let i = 0; i < root.children.length; i++) { traverse(root.children[i]); }};Copy the code
The reason for the extra loop is that the vue-Router’s alias and original are split at the same time. As mentioned in the previous section, the route will be grouped at the beginning to achieve a closed loop
/ / the source code
const routes = { path: "/users".alias: "/humans" };
// Vue-router is processed
const normalizedRecords = [{ path: "/users" }, { path: "/humans" }];
Copy the code
From this part, we can know that vue-router uses the recursive traversal framework to process the multi-fork tree structure of routes
conclusion
Finally, a few tips for reading vue-Router. When I first looked at the matcher section of the code, I looked at the relationship between each part of the call, and I fell into the detail trap. I wasted a lot of time worrying about the designer’s consideration of part of the source code, and the type of TS. For a quick understanding of some of the source code usage and designers’ considerations, you can try debugging in Chrome. After you know the call relationships between source modules, you can design test cases. For example, the route given in vue-Router documentation is a very good test case. Then run it to Chrome for debugging. Chrome debugging is better than Vs Code debugging. You can see the designers thinking about the source code, debugging this dynamic process, is much more efficient than if you just read the source code
Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4
- How does vue-Router find vUE components to render? Vue – Router Matcher parsing (1) – Standardized route
- How does vue-Router find vUE components to render? Route-router Matcher (