news 2026/10/6 4:47:04

Vue 2 项目维护全景笔记:环境、组件、集成与部署面试一网打尽

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue 2 项目维护全景笔记:环境、组件、集成与部署面试一网打尽

2016年那会儿我刚入行前端,第一次打开 Vue 2 的文档就被简洁的 API 吸引住了。几年过去,Vue 3 早已成了新项目的默认选项,但你要是现在去接手一个企业级项目,或者去看那些还在稳定迭代的系统,大概率碰到的还是 Vue 2。这篇不是从零教学,而是我在持续维护 Vue 2 项目时沉淀下来的一份全景笔记:安装环境、依赖管理、路由插槽、样式折叠、m3u8 播放、地图集成、SSE 对接、打包含进 Spring Boot、源码怎么交给别人、面试常问什么,全都有。目标是帮你少踩我踩过的坑。

1. 为什么还在用 Vue 2:技术选型前的冷静思考

1.1 存量项目远比想象中多

很多人一听到 Vue 2 就是“该淘汰了”,但现实是,大量长期运营的后台管理系统、中台项目、老电商站点,核心代码还是 Vue 2。改造成本不是写两行代码那么简单:老的第三方组件库、同事习惯的写法、已经稳定运行多年的业务逻辑,都成了继续使用 Vue 2 的理由。尤其是那些基于 vue-cli 3/4、Element UI、Vant 2 搭建的项目,内部系统迭代几年后,直接升 Vue 3 的风险远大于收益。

我自己手上就有这样的项目,每年都要往上叠加需求。比起一门心思迁移,更实际的做法是把 Vue 2 的机制吃透,把该修的坑修好,把老代码维护利索。对新入行的朋友,我的建议也很直白:如果你的目标是快速进入团队干活,Vue 2 绝对是绕不开的一课;如果是从零做新项目,再考虑 Vue 3 也不迟。

1.2 Vue 2 与 Vue 3 核心差异速览

面试时被问到“Vue 2 和 Vue 3 的区别”,不要只答“Vue 3 更快”。核心区别要从三个角度看:

  • 响应式原理:Vue 2 用 Object.defineProperty 拦截对象的属性读写,数组通过重写方法实现;Vue 3 用 Proxy 直接拦截对象整体操作,支持新增属性、删除属性、Map/Set 等数据类型。
  • API 风格:Vue 2 主推 Options API,data/methods/computed/watch 分段写;Vue 3 同时提供 Composition API,把关联逻辑聚合到一起。
  • 构建与性能:Vue 3 代码基于 ES Module,利用 tree-shaking 按需打包,运行时体积更小;Vue 2.7 虽然也支持组合式 API,但底层仍是旧响应式方案。

Nuxt 和 Vue 的区别也常被混为一谈。Vue 是一个前端视图层框架,只负责页面渲染;Nuxt 是基于 Vue 的上层框架,帮你解决服务端渲染(SSR)、文件路由、SEO、中间件等工程化问题。Nuxt 2 对应 Vue 2,Nuxt 3 对应 Vue 3。简单类比:Vue 是发动机,Nuxt 是给你装好发动机、轮子、导航的整车。

1.3 一条务实的 Vue 2 学习路线

结合我带新人和面试候选人的经验,整理一条比较快的路线:先装环境跑通一个 demo,再啃模板语法、组件通信、生命周期;然后学路由和状态管理;接着看工程化配置,理解打包;最后找一个真实业务场景完整做一遍。顺序一定不要反,很多人上来就啃源码,结果连 computed 缓存特性都没搞明白。

这块就是热词里“vue 快速学习路线”的本意。我的建议是给自己定一个目标,比如两周之内做一个带登录、列表、详情、权限路由的 Vue 2 后管页面,比看十遍文档都管用。

2. 环境搭建与依赖安装:每个新手都要过的一关

2.1 初始化一个 Vue 2 项目的方式

目前初始化 Vue 2 项目有两条主流路径:用 vue-cli 4,或者用 Vite 加官方插件。vue-cli 老牌稳妥,命令很简单:

npm install -g @vue/cli vue create project-name

选预设的时候,注意选择 Vue 2 版本,别顺手选了 Vue 3。vue-cli 会生成完整的 Webpack 构建配置,开箱即用,适合业务项目。

如果不想用 Webpack,也可以用 Vite 搭配官方插件:

npm create vite@latest project-name -- --template vue npm i vite@3 vue@2.7 @vitejs/plugin-vue2

这里特别提醒:Vite 3 配 @vitejs/plugin-vue2 是稳定组合,Vite 4/5 不一定兼容 Vue 2 插件,这类版本错位问题排查起来很花时间,尽量按官方维护矩阵走。

2.2 安装依赖时最容易忽视的版本锁定问题

{Vue 2 项目依赖安装}有句口诀:先把 package.json 发给同事,别急着 npm install。因为很多老项目的依赖树经不起升级,npm 默认会按语义化版本拉新,如果某天一个子依赖悄悄升了主版本,整个构建就崩了。我的习惯是项目里同时维护 package-lock.json 和 .npmrc,安装命令固定为:

npm config set registry https://registry.npmmirror.com npm install --legacy-peer-deps

这里解释一下 --legacy-peer-deps 的作用。老项目里经常出现 Element UI 要求 peer 依赖 vue@^2.x,但 npm 7 以上会严格检查,导致安装失败;加了这个参数就跳过 peer 依赖校验,代价是可能忽略某些依赖冲突,所以装完一定要跑一遍构建和测试。

新手常见问题:拉下来的项目,npm install 半天装不上,最后发现是全局 Node 版本太高。Vue 2 + webpack 4 项目建议 Node 14/16,别轻易上 Node 18+,不然 node-sass 编译直接报错。

2.3 failed to load tsconfig '“@vue/tsconfig/tsconfig.web.json"':这个报错怎么处理

写 TS 的 Vue 2 项目偶尔会碰上这么一句:failed to load tsconfig '@vue/tsconfig/tsconfig.web.json': tsconfig not found。这个热词本身已经说明了场景。

我遇到的情况一般是两类:一是引用 @vue/tsconfig 这个包,但 node_modules 里根本没装,或装到了错误的版本;二是 monorepo 结构下相对路径解析失败。解决步骤按顺序来:

npm i -D @vue/tsconfig npx tsc --showConfig

先确认 @vue/tsconfig 的真实路径,再到 tsconfig.json 里改成可解析的相对路径。比如在 monorepo 的 apps/web 里,引用要写成 ../../packages/... 这种相对路径,不能写绝对包名。

还有一类情况是 vue-tsc 版本和 @vue/tsconfig 版本不匹配,导致 exports 字段不允许导入该子路径。解决方案是固定两边版本,或者把 include 改成更宽容的配置。

2.4 VSCode 里 .vue 标签跳转失效的解决方案

热词里有“vscode中点vue中的标签没有跳转”,这问题几乎每个 Vue 2 项目都碰到过。原因很简单:Vue 2 和 Vue 3 推荐的插件不一样,很多人装的是 Volar,但 Volar 对 Vue 2 的支持并不好。

我做 Vue 2 项目的插件组合是 Vetur,而不是 Volar。Vetur 装好之后,如果要支持在 template 里点击组件名跳到对应文件,需要手动开启一个隐藏配置:

"vetur.experimental.templateInterpolationService": true

搞完这个,按住 Ctrl 点击组件标签就能跳转。如果还不生效,检查 .vue 文件是否被 Vetur 识别,命令面板里输入 Vue: Restart Language Server,重启语言服务基本就好了。

3. 路由、插槽与样式折叠:Vue 2 组件的三大核心

3.1 从静态路由到动态路由

Vue 2 的路由用 vue-router,版本对应关系是 vue-router@3.x 配 Vue 2,版本一定不能装成 4.x,否则一启动就报匹配不到组件。基础路由很简单:

import Vue from 'vue' import Router from 'vue-router' import Home from './views/Home.vue' Vue.use(Router) export default new Router({ mode: 'history', routes: [ { path: '/', name: 'home', component: Home } ] })

动态路由常见的应用场景是权限系统。登录后拿到菜单数据,通过 addRoutes 动态注入。注意 addRoutes 是 Vue Router 3 的 API,Router 4 改成了 addRoute;Vue 2 项目里不要用错。动态路由的核心思路是:把权限映射成每个路由的 meta,比如 meta: { roles: ['admin'] },然后在全局前置守卫里做判断。

router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (!token && to.path !== '/login') { next('/login') } else { next() } })

3.2 路由参数传递:query 和 params 的区别与坑

Vue 2 路由参数是面试高频题,实际开发里几乎天天用。query 和 params 的区别要记牢:

方式写法URL 表现刷新后
querythis.$router.push({ path: '/detail', query: { id: 1 } })/detail?id=1不丢
params + namethis.$router.push({ name: 'detail', params: { id: 1 } })/detail(不显示参数)丢
路径参数this.$router.push({ path: '/detail/1' }),路由定义 /detail/:id/detail/1不丢

最容易踩的坑是第二种,params 配合 name 跳转,页面刷新后 this.$route.params.id 变成 undefined。如果你希望刷新后参数还在,要么用 query,要么用路径参数。本质上是因为非路径的 params 只存在于当前内存路由记录中,刷新后路由重新匹配,找不到对应参数。

实战里我倾向于把关键参数都用路径或 query 传递,params 只用来传一些非必选的辅助状态。组件里接收参数最好用 props 解耦:

props: ['id']

路由配置加上 props: true,这样组件不依赖 $route,测试和复用都方便。

3.3 插槽的三种形态:基础组件封装的关键

插槽是 Vue 2 组件封装里最顺手也最容易被忽略的能力。默认插槽最直白,父组件往子组件标签里塞内容,子组件用 接住。具名插槽解决一个组件多处需要自定义区域的场景,比如 dialog 的头部、底部按钮,用 name 区分。

作用域插槽才是重点,它让父组件能拿到子组件内部的数据。Vue 2.6 之后统一了 v-slot 写法:

<!-- 子组件 --> <slot name="item" :data="itemData"></slot> <!-- 父组件 --> <template v-slot:item="{ data }"> <span>{{ data.name }}</span> </template>

开发表格、下拉、列表这类通用组件时,作用域插槽几乎是刚需。它可以让你在不改子组件源码的前提下,把每一行的渲染逻辑完全交给业务方。面试里提到的“slot vue”基本都是这个知识点。

3.4 内容折叠展开:一个容易做丑的交互

Vue 2 里做折叠展开,最基础的方案是 v-show 或 v-if。v-show 适合频繁切换但内容不重的场景,v-if 适合内容里包含大量组件、不想初始化的场景。但用户想要的很可能是带动画的流畅折叠,这里就要用 transition 和 height 动画。

我的做法是给容器设置 max-height,展开时从 0 过渡到内容高度。这个方案的缺点是内容高度不固定时,需要 JS 动态测量 scrollHeight:

this.isOpen ? (box.style.height = box.scrollHeight + 'px') : (box.style.height = 0)

过渡结束之后再把 height 改成 auto,避免窗口缩放时内容被截断。另一个更现代的方案是用 CSS grid 的 fr 技巧:

.fold { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .3s; } .fold.open { grid-template-rows: 1fr; } .fold > .inner { overflow: hidden; }

这个方案不需要 JS 测量高度,动画还平滑,兼容性也可以接受。Vue 2 里给 .fold 动态绑定 open class 就行。

注意“vue div超出隐藏”也是同一类样式问题。单行超出隐藏是 text-overflow: ellipsis,多行要用 -webkit-line-clamp;但如果这个 div 是 flex 布局的 item,记得给 min-width: 0,不然依旧会撑破布局。这个坑我替你们踩过了。

4. 业务集成实战:视频、图表、地图、上传

4.1 Vue 2 中播放 m3u8 流媒体

“vue播放m3u8免安装”这词儿点出了一个常见需求:网页直接播 HLS 格式视频。原生 video 标签默认不解析 .m3u8,必须要借助 hls.js 来做。安装方式:

npm install hls.js

组件里的核心逻辑是:拿到视频元素引用,创建 Hls 实例,监听 URL 并绑定:

if (Hls.isSupported()) { const hls = new Hls() hls.loadSource(videoSrc) hls.attachMedia(this.$refs.video) this.hls = hls }

注意两点:一是 Hls.isSupported() 在 Safari 里是 false,因为 Safari 原生支持 HLS,这种情况直接走原生 video.src 就行;二是 beforeDestroy 里一定要 hls.destroy(),否则播放器实例残留会导致内存泄漏和音频继续播放。

如果不想用 npm 安装,也可以直接在 index.html 里通过 script 标签引入 hls.min.js 的 CDN,Vue 2 里通过 window.Hls 使用,功能完全一致。这是“免安装”的常见做法。还有一个容易混淆的点,热词里“vue .acc播放器”其实大概率说的是音频播放器,音频用原生 audio 标签直接 src 就能播,不涉及 m3u8。

4.2 ECharts 双柱状统计图:从初始化到销毁

“vue中用echarts画两个柱状统计图”是后台项目最高频的可视化需求。ECharts 接入 Vue 2 的思路不要搞复杂,直接在 mounted 里初始化:

this.chart = echarts.init(this.$refs.chart) this.chart.setOption({ legend: { data: ['本月', '上月'] }, xAxis: { data: ['1月', '2月', '3月'] }, yAxis: {}, series: [ { name: '本月', type: 'bar', data: [120, 200, 150] }, { name: '上月', type: 'bar', data: [80, 140, 110] } ] })

双柱状图的关键配置:series 数组里放两个 bar 对象,xAxis 要共用,否则会出现两组坐标。样式上可以控制 barWidth 和 barGap,两个柱子之间留一点间距更美观。

真正要注意的是生命周期。图表所在的容器如果初始是隐藏状态,初始化时宽度会是 0,画出来就是一张废图。解决办法:容器显示后再调用 this.chart.resize(),或者用 nextTick 延迟初始化。还有,beforeDestroy 里一定要 this.chart.dispose(),卸载组件时清掉 echarts 实例,不然切页多了,页面卡到怀疑人生。窗口 resize 事件也要在 mounted 里绑定、beforeDestroy 里解绑,并且 resize 时加个防抖。

4.3 Canvas 2D 在 Vue 2 中的正确用法

Canvas 2D 跟 Vue 的“数据驱动视图”思路天然冲突,因为 Canvas 本质是命令式绘制,我每次用的时候都会先跟团队说清楚:不要指望 Vue 帮我们画 Canvas,我们要在合适的时机自己调用 Canvas API。

Vue 2 项目里最常见的玩法是给 canvas 元素加 ref,然后在 mounted 里拿 DOM 画:

const canvas = this.$refs.canvas const ctx = canvas.getContext('2d') ctx.fillStyle = '#409EFF' ctx.fillRect(20, 20, 100, 100)

如果是画动态图形,比如跑一个粒子动画,需要 requestAnimationFrame 循环,同时要记住每帧清屏。组件销毁时 cancelAnimationFrame,否则后台页面挂着,几十个画布还在疯狂重绘,CPU 直接拉满。

Canvas 在 Vue 2 里另一个常见结合是图表填echarts;但有些轻量场景,比如签名板、图片水印、验证码,纯 Canvas 更灵活,不用引入大库。不过要注意,canvas 的绘制坐标不受 Vue 响应式驱动,一旦业务数据变化,必须手动重新绘制,所以最好把绘制逻辑封装成一个方法,数据变化后用 watch 触发重绘。

4.4 地图集成:Mapbox 和腾讯地图在 Vue 2 中的落地

热词里有两个地图相关:mapbox vue、用在 vue 里的腾讯地图。先说 Mapbox,安装 mapbox-gl 之后,在组件里初始化:

import mapboxgl from 'mapbox-gl' mapboxgl.accessToken = 'YOUR_TOKEN' this.map = new mapboxgl.Map({ container: this.$refs.map, style: 'mapbox://styles/mapbox/streets-v11', center: [116.397428, 39.90923], zoom: 12 })

Mapbox 的坑在于 token 和样式 URL,免费额度有限,超过请求量会黑屏。腾讯地图相对省心一些,直接用 TMap 和它的 key:

this.map = new TMap.Map(this.$refs.map, { center: new TMap.LatLng(39.90923, 116.397428), zoom: 12 })

不管哪家地图,共同注意点:容器一定要有明确的高度,否则地图初始化为 0 高度,只有滚动条没有图;初始化不要放在隐藏的 tab 页里,否则地图渲染错乱,需要调用 resize 重新计算;组件销毁前调用 map.remove() 或 destroy 释放资源。

4.5 多文件上传:从原生 Input 到组件化

Vue 2 的多文件上传,最简单的实现是 input 加 multiple:

<input type="file" multiple @change="handleUpload" />

选中多个文件后,遍历 files 列表,逐个转 FormData 后调用 axios:

for (const file of this.fileList) { const formData = new FormData() formData.append('file', file) await api.upload(formData) }

如果项目里用了 Element UI,el-upload 组件本身就是封装好的多文件上传统一方案,给 action 指定接口地址,on-success 里处理返回结果。进阶玩法是大文件切片:把文件拆成若干片并发上传,最后调一个合并接口。这一块面试常被追问,我会在最后总结里提一下思路,实现上核心就是 Blob.slice 和并发控制。

5. 前后端对接与部署:SSE、Spring Boot 和源码交付

5.1 Vue 2 + Python SSE:流式数据的正确接法

SSE(Server-Sent Events)在聊天、进度条、实时通知场景里很常用。“vue python sse”这个热词说明了很多人是在 Python 后端项目里碰到 SSE。前端常规用法是 EventSource:

const source = new EventSource('/api/stream') source.onmessage = (event) => { console.log(JSON.parse(event.data)) }

EventSource 的优点是自带断线重连,缺点是只能用 GET 请求,没法加自定义请求头。如果你的 Python 后端接口是 POST,或者需要带 token 认证,就得绕到 fetch 流式读取:

const response = await fetch('/api/stream', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + token }, body: JSON.stringify({ params: 1 }) }) const reader = response.body.getReader() const decoder = new TextDecoder() while (true) { const { value, done } = await reader.read() if (done) break const text = decoder.decode(value) // 按行解析 data: 前缀,再 JSON.parse console.log(text) }

SSE 的格式是连续的 text/event-stream,服务端通常发data: {...}\n\n。前端拿到的是原始字节流,需要自己按行切割和解析。我这里踩过最大的坑是忘了处理拆包和粘包,因为网络传输过程中一个 JSON 可能被拆成多次传输,也可能多个 data 合在一次返回里。稳妥做法是维护一个缓冲区,把 chunk 先拼接,再按换行符切出完整事件。

5.2 Vue 2 打包放进 Spring Boot:两个致命细节

“vue打包放进springboot中”是典型的单体部署方式。思路很简单:Vue 2 项目 npm run build 生成 dist,把 dist 复制到 Spring Boot 的 src/main/resources/static 下,启动后端就能访问。但有两个细节能让你一夜白发。

第一个是 publicPath。Vue 2 的 vue.config.js 里默认 publicPath 是 '/',如果你的后端在根路径部署没毛病,但只要 Spring Boot 配了 context-path,比如 /admin,静态资源请求就会 404。正确配置:

module.exports = { publicPath: process.env.NODE_ENV === 'production' ? '/admin/' : '/' }

第二个是路由的 history 模式和刷新 404。你 router 用了 history 模式,在 Spring Boot 里直接刷新 /admin/user 页面时会 404,因为后端没这个静态文件。解决方案是提供一个 fallback:让 Spring Boot 对所有不匹配 /api 的路径都转发到 index.html。这个用 Java Config 写一个 WebMvcConfigurer 就能搞定。如果不想动后端,也可以把 mode 改成 hash,URL 会带个 #,刷新不会 404,体验稍差但省事。

5.3 项目源码怎么发给别人:交接不是甩包裹

“vue项目源码怎么发给别人”这个热词背后,其实是交接协助的问题。我先说结论:不要把整个项目文件夹压缩发过去,因为 node_modules 动辄几百 MB,对方电脑环境跟你不一样,大概率跑不起来。

标准做法是把源码(不含 node_modules)打成压缩包,保留 package-lock.json 或 yarn.lock,再写一个 README,记录 Node 版本、依赖安装命令、启动命令、环境变量、后端接口地址。如果项目用了 .env.development 之类的环境配置,记得把示例文件也带上,把敏感字段脱敏。

如果双方都懂 Git,最好直接推一个仓库分支,让对方 clone。另外,有一些“老项目病”是交接专用问题:比如依赖里带 node-sass,换电脑就装不上。这种依赖在安装前要优先处理,要么换成 sass(dart-sass),要么把 Node 版本固定成能编译的那一个。源码交接这件事,真正做到位,是让对方 clone 下来执行两条命令就能跑起来。

6. 高频面试题速查:Vue 2 背这些就够

6.1 响应式原理:Object.defineProperty 的局限

Vue 2 面试必问响应式原理。Vue 2 初始化时遍历 data,通过 Object.defineProperty 给每个属性添加 getter/setter,同时为每个对象创建一个依赖收集器 dep。render 过程中读取属性会触发 getter,把当前 watcher 收集进 dep;属性改变时触发 setter,通知 watcher 重新渲染。

这个机制的硬伤是:直接给对象添加一个新属性 obj.newKey = 1,Vue 检测不到,因为没有 getter/setter。数组也是,只有 7 个会改变数组自身的方法被重写过,直接 arr[0] = 'xx' 不会触发更新。解决办法就是大家熟悉的 this.$set(obj, 'newKey', value)。这个原理解释清楚了,后面一系列坑都能想通。

6.2 生命周期顺序:父子组件谁先跑

Vue 2 生命周期顺序也是热门题。单个组件的顺序是 beforeCreate -> created -> beforeMount -> mounted -> beforeDestroy -> destroyed,配合 keep-alive 还有 activated/deactivated。面试更喜欢问父子组件嵌套时的顺序:父 beforeCreate、父 created、父 beforeMount、子 beforeCreate、子 created、子 beforeMount、子 mounted、父 mounted。销毁顺序反过来,先父 beforeDestroy,再子 beforeDestroy,最后子 destroyed 和父 destroyed。

理解这个顺序对实际开发很重要。在 created 里拿接口数据,在 mounted 里操作 DOM,在 beforeDestroy 里清除定时器、取消事件监听、销毁图表实例,这些都是 Vue 2 项目的日常。我在项目里见过有人在 mounted 里拿不到 DOM 高度,基本就是没理解异步渲染和 nextTick 的关系。

6.3 组件通信方式全盘点

组件通信的完整答案包括:

  • props / $emit:父子组件单向数据流。
  • $refs / $parent / $children:直接访问实例,简单但侵入性强。
  • $attrs / $listeners:祖先组件给孙组件传属性和事件,常用于二次封装第三方组件。
  • provide / inject:跨层级注入,适合封装高阶组件,但不具备响应式,使用时注意。
  • EventBus:平级通信或跨组件通信,用 new Vue() 做事件中心,适合简单场景但容易混乱。
  • Vuex:全局状态管理,适合多组件共享、异步流程复杂的场景。

我个人建议:业务状态尽量走 Vuex,UI 联动多级组件时优先用 $attrs/$listeners,不要一上来就搞 EventBus,后期维护成本太高。

6.4 v-if 和 v-show 的区别、computed 和 watch 的分工

v-if 是真正的条件渲染,表达式为 false 时组件不渲染,用到时才创建;v-show 是 CSS display 控制,元素会一直存在。高频且频繁切换的场景用 v-show,内容重且不需要初始化的场景用 v-if。computed 有缓存,依赖不变不会重新计算;watch 用于观察数据变化然后执行副作用,适合异步操作。一句经验:能用 computed 解决的问题不要用 watch,watch 写多了,数据流会变得难以追踪。

7. 常见问题排查与实践心得

7.1 高频问题排查一览表

问题场景大概率原因处理建议
Vue 2 项目启动白屏路由 mode 是 history,且后端没配 fallback改 hash 模式,或后端转发 index.html
npm install 报 peer 依赖冲突npm 7 严格校验加 --legacy-peer-deps 安装
node-sass 编译报错Node 版本或 python 环境不一致换 Node 16 或改 dart-sass
页面刷新后 params 丢失用了 name + params 且非路径参数改用 query 或路径参数
tap 事件在移动端 300ms 延迟未引入 fastclick 或 viewport 不合适检查 meta viewport,必要时引入 fastclick
img 标签无法显示 PDFimg 本身不支持 PDF 渲染用 iframe 或 vue-pdf 展示
VSCode 点击组件标签不跳转Vue2 项目装了 Volar换 Vetur,并开启 experimental.templateInterpolationService
.vue 文件 tsconfig 报错找不到 @vue/tsconfig依赖缺失或版本不匹配重新安装对应版本,路径改相对路径
后台页面切换后图表空白echarts 实例销毁或 resize 未处理beforeDestroy 里 dispose,窗口 resize 绑定后再解绑
折叠动画不平滑height 从 0 到 auto 无法过渡用 scrollHeight 动态赋值,或 grid-template-rows
div 多行省略失效flex 子项挤压加 min-width: 0,配合 overflow: hidden
m3u8 在 Safari 播不了Safari 原生支持 HLS,hls.js 不启用判断 Hls.isSupported() 后走原生 video.src
Spring Boot 打包后静态资源 404publicPath 未适配 context-path配置 publicPath 为绝对路径前缀

7.2 几条压箱底的经验

说实话,我把这些写下来的时候,脑子里飘过的都是一个个加班排查的场景。做 Vue 2 项目,我最深切的体会是:它不是一个完美的框架,但它足够成熟,成熟到你遇到的所有问题,几乎都有人在网上记录过。关键是你能不能搜对关键词,能不能用最小代价找到答案。

有一句话我必须多说一遍:所有涉及第三方实例的东西,图表、地图、播放器、Canvas 动画,在组件销毁前必须做清理。Vue 2 的页面跳转非常频繁,destroyed 里不清理,内存就像漏水一样一点点漏干,等用户反馈页面越来越卡,你根本查不出是哪一屏的锅。

另一个经验是:老项目升级依赖,一定要小步慢跑。先锁版本,再逐个升级,每次升级都跑一遍构建和核心流程。我见过同事把 Element UI 从 2.13 升到 2.15,结果一个 table 的默认行为变了,十几个页面出问题,比迁移 Vue 3 还痛苦。稳定压倒一切,这大概就是 Vue 2 项目教会我的第一课。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/6 4:47:03

5G NTN协议栈改造与工程落地实战指南

简介&#xff1a;本资源是一份面向通信工程专业学生、5G系统研发工程师及卫星通信技术研究者的深度技术文档&#xff0c;聚焦5G非地面网络&#xff08;NTN&#xff09;的关键演进路径与核心挑战。文档系统梳理了NTN在卫星通信、低空平台&#xff08;HAPS&#xff09;及中高轨卫…

作者头像 李华
网站建设 2026/10/6 4:47:01

WPF实现3D动画看板:3D IC封装智能工厂的数据管理与可视化实战

先说说我最近在忙的一件事&#xff1a;帮一个半导体封测厂做数字化看板&#xff0c;客户提了一堆需求&#xff0c;最后拍板要一个能把3D IC封装工艺流程“演”出来的可视化系统。一开始我觉得这就是个“高级版PPT”&#xff0c;后来跟工艺工程师聊了几轮才意识到——当芯片开始…

作者头像 李华
网站建设 2026/10/6 4:46:40

MOSFET实战选型与保护:从参数误读到十年不坏的工程法则

1. 这不是教科书里的FET&#xff0c;而是我修了八年电源板、调了五年射频功放、焊过两千块PCB后&#xff0c;真正用得上的场效应晶体管实战手册“场效应晶体管”这六个字&#xff0c;第一次出现在大学模电课本里时&#xff0c;我盯着那个带箭头的三角形符号看了整整二十分钟——…

作者头像 李华
网站建设 2026/10/6 4:46:23

Spring Boot进阶实战:学习路线、接口架构与生产监控

平时逛技术社区&#xff0c;经常看到有人把Spring Boot的资料打包下载了几十个G&#xff0c;结果打开一看全是Hello World级别的demo&#xff0c;真正遇到“多商户跨境商城怎么拆服务”“第三方接口该放哪个模块”“生产环境怎么监控”这种实际问题&#xff0c;照样抓瞎。这个标…

作者头像 李华
网站建设 2026/10/6 4:45:36

Agent-Reach CLI 实战:快速搭建与部署 AI Agent 的完整指南

1. 项目缘起与核心定位Agent-Reach 这个名字第一次出现在我视野里的时候&#xff0c;我正被一堆零散的 Agent 工具链折腾得够呛。简单来说&#xff0c;它是一个基于 Python 构建的 CLI 工具&#xff0c;目标很明确&#xff1a;让开发者能通过命令行快速搭建、调试和部署 AI Age…

作者头像 李华
网站建设 2026/10/6 4:45:20

OpenShell实操指南:从开始菜单定制到批量部署与避坑

如果你还在Windows 10或Windows 11上折腾开始菜单&#xff0c;OpenShell这个名字你应该不陌生。作为Classic Shell的开源继任者&#xff0c;它把Windows 8之后微软逐步收走的那些“鼠标友好”功能重新拉回了桌面&#xff1a;一个真正能当作启动器的经典开始菜单、资源管理器里的…

作者头像 李华