The left navigation bar needs to be used in work. When the right window is switched, the address will change. The left navigation bar needs to match the corresponding menu and highlight it.

The component structure is basically as follows. Every time you click on the menu to expand and collapse, NavItem is remounted to view the source code of elementUI. The original ElMenu key is set to key={+this.collapse}, so vue will directly create a new ElMenu when the key is different during patch, and all the sub-components will also be rebuilt. A needValidate state is maintained in the NavItem component, which is initialized again after each mount. What is the reason for setting the ElMenu key?

<template>
  <el-row class="tac">
    <el-menu
      class="el-menu-vertical-demo"
      :collapse="isCollapse"
      :collapse-transition="false"
    >
      <nav-item :menu="navList" />
    </el-menu>
  </el-row>
</template>
<script>
import { mapState } from "vuex";
import NavItem from "./NavItem2.vue";
export default {
  name: "LeftNav".components: { NavItem },
  data() {
    NavItem;
    return {
      navList: [{path: "/index1".label: "Navigation one".icon: "el-icon-location" },
        { path: "/index2".label: "Navigation 2".icon: "el-icon-menu" },
        { path: "/index3".label: "Navigation three".icon: "el-icon-document"},]}; },methods: {},
  computed: {
    ...mapState(["isCollapse"]),},mounted() {
    console.log("nav2 mounted");
  },
  updated() {
    console.log("nav2 updated"); }};</script>
Copy the code
<template>
  <div>
      <el-menu-item
        v-for="item in menu"
        :class="{ 'is-active': vaildAvtive(item) }"
        :index="item.path"
        :key="item.path"
        @click="click()"
      >
        <i :class="item.icon" />
        <span slot="title">{{ item.label }}</span>
      </el-menu-item>
  </div>
</template>
<script>
export default {
  name: "NavItem".props: ["menu"."collapse"].data() {
    return {needValidate: false};
  },
  methods: {
    click() {
      this.$store.commit("changeCollapse");
    },
    vaildAvtive(){}},mounted() {
    console.log("nav2 item mounted"); }};</script>
Copy the code
// \element-ui\packages\menu\src\menu.vue
export default {
  name: 'ElMenu',

  render (h) {
    const component = (
      <ul
        role="menubar"
        key={ +this.collapse} // Every time a toggle collapses, it changes, and all child nodes are redonedestroy, the new child nodemount
        style={{ backgroundColor: this.backgroundColor| | '}}class={{
          'el-menu--horizontal': this.mode= = ='horizontal',
          'el-menu--collapse': this.collapse,"el-menu": true
        }}
      >
        { this.$slots.default }
      </ul>); . }Copy the code
 return function patch (oldVnode, vnode, hydrating, removeOnly) {
    if (isUndef(vnode)) {
      if (isDef(oldVnode)) { invokeDestroyHook(oldVnode); }
      return
    }

    var isInitialPatch = false;
    var insertedVnodeQueue = [];

    if (isUndef(oldVnode)) {
      // empty mount (likely as component), create new root element
      isInitialPatch = true;
      createElm(vnode, insertedVnodeQueue);
    } else {
      var isRealElement = isDef(oldVnode.nodeType);
      // Check whether two vNodes are the same
      if(! isRealElement && sameVnode(oldVnode, vnode)) {// Compare if they are the same
        // patch existing root node
        patchVnode(oldVnode, vnode, insertedVnodeQueue, null.null, removeOnly);
      } else {
      // If not, oldVnode will be removed and new vNodes will be created and inserted
        if (isRealElement) {
          // mounting to a real element
          // check if this is server-rendered content and if we can perform
          // a successful hydration.
          if (oldVnode.nodeType === 1 && oldVnode.hasAttribute(SSR_ATTR)) {
            oldVnode.removeAttribute(SSR_ATTR);
            hydrating = true;
          }
          if (isTrue(hydrating)) {
            if (hydrate(oldVnode, vnode, insertedVnodeQueue)) {
              invokeInsertHook(vnode, insertedVnodeQueue, true);
              return oldVnode
            } else if(process.env.NODE_ENV ! = ='production') {
              warn(
                'The client-side rendered virtual DOM tree is not matching ' +
                'server-rendered content. This is likely caused by incorrect ' +
                'HTML markup, for example nesting block-level elements inside ' +
                '<p>, or missing <tbody>. Bailing hydration and performing ' +
                'full client-side render.'); }}// either not server-rendered, or hydration failed.
          // create an empty node and replace it
          oldVnode = emptyNodeAt(oldVnode);
        }

        // replacing existing element
        var oldElm = oldVnode.elm;
        var parentElm = nodeOps.parentNode(oldElm);

        // create new node
        createElm(
          vnode,
          insertedVnodeQueue,
          // extremely rare edge case: do not insert if old element is in a
          // leaving transition. Only happens when combining transition +
          // keep-alive + HOCs. (#4590)
          oldElm._leaveCb ? null : parentElm,
          nodeOps.nextSibling(oldElm)
        );

        // update parent placeholder node element, recursively
        if (isDef(vnode.parent)) {
          var ancestor = vnode.parent;
          var patchable = isPatchable(vnode);
          while (ancestor) {
            for (var i = 0; i < cbs.destroy.length; ++i) {
              cbs.destroy[i](ancestor);
            }
            ancestor.elm = vnode.elm;
            if (patchable) {
              for (var i$1 = 0; i$1 < cbs.create.length; ++i$1) {
                cbs.create[i$1](emptyNode, ancestor);
              }
              / / # 6513
              // invoke insert hooks that may have been merged by create hooks.
              // e.g. for directives that uses the "inserted" hook.
              var insert = ancestor.data.hook.insert;
              if (insert.merged) {
                // start at index 1 to avoid re-invoking component mounted hook
                for (var i$2 = 1; i$2 < insert.fns.length; i$2++) {
                  insert.fns[i$2] (); }}}else{ registerRef(ancestor); } ancestor = ancestor.parent; }}// destroy old node
        if (isDef(parentElm)) {
          removeVnodes([oldVnode], 0.0);
        } else if (isDef(oldVnode.tag)) {
          invokeDestroyHook(oldVnode);
        }
      }
    }

    invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch);
    return vnode.elm
  }
}

Copy the code
function sameVnode (a, b) {
  return (
    // Compare key first
    a.key === b.key && (
      (
        a.tag === b.tag &&
        a.isComment === b.isComment &&
        isDef(a.data) === isDef(b.data) &&
        sameInputType(a, b)
      ) || (
        isTrue(a.isAsyncPlaceholder) &&
        a.asyncFactory === b.asyncFactory &&
        isUndef(b.asyncFactory.error)
      )
    )
  )
}
Copy the code