Analysis of Vue router source code (VI) usage and principle of router view component

Time:2020-12-1

Router view is a functional component. The rendering path matches the view component.Rendered components can also be embedded in their own, render nested components according to the nested path

It has only one props named name, which has a default value, which is default. Generally, we do not need to pass name. Only in the case of named view, we need to pass name. Named view is to display multiple views at the same level, rather than nested display,

The router view component is rendered from the vuerouter instance_ route.matched Property to get the component to be rendered, that is, this in Vue$ route.matched For example, a chestnut was obtained from

Info page     
        Page        
        
        
    
    <span style="background-color: #f5f5f5; color: #000000;">                   
        const info  </span><span style="background-color: #f5f5f5; color: #000000;">=</span><span style="background-color: #f5f5f5; color: #000000;"> { template:</span><span style="background-color: #f5f5f5; color: #000000;">'</span><span style="background-color: #f5f5f5; color: #000000; < span > < span > < span > < span > < span > < span > < span > < span > < span > < span > < span < span > < span > < span style = background color: "background color:" f5f5f5; color: Color: not "font;" ">" < / span > < span style: "background color:" f5f5f5; color: Color: Color: f5f5f5; color: Color: Color: Color: Color: Color: f5f5f5; color: Color: Color: Color: f5f5f5; color: Color: Color: f5f5f5f5; color: Color: Color: Color: f5f5f5f5f5; color: Color: Color: background color: background color: background color: background color: background color: background color: Color: Color: f5f5f5f5"> // < / span > < span style:" background color: "f5f5f5; color:" 008000; "> outer components</span>
<span style="background-color: #f5f5f5; color: #000000;">        const page  </span><span style="background-color: #f5f5f5; color: #000000;">=</span><span style="background-color: #f5f5f5; color: #000000;"> { template:</span><span style="background-color: #f5f5f5; color: #000000;">'</span><span style="background-color: #f5f5f5; color: #000000; Background: < span > "< background: < span >" < background: < span > "< background: < span >" < background: < span > "< background: < span >" < background: < span > "< background: < span >" < background: < span > "< background: < background: < span >" < background: < span > "< background: < span >" < background: < span > "< background: < span >" < background: < span > "< background: < span >" < background: < span > "< background: < background: < span >" < background: < span > "< background: < span >" < background: < span > "< span >" < background: < background: < span < span < span < span < span < span < span < span < background: < span < span < span < span < span < span < span < span < span < span< F000; "> Color: < F000; ţ</span>
<span style="background-color: #f5f5f5; color: #000000;">        const routes </span><span style="background-color: #f5f5f5; color: #000000;">=</span><span style="background-color: #f5f5f5; color: #000000;"> [                                   
            {
                path:</span><span style="background-color: #f5f5f5; color: #000000;">'</span><span style="background-color: #f5f5f5; color: #000000;">/info/</span><span style="background-color: #f5f5f5; color: #000000;">'</span><span style="background-color: #f5f5f5; color: #000000;">,
                component:info,
                children:[                         
                    {path:</span><span style="background-color: #f5f5f5; color: #000000;">'</span><span style="background-color: #f5f5f5; color: #000000;">face</span><span style="background-color: #f5f5f5; color: #000000;">'</span><span style="background-color: #f5f5f5; color: #000000;">, component:page }        </span><span style="background-color: #f5f5f5;  Color: ා 008000; "> // < / span > < span style:" background color: "f5f5f5; color:" 008000; "> nested routing is used</span>
<span style="background-color: #f5f5f5; color: #000000;">                ]
            }
        ]
        const app </span><span style="background-color: #f5f5f5; color: #000000;">=</span> <span style="background-color: #f5f5f5; color: #0000ff;">new</span><span style="background-color: #f5f5f5; color: #000000;"> Vue({                                                     
            el:</span><span style="background-color: #f5f5f5; color: #000000;">'</span><span style="background-color: #f5f5f5; color: #000000;">#app</span><span style="background-color: #f5f5f5; color: #000000;">'</span><span style="background-color: #f5f5f5; color: #000000;">,
            router:</span><span style="background-color: #f5f5f5; color: #0000ff;">new</span><span style="background-color: #f5f5f5; color: #000000;"> VueRouter({routes})
        })
    </span>

Render as follows:

When we route to the info page, we print the app on the console$ route.matched The output is as follows:

Writer by: Desert QQ: 22969969

When we route to the page page, we print the app on the console$ route.matched The output is as follows:

You can see that all parent-child component information is saved in matched. The index starts from 0, followed by the top-level components, and then the child components. The matched attribute will be read when the inner render implementation of router view component is implemented, as follows:

var View = {
  name: 'RouterView',
  Functional: true, // functional component
  props: {
    name: {
      type: String,
      default: 'default'
    }
  },
  render: function render (_, ref) {
    var props =  ref.props ; // get props; for example: {Name: "default"}
    var children =  ref.children ; // get all child nodes
    var parent =  ref.parent ; // reference of parent component
    var data = ref.data;

    // used by devtools to display a router-view badge
    data.routerView = true;

    // directly use parent context's createElement() function
    // so that components rendered by router-view can resolve named slots
    Var H = parent. $createElement; // gets the reference of the parent component's $createElement function, so that the component can use the named slot when executing render
    var name = props.name;
    Var route = parent. $route; // current routing address
    var cache = parent._ routerViewCache || (parent._ Routerviewcache = {}); // get the parent component's_ Routerviewcache property. If not, initialize it as an empty object

    // determine current view depth, also check to see if the tree
    // has been toggled inactive but kept-alive.
    Var depth = 0; // level of component nesting
    Var inactive = false; // is it in the keep alive component
    while (parent && parent._routerRoot !== parent) {
      if (parent.$vnode && parent.$vnode.data.routerView) {
        depth++;
      }
      if (parent._ // if parent is active_ Inactive existence
        Inactive = true; // set inactive to true
      }
      parent = parent.$parent;
    } 
    data.routerViewDepth  =Depth; // the level of component nesting

    // render previous view if the tree is inactive and kept-alive
    if (inactive) {
      return h(cache[name], data, children)
    }
 
    var matched =  route.matched [depth]; // get the routing object of the current level from the matched attribute, where the components to be rendered are saved. This is what we have done through app$ route.matched Gets the object
    // render empty node if no matched route
    if (!matched) {
      cache[name] = null;
      return h()
    }

    var component = cache[name] =  matched.components [name]; // get the components to be rendered

    // attach instance registration hook
    // this will be called in the instance's injected lifecycle hooks
    data.registerRouteInstance = function (vm, val) {
      // val could be undefined for unregistration
      var current = matched.instances[name];
      if (
        (val && current !== vm) ||
        (!val && current === vm)
      ) {
        matched.instances[name] = val;
      }
    }

    // also register instance in prepatch hook
    // in case the same component instance is reused across different routes
    ;(data.hook || (data.hook = {})).prepatch = function (_, vnode) {
      matched.instances[name] = vnode.componentInstance;
    };

    // resolve props
    var propsToPass = data.props = resolveProps(route, matched.props && matched.props[name]);
    if (propsToPass) {
      // clone to prevent mutation
      propsToPass = data.props = extend({}, propsToPass);
      // pass non-declared props as attrs
      var attrs = data.attrs = data.attrs || {};
      for (var key in propsToPass) {
        if (!component.props || !(key in component.props)) {
          attrs[key] = propsToPass[key];
          delete propsToPass[key];
        }
      }
    }

    Return H (component, data, children) // finally render the component
  }
}

By reading the source code, we know that router view determines the nesting level of the current component, and then through this level, it starts from route.matches In the array, we need to get the components that need to be rendered in the array. Finally, we call the global $createElement to create the corresponding VNode to finish rendering.

Recommended Today

[cmake series] (4) test with Google test

Today, let’s talk about the cmake test. However, we are still talking about C + + testing. Cmake provides us with perfect testing support, for example, it has a special module ctest. Cmake native test support The cmake native support test is very simple, with only two functions: enable_testing() add_test(NAME <name> COMMAND <command> [<arg>…] [CONFIGURATIONS […]