记录Vue3项目中的各类问题

头一次开发Vue3项目,之前都是使用Vue2进行的开发,所以多学习多总结快速适应吧。

一、项目 Bug

1、测试环境图片展示失败

bug 背景:

本地开发,项目图片正常展示,到了测试环境上,图片展示不出来了。那就查吧:


  • 问:项目里的 svg 图片 build 打包构建后在 dist / assets 下面没有怎么回事?

SVG 打包后 dist/assets 缺失常见原因 & 排查(Vite/Webpack 通用)

一、Vite 项目(最常用)

1. 引入方式错误(不被资源插件捕获)

  1. 字符串直接写路径(不会打包复制)
javascript 复制代码
// 无效,vite不解析字符串路径
icon: './assets/icon.svg'

改用 import 引入 :import IconSvg from '@/assets/icon.svg'

javascript 复制代码
import IconSvg from '@/assets/icon.svg'
icon: IconSvg

svg-sprite-loader / vite-plugin-svg-icons 托管 svg

插件会把 svg 编译成 sprite 内联符号不会输出单独 svg 文件到 dist/assets(正常现象)

特征:页面用 <svg-icon name="xxx"/> 使用,dist 找不到原 svg 文件

2. 配置排除 / 静态资源过滤

  • vite.config build.rollupOptions.external 把 svg 外部化
  • 资源目录不在 vite 解析的 public/src/assets 扫描范围

3. 放在 public 文件夹

public 内资源 原路径直接输出根目录 ,不在 assets/

public/a.svg → dist/a.svg

二、Webpack/VueCli 项目

  1. svg 被 svg-sprite-loader 处理:编译成雪碧图,无单独 dist 文件
  2. file-loader / asset-module 配置 type:'asset/inline':svg 转 base64 内嵌 js,不生成文件
javascript 复制代码
// webpack asset配置 内嵌则无实体文件
{ test:/\.svg/, type:'asset/inline' }

改成 asset/resource 才会打包出实体文件到 assets

三、快速排查步骤

  1. 搜索项目是否装了 vite-plugin-svg-icons、svg-sprite-loader → 大概率被内联
  2. 改成**import xxx from 'xxx.svg'**重新 build,看是否生成
  3. 查看 svg 存放目录:public→dist 根目录;src/assets→dist/assets
  4. 搜索配置文件externalexclude是否忽略 svg

  • 问:在 vue setup 里面怎么写

分两种场景(Vue3 + setup)

场景 1:想要打包出单独 svg 文件到 dist/assets(找不到文件就是用了精灵图插件)

html 复制代码
<template>
  <!-- 直接用引入变量 -->
  <img :src="svgImg" alt="" />
</template>

<script setup>
// 引入src/assets里svg,打包会进dist/assets
import svgImg from '@/assets/xxx.svg'
</script>

场景 2:项目用了 vite-plugin-svg-icons / svg-sprite(图标精灵,不会打包出单独 svg)

特点:dist/assets 不会生成原 svg 文件,是正常的

html 复制代码
<template>
  <svg-icon name="xxx" />
</template>

<script setup>
// 无需import,插件自动注册
</script>

场景 3:svg 放 public(打包在 dist 根目录,不在 assets)

html 复制代码
<template>
  <img src="/xxx.svg" />
</template>

想要打包输出独立 svg 文件解决办法

  1. 图标类 svg 继续用 svg-icon(不生成文件)
  2. 需要实体文件的 svg,直接 import 引入,不要放到 svg 图标目录⭐️

  • 问:项目里好像没有配置@/,控制台报错了

答:

没有配置别名 @,改用相对路径写法(setup 直接可用)

1、普通 svg 生成 dist/assets(打包出文件)

html 复制代码
<template>
  <img :src="iconSvg" />
</template>
<script setup>
// 从当前文件位置去找assets,../回退层级
import iconSvg from '../assets/xxx.svg'
</script>

目录举例:views/index.vue → ../assets/xxx.svg

components/xx.vue → ../../assets/xxx.svg

2、public 下 svg(打包在 dist 根目录,不在 assets)

html 复制代码
<template>
  <img src="/xxx.svg" />
</template>

3、svg-icon 精灵图标(不产出 dist 单独文件)

html 复制代码
<template>
  <svg-icon name="xxx"></svg-icon>
</template>

补充: vite 添加 @别名(一劳永逸)

vite.config.js

javascript 复制代码
import { defineConfig } from 'vite'
import { resolve } from 'path'
export default defineConfig({
  resolve:{
    alias:{
      '@': resolve(__dirname,'src')
    }
  }
})

配完重启项目就能用 @/assets


  • "iconSvg" is declared but its value is never read.

报错:iconSvg 声明未使用(eslint 未使用变量校验)

1、原因

<script>里定义了 const iconSvg = xxx,但 模板、JS 全程没用到这个变量,eslint 报错。

2、三种解决

① 删掉没用的变量(最优)

javascript 复制代码
// 删除这行
// const iconSvg = 'xxx'

② 确实后续要用,临时注释忽略单行

javascript 复制代码
// eslint-disable-next-line no-unused-vars
const iconSvg = ''

③ eslint 全局关闭(不推荐)

javascript 复制代码
// .eslintrc
rules: {
  "no-unused-vars": "off"
}

补充:如果是模板用到了还报错

检查:变量名大小写 iconSvg / iconSVG 不一致。


2、控制台报错相关

bug 背景:

本地开发,控制台报错:nodes is not iterable.

javascript 复制代码
/**
 * 递归查找指定ID的树节点
 * @param id 节点ID
 * @returns 节点对象 / null
 */
function findNode(id: string): OrgTreeNode | null {
  function walk(nodes: OrgTreeNode[]): OrgTreeNode | null {
    for (const n of nodes) {
      if (n.id === id) return n
      if (n.children) {
        const found = walk(n.children)
        if (found) return found
      }
    }
    return null
  }
  return walk(mockOrgTree)
}

报错原因

nodes is not iterable = 传入的 n.children 不是数组(undefined /null/ 对象),不能用 for...of 遍历

树节点里部分节点没有 children 字段、或 children: null / {},直接传给 walk 循环报错。

修复代码

javascript 复制代码
/**
 * 递归查找指定ID的树节点
 * @param id 节点ID
 * @returns 节点对象 / null
 */
function findNode(id: string): OrgTreeNode | null {
  function walk(nodes: OrgTreeNode[]): OrgTreeNode | null {
    // 兜底:非数组直接终止遍历
    if (!Array.isArray(nodes)) return null

    for (const n of nodes) {
      if (n.id === id) return n
      // 只有children是数组才递归
      if (n.children && Array.isArray(n.children)) {
        const found = walk(n.children)
        if (found) return found
      }
    }
    return null
  }
  // 顶层mockOrgTree也做数组校验
  return Array.isArray(mockOrgTree) ? walk(mockOrgTree) : null
}

关键点改动说明

  1. walk 开头增加 Array.isArray(nodes) 判断,非数组直接返回null,避免for...of遍历异常
  2. 递归前校验 n.children 是数组 再进入walk
  3. 入口调用校验根数据mockOrgTree是否为数组

可选:类型层面根治(修改 OrgTreeNode)

javascript 复制代码
interface OrgTreeNode {
  id: string
  // 强制children可选、类型只能是数组 | undefined,杜绝null/其他类型
  children?: OrgTreeNode[]
}

if(findNode(id)?.type === 'person') continue ,

if 里面的判断条件是 true 了,continue 下一行的代码,

const parent = findPersonParentDeptId(id) ,为什么执行不到了呢?

先解答核心问题:

if(findNode(id)?.type === 'person') continue 导致后续代码不执行原因

javascript 复制代码
if (findNode(id)?.type === 'person') continue 
const parent = findPersonParentDeptId(id)

逻辑释义

  1. continue作用:跳出当前本次 for 循环,直接进入下一次循环迭代
    • id是人员(type='person'),if条件=true → 执行continue
    • continue 会终止本轮循环剩余所有代码 ,后面 const parent = ...personSet.add(id) 全都跳过,直接开启下一轮 for(const id of rawIds)
  2. 这段代码业务逻辑:

如果当前选中 ID 是 人员 ,先去查找人员所属父部门;若父部门已经被整体勾选在部门集合deptSet里,则 不再单独把这个人存入人员列表 (部门全选自动包含下属人员,人员不用重复勾选)。所以:type=person 不 continue 才走下面去判断父部门,你现在写反了条件!

错误原代码

javascript 复制代码
if (findNode(id)?.type === 'person') continue // 人直接跳过,逻辑反了
const parent = findPersonParentDeptId(id)
if (parent && deptSet.has(parent)) continue
personSet.add(id)

修正代码

javascript 复制代码
// 只处理人员类型数据,非人员直接跳过
if (findNode(id)?.type !== 'person') continue
const parent = findPersonParentDeptId(id)
// 人员的父部门已被全选,则该人员不需要单独选中
if (parent && deptSet.has(parent)) continue
personSet.add(id)

总结

  1. 原代码 BUG 根源if(findNode(id)?.type === 'person') continue 写反条件,person 直接 continue 跳过父部门判断,改为 !== person continue 即可;
  2. continue 只作用 当前 for 循环单次迭代,触发后本循环剩余代码全部不执行,直接下一轮循环。

未完待续loading...

相关推荐
亿元程序员1 小时前
Cocos游戏开发中的弯的箭头游戏效果
前端
ct9781 小时前
Promise
前端·javascript·vue.js
怕浪猫1 小时前
Electron 开发实战(十一):自动更新机制|服务架构、公私网更新、版本回滚全解
前端·javascript·electron
AI视觉网奇1 小时前
three-bvh-csg glb分割
开发语言·前端·javascript
zhangfeng11331 小时前
workbuddy ,node.js 每次会在 项目目录上安装 node_modules,能不能一次安装多次使用,为什么 npm 不把包装在全局
前端·npm·node.js
一次旅行1 小时前
CopilotKit实战:用生成式UI打造智能Agent前端
前端·人工智能·ui
禅思院1 小时前
大列表性能优化 · 工程实战·四
开发语言·前端·性能优化·前端框架·php·异步加载
rising start1 小时前
五、Vue3 ref 用法 + Props 完整指南
前端·javascript·vue.js
web打印社区1 小时前
前端html转换pdf并静默打印pdf最佳实现路径
前端·javascript·vue.js·electron·html