前端Vue+elementUi框架动态菜单渲染问题,为什么会重复渲染组件?

新手上路,请多包涵

在自己研发一个框架来提升自己的技术的时候出现了如下问题
路由嵌套的时候框架也会嵌套单个路由则会正常显示
以及加入path路径为外部链接的时候报错
Error in render: "ReferenceError: process is not defined"

以下是我的代码块(MenuItem.vue)

<template>
  <div v-if="!item.meta.hidden">
    <router-link tag="span" :to="resolvePath()" v-if="!item.children">
      <el-menu-item :index="resolvePath()">
        <i :class="item.meta.icon"></i>
        <span slot="title">{{ item.meta.title }}</span>
      </el-menu-item>
    </router-link>

    <el-submenu :index="resolvePath()" v-else>
      <template slot="title">
        <i :class="item.meta.icon"></i>
        <span slot="title">{{ item.meta.title }}</span>
      </template>
      <menu-item
        v-for="(route, index) in item.children"
        :key="index"
        :item="route"
        :fatherPath="resolvePath(route.path)"
      >
      </menu-item>
    </el-submenu>
  </div>
</template>

<script>
import path from 'path'

export default {
  name: 'MenuItem',
  props: {
    // 上一级的路由信息
    item: {
      type: Object,
      default: null
    },
    // 上一级的路径
    fatherPath: {
      type: String,
      default: ''
    }
  },
  data () {
    return {}
  },
  methods: {
    resolvePath (routePath = '') {
      return path.resolve(this.fatherPath, routePath)
    }
  }
}
</script>

vue.config.js

const { defineConfig } = require('@vue/cli-service')

module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    open: true // 运行项目后自动打开浏览器
  },
  configureWebpack: {
    resolve: {
      fallback: {
        path: require.resolve('path-browserify')
      }
    }
  }
})

(package.json)

{
  "name": "laohe-ui",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.38.1",
    "element-ui": "^2.15.14",
    "i": "^0.3.7",
    "npm": "^10.9.0",
    "path-browserify": "^1.0.1",
    "vue": "^2.6.14",
    "vue-router": "^3.5.1",
    "vuex": "^3.6.2"
  },
  "devDependencies": {
    "@babel/core": "^7.12.16",
    "@babel/eslint-parser": "^7.12.16",
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-eslint": "~5.0.0",
    "@vue/cli-plugin-router": "~5.0.0",
    "@vue/cli-plugin-vuex": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "@vue/eslint-config-standard": "^6.1.0",
    "eslint": "^7.32.0",
    "eslint-plugin-import": "^2.25.3",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-promise": "^5.1.0",
    "eslint-plugin-vue": "^7.0.0",
    "sass": "^1.32.7",
    "sass-loader": "^12.0.0",
    "vue-template-compiler": "^2.6.14"
  }
}

layoutsIndex.vue

<template>
  <div>
    <!-- 判断是否在空白页打开 -->
    <template v-if="!isOneself">
      <div class="app-wrapper">
        <el-container class="main-container">
          <!-- 左侧菜单 -->
          <SidebarMenu
            background-color="#2C3E50"
            text-color="#ECF0F1"
            active-text-color="#3498DB"
            @open="handleOpen"
            @close="handleClose" />
          <el-container class="vertical-layout">
            <!-- 头部 -->
            <Navbar />
            <!-- 主体 -->
            <el-main class="main-content">
              <AppContent />
            </el-main>
          </el-container>
        </el-container>
      </div>
    </template>
    <!-- 如果在空白页打开则不显示框架 -->
    <template v-else>
      <AppContent />
    </template>
  </div>
</template>

<script>
import AppContent from '@/layouts/components/AppContent.vue'
import SidebarMenu from '@/layouts/components/SidebarMenu.vue'
import Navbar from '@/layouts/components/Navbar.vue'

export default {
  name: 'layoutsIndex',
  components: { Navbar, SidebarMenu, AppContent },
  data () {
    return {
      isOneself: false
    }
  },
  mounted () {
    // 获取当前路由是否是独自打开的
    this.isOneself = this.$route.meta.oneself
  },
  watch: {
    // 监听路由变化,实时获取路由信息
    $route: function (newVal) {
      this.isOneself = newVal.meta.oneself
    }
  },
  methods: {
    handleOpen (key, keyPath) {
      console.log(key, keyPath)
    },
    handleClose (key, keyPath) {
      console.log(key, keyPath)
    }
  }
}
</script>

<style scoped lang="scss">
.app-wrapper {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.main-container {
  display: flex;
}

.vertical-layout {
  display: flex;
  flex-direction: column;
}

.main-content {
  flex-grow: 1;
  padding: 20px;
  background-color: #F9FAFB;
}
</style>

以及router.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Layouts from '@/layouts/layoutsIndex.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '',
    redirect: 'index',
    component: Layouts,
    children: [
      {
        path: '/index',
        name: 'index',
        meta: { title: '首页', icon: 'el-icon-s-home' },
        component: () => import('@/views/userIndex.vue')
      },
      {
        path: '/test',
        name: 'test',
        meta: { title: '多级路由测试', icon: 'el-icon-s-home', oneself: true },
        component: Layouts,
        children: [
          {
            path: 'about',
            name: 'about',
            meta: { title: '关于', icon: 'el-icon-s-home' },
            component: () => import('@/views/test/AboutView.vue')
          }
        ]
      },
      {
        path: '/about',
        name: 'about',
        meta: { title: '关于', icon: 'el-icon-s-home' },
        component: () => import('@/views/test/AboutView.vue')
      },
      {
        path: '/login',
        name: 'login',
        meta: { title: '登录页', icon: 'el-icon-user-solid', oneself: true, hidden: true },
        component: () => import('@/views/userLogin.vue')
      }
    ]
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

// 前置路由拦截器
router.beforeEach((to, from, next) => {
  // 设置当前页签名称
  document.title = to.name
  next()
})

export default router

以下是我的项目结构

尝试过重写解析path方法也是不行

resolvePaths (fatherPath, routePath) {
  // 确保路径以 '/' 开头
  if (!fatherPath.endsWith('/')) {
    fatherPath += '/'
  }

  // 如果 routePath 是绝对路径,直接返回
  if (routePath.startsWith('/')) {
    return routePath
  }

  // 拼接路径
  return fatherPath + routePath
}
阅读 1.1k
1 个回答
✓ 已被采纳

image.png你子路由使用组件也是layouts所以嵌套渲染了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏