This is the 25th day of my participation in the August Genwen Challenge.More challenges in August
One, foreword
$route, $router and router-link
- Define the prototype method
$route
和$router
; <router-link>
Component functionality and implementation;
This article introduces the implementation of
component.
Two, the previous review
- When VueRouter is instantiated, the route configuration is flattened by createMatcher.
- The match method in createMatcher matches routing records and creates routing objects.
- Create the current matching routing object, current, as responsive data;
- Click router-link component to switch path, call transitionTo to match new route record and update responsive data current, trigger view update;
When clicking the router-link component to switch paths, all routing rules need to be matched according to the latest routing address, and the page is updated and rendered recursively.
Third, functional components
Router-view is a functional component that has the following features:
- High performance, render without this;
- Functional: true stands for functional components;
export default {
name: 'routerView'.functional: true.// Functional components
render() {
/ / this is null
return <div></div>}}Copy the code
$mount(); new Ctor().$mount();
Function components that can be used without creating an instance (equivalent to function components in React);
The only difference is that there is no this in the render function, i.e. no component state (no data, props, etc.)
Vue official website: an introduction to functional components
Four,<router-view>
Component implementation
1. Obtain render record data
The $route attribute exists on the parent of the current component.
$router = _route; parent.$router = _route;
/** * Router-view functional components, multi-layer rendering * Functional components features: high performance, no need to create instances, no this */
export default {
name: 'routerView'.functional: true.// Functional components
render(h, { parent }) {
// Get the relevant route record that needs to be rendered currently, namely: this.current
letroute = parent.$route; }}Copy the code
2. Record the depth of recursion
After obtaining $route attribute, route.matched is all routing matching records.
Processing logic:
- App. vue contains router-View component and Home page rendering component;
- When clicking “Jump to Mine” for route switching, router-view in app.vue renders Mine component;
- When clicking “Mys-Personal Information” for route switching, the components corresponding to router-view rendering /mine/ User routing in mine.vue;
Therefore, when accessing /mine/user, three routing rules will be matched: /, /mine, /mine/user;
In this case, render operations need to be carried out as described above.
Therefore, it is necessary to record the depth of each layer of router-view to render the content;
3. Handle the first layer of rendering
When the Router-View component renders, the routerView component’s Render method is called.
Add the custom data.routerView = true to the data attribute of the current layer (layer 1).
export default {
name: 'routerView'.functional: true.render(h, { parent, data }) {
let route = parent.$route;
let depth = 0;// Record the level depth
data.routerView = true; // Custom attributes}}Copy the code
The first rendering, according to the matching result and the depth of the hierarchy, needs to render the 0 item in Route. matched;
Let Record = route.matched[0] to obtain the records required by the corresponding level of rendering;
export default {
name: 'routerView'.functional: true.render(h, { parent, data }) {
let route = parent.$route;
let depth = 0;
data.routerView = true;
// Router-view renders the first record and the second router-view renders the second record
let record = route.matched[depth]; // Get the corresponding level of records}}Copy the code
- Router-view may have only one layer, which can be removed directly.
- If no record is matched, the record does not exist, and an empty virtual node called empty-vNode is returned
h()
- If a record is matched, the record has a value and the component is rendered
h(record.component)
, get components from record.component; - H (record.component): Renders the current component. When the component renders, it passes in data data containing the previously identified routerView property.
export default {
name: 'routerView'.functional: true.render(h, { parent, data }) {
let route = parent.$route;
let depth = 0;
data.routerView = true;
// Obtain the routing record corresponding to the current layer depth for view rendering
let record = route.matched[depth];
// No routing record was matched, render empty virtual node (empty-vNode), also called comment node
if(! record) {return h();
}
returnh(record.component, data); }}Copy the code
This completes the rendering of the first layer of router-view tags;
4. Handle multi-level router-view rendering
- Each time a Router-View is rendered, the routerView attribute is set as a marker in the current data.
- The parent in the render function is the parent tag of the current router-View.
- Check by loop parent
parent.$vnode.data.routerView
Calculates the depth of the current render level. - Obtain routing records of corresponding levels and render views;
Related instructions:
- Parent.$vnode: represents the placeholder vnode; That is, virtual nodes with component label names.
- Parent._vnode refers to the contents of the component; That is, the actual virtual node to render;
/** * Router-view functional components, multi-layer rendering * Functional components features: high performance, no need to create instances, no this */
export default {
name: 'routerView'.functional: true.// Functional components
render(h, { parent, data }) {
// Get the relevant route record that needs to be rendered currently, namely: this.current
let route = parent.$route;
let depth = 0;// Record the level depth
data.routerView = true; // Custom attributes
// App.vue calls the Render function when the app. vue component is rendered without a data.routerView attribute
// Add the routerView=true flag when rendering the first layer
while (parent) { // parent is the parent label of router-view
// parent.$vnode: placeholder vnode; That is, virtual nodes with component label names.
// parent._vnode refers to the contents of the component; That is, the actual virtual node to render;
if (parent.$vnode && parent.$vnode.data.routerView) {
depth++;
}
parent = parent.$parent; // Update the parent for the next processing of the loop
}
// Obtain the routing record corresponding to the current layer depth for view rendering
let record = route.matched[depth];
// No routing record was matched, render empty virtual node (empty-vNode), also called comment node
if(! record) {return h();
}
returnh(record.component, data); }}Copy the code
This implements router-view component view update operation;
Five, the end
This article introduces the implementation of router-View component, mainly involving the following contents:
- Introduction to functional components;
- Implementation of router-view component:
- Get render record;
- Mark router-view hierarchy depth;
- Router-view rendering based on depth;
In the next article, vue-Router hook functions are introduced.