1. 效果图
如图是我想要的效果,这是两个菜单页面,在页面标题前会有一个小图标。
1. 先看代码
这是路由配置文件,是这两个页面的一些配置,其中meta.icon
是图标的相对路径。
/src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/taskList',
name: 'TaskList',
component: () => import('../views/task/TaskList.vue'),
meta: {title: '任务列表', menu: true, show: true, icon: './assets/list.png'}
},
{
path: '/addTask',
name: 'AddTask',
component: () => import('../views/task/AddTask.vue'),
meta: {title: '添加任务', menu: true, show: true, icon: './assets/add.png'}
}
]
})
export default router
在项目路径下,这两个图片是在/src/assets/
确实存在的。
在App.vue
中,侧边栏容器显示菜单图标,图片的路径route.meta.icon
来自路由配置文件,通过getIcon()
方法返回图标的绝对路径。
<template>
<div class="app">
<!--header 顶栏容器-->
<el-container class="middle">
<!--aside 侧边栏容器-->
<el-aside class="aside">
<el-menu router default-active="1">
<el-menu-item v-for="route in routes" :key="route.path" :index="route.path">
<div class="menu-item">
<img :src="getIcon(route.meta.icon)" :alt="route.meta.title" class="menu-icon">
{{ route.meta.title }}
</div>
</el-menu-item>
</el-menu>
</el-aside>
<!--main 主要区域容器-->
</el-container>
<!--footer 底栏容器-->
</el-container>
</div>
</div>
</template>
<script>
const getIcon = (icon) => {
return new URL(icon, import.meta.url).href
}
</script>
2. 发现问题
在开发环境中这样获取图标的绝对路径是没问题的,图标的路径如下。
但是在生产环境中却加载不到图标,路径是错的。
图标绝对路径如下,执行npm run build
之后构建的/dist目录下也不存在这个路径。
3. 分析问题
以下是来自DeepSeek的回答。
App.vue中的getIcon函数使用new URL(icon, import.meta.url).href。这里的import.meta.url是当前模块(App.vue)的URL。在开发环境中,App.vue可能位于项目的根目录,所以./assets相对于App.vue是正确的。但是在生产环境中,当资源被打包后,App.vue的位置可能发生变化,导致相对路径解析错误,从而生成错误的URL。
生产环境下,打包后的结构是dist目录,App.vue可能被编译到assets目录下的某个JS文件中,这时候new URL('./assets/list.png', import.meta.url)会解析到assets目录下的assets/list.png,导致路径重复。
开发环境:Vite服务器直接提供源码,相对路径./assets/list/png
能正确映射到src/assets
目录。
生产环境:Vite打包时会对静态资源进行哈希处理并重新组织目录结构,直接实录字符串路径无法动态适配这些变化。
通过import
引入图片,vite会在构建时将其识别为静态依赖,自动处理路径并替换为生产环境下的正确路径,确保引用无误。
4. 解决问题
所以,问题还是出在路径的解析上。
在路由配置中,使用import
语句引入图片,在meta.icon
中使用引入后的路径。
/src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import listIcon from '../assets/list.png'
import addIcon from '../assets/add.png'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/taskList',
name: 'TaskList',
component: () => import('../views/task/TaskList.vue'),
meta: {title: '任务列表', menu: true, show: true, icon: listIcon}
},
{
path: '/addTask',
name: 'AddTask',
component: () => import('../views/task/AddTask.vue'),
meta: {title: '添加任务', menu: true, show: true, icon: addIcon}
}
]
})
export default router
在App.vue
中,直接使用route.meta.icon
作为图标的src
。
<img :src="route.meta.icon" :alt="route.meta.title" class="menu-icon">
5. 测试一下
5.1 开发环境
5.2 生产环境
以上。