ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Vue 2实战笔记:环境配置、核心原理与高频场景避坑指南

Vue 2实战笔记:环境配置、核心原理与高频场景避坑指南 1. 先聊两句这个时代学Vue 2到底图什么项目标题是vue.2我第一反应就是一套在Vue 2.x上跑起来的真实工程。2023年底Vue 2官方停止维护之后圈子里的风向几乎是一边倒地喊快升级Vue 3但真正落到公司生产环境里你会发现大量存量系统用的还是Vue 2 Element UI Vue Router 3 Vuex 3这套组合。这些项目不是想升就能升的业务逻辑复杂、第三方依赖多、团队人手紧张随便动一个底层版本可能就要连带改十几个组件库。所以我一直觉得Vue 2不是过时而是存量巨大、维护压力真实存在。这篇文章不是给什么纯新手从头讲什么是Vue的也不是劝你非得用Vue 2不可。它更像是我这几年在Vue 2项目里摸爬滚打总结出来的一套实操笔记避坑指南覆盖环境配置、路由、插槽、组件通信、常用场景实现、常见面试题、前后端联调打包这些高频问题。如果你是刚开始接触前端、或者手里正维护着一个Vue 2老项目的开发者这篇内容应该能帮你节省不少试错时间。我默认你看这篇文章时已经有了一点JavaScript基础知道npm、import、组件这些概念。遇到再基础的东西我也会顺手提一嘴但重点还是放在项目里真正会碰到的坑上。毕竟看过再多文档不如直接看别人踩过的坑长什么样。2. 环境与工程化装环境、建工程、配编辑器很多新手在vue安装及环境配置这一步就被卡住了卡住的原因往往不是操作多难而是版本之间的关系没搞明白。Vue 2的项目不等于随便装个最新Node.js就能跑CLI工具的版本、Node版本、npm源、编辑器插件都会连环影响你后面的开发体验。2.1 Node.js版本和包管理器选型Vue 2官方推荐的构建工具是Vue CLI 4.x这代CLI对Node.js的版本要求相对宽松Node 14到Node 16都跑得挺稳。如果你的本机装的是Node 18甚至Node 20直接全局安装vue/cli 4版本再创建项目大概率会遇到一些OpenSSL相关的报错比如error:0308010C:digital envelope routines::unsupported这是因为新版Node改了默认的哈希算法老的Webpack 4不兼容。遇到这类报错最快的解决办法不是降级Node而是先试试在命令行里临时设置一个环境变量Unix类系统用NODE_OPTIONS--openssl-legacy-provider npm run serveWindows PowerShell里用$env:NODE_OPTIONS--openssl-legacy-provider。但说实话这只是临时方案长期维护还是建议把Node版本固定下来用nvm或者fnm这类版本管理工具项目里放一个.nvmrc文件里面写上14.21.3之类的具体版本号谁接手项目都清楚该用哪个Node。包管理器方面Vue 2老项目里最稳的是npmYarn 1也可以用。但像pnpm这种使用符号链接策略的包管理器在老项目里经常遇到幽灵依赖问题Element UI、一些老组件的依赖关系没声明清楚pnpm的严格模式直接给你报错。我的建议是老项目老老实实用npm别为了快那几秒装包把自己坑了。2.2 用Vue CLI创建项目现在创建一个Vue 2项目我用得最多的还是vue create这条命令。全局装好vue/cli以后执行vue create my-project然后根据提示选择预设。这里有个关键点一定要手动选择功能Manually select features别直接选默认预设否则你后面还要补一堆配置。建议勾选这几项Babel必须的不然ES6语法在部分浏览器里跑不起来Router项目基本都需要Vuex涉及共享状态的就用Linter / Formatter代码规范从第一天就养成CSS Pre-processors如果公司规范用SCSS就选上选完之后有个问你是用history mode for router还是hash mode新手可以先选hash部署到任意静态服务都不会404。history模式需要后端配合做fallback后面讲Spring Boot部署时我会再详细说。如果是给老项目维护不想重新创建工程也可以在现有项目里手动装Vue 2依赖。注意Vue 2的npm包名就是vue安装时如果不指定版本现在默认会装到Vue 3.x所以老项目里一定要锁定版本npm install vue2.7.16 vue-router3.6.5 vuex3.6.22.3 VS Code里做对三件事现在很多新手在VS Code里写Vue 2最常踩的坑就是标签跳转不了这个问题我放到后面专门讲。这里先说编辑器层面的基础配置。第一件事是装对Vue插件。Vue 2项目建议用Vetur这是老牌插件对Vue 2的template语法支持得最成熟。Volar是给Vue 3准备的你要是装了Volar去写Vue 2不是完全不能用但经常会出现类型提示乱跳、template里变量标红的问题。所以我排查vscode中点vue中的标签没有跳转时第一步就是看插件是不是装混了。第二件事是配好eslint。Vue CLI创建的项目自带ESLint配置VS Code里装好ESLint插件之后注意在设置里打开eslint.validate把vue文件加进去eslint.validate: [javascript, javascriptreact, vue]保存时勾选editor.codeActionsOnSave: { source.fixAll.eslint: true }保存文件自动格式化能帮你省掉大量手动处理缩进和引号的时间。第三件事是配Prettier还是配勾选格式化需要统一。团队项目里你在.prettierrc定了semi: false、singleQuote: true别人不装Prettier或者没有读取配置改一个文件就给你全局加一遍分号代码review的时候全是格式噪音。所以我的习惯是在.vscode/settings.json里强制指定默认格式化器为Prettier并设置prettier.requireConfig: true没有配置文件的目录直接不生效从源头避免格式漂移。2.4 目录结构建议与工程规范Vue 2项目的目录结构我一般这么规划src ├── api // 接口请求统一封装的模块 ├── assets // 静态资源图片、字体、全局样式 ├── components // 通用组件 ├── directives // 自定义指令 ├── filters // 全局过滤器 ├── router // 路由配置 ├── store // Vuex store ├── utils // 工具函数 ├── views // 页面级组件 ├── App.vue └── main.js这个结构公司跟公司之间会有差异但几个原则是通用的接口请求和页面分离一个页面一个文件夹放自己的私有组件和样式全局状态不要乱塞。特别提醒一点Vue 2里main.js是入口文件所有全局注册都在这做Element UI按需引入、自定义指令注册、axios挂载到原型上都写在这里比散落在各个页面里好维护得多。工程规范里最值得花时间的是路径别名。在vue.config.js里配上const path require(path); module.exports { chainWebpack: config { config.resolve.alias .set(, path.resolve(__dirname, src)) .set(api, path.resolve(__dirname, src/api)); } };然后在jsconfig.json里也同步配置{ compilerOptions: { baseUrl: ., paths: { /*: [src/*] } }, exclude: [node_modules, dist] }这样import路径不用写一串../../../../而且在VS Code里也能正确跳转。3. 核心基础响应式原理、组件通信、路由与插槽Vue 2的核心知识说多不多说少不少面试也是这些实战也是这些。把这个部分吃透你去看大部分Vue 2项目的源码都不会太吃力。这里我不按教程顺序讲而是按照实际开发中你每天都会碰到的点来拆。3.1 响应式原理Object.defineProperty的边界Vue 2的响应式基于Object.defineProperty它在初始化时遍历data里的所有属性把它们转换成getter/setter。这个机制的优点是兼容性极好缺点是它只能拦截对象属性的访问和修改无法拦截新增属性和删除属性。这就是为什么Vue 2明明要求你在data里先声明好所有字段但还是有大量新手在mounted里写this.obj.newField 1结果页面死活不更新。解决的方案无非这几种在data里提前声明所有字段哪怕初始值是null使用this.$set(obj, newField, 1)Vue 2内部会用defineProperty重新为这个新属性加上响应式数组场景用splice或this.$set(arr, index, newValue)直接改arr[index]不会触发视图更新我实际开发中遇到的另一个高频坑是props里传下来的对象被局部组件直接修改。defineProperty只管深度劫持不限制你改Buffer没有强制报错但等你发现父组件状态被莫名其妙带走了排查起来很费劲。所以我给自己定了一条规矩props永远只读要改就emit事件让父组件改。还有一点需要知道的是Vue 2.7及以上版本为了兼容Vue 3写法引入了composition-api的处理器但响应式核心仍然是defineProperty跟Vue 3的Proxy有本质区别。这个区别也是面试最爱问的为什么Vue 3要换ProxyProxy可以监听整个对象的增删改还能拦截数组下标操作响应式能力更强性能更具优势但兼容性上不了IE。3.2 组件通信方式总结Vue 2里组件通信的方式挺多我列了个表方便对照场景方式注意事项父子组件props 向下传递$emit 向上通知props不要直接改emit事件名用kebab-case兄弟组件通过父组件中转或事件总线EventBus事件总线记得在beforeDestroy里off避免内存泄漏深层嵌套provide/inject适合跨层级注入但破坏单向数据流别乱用任意组件Vuex复杂状态共享的首选直接访问$refs、$parent、$children$children顺序依赖渲染顺序尽量少用事件总线new Vue()的做法在中国老项目里特别常见但用不好就是灾难。我见过一个项目把上百个事件挂在全局bus上页面关了还在监听最终造成内存泄漏和难以复现的Bug。现在我的态度是如果项目正在维护且代码能改Communication类型的事件统一用Vuex或者一个简单的reactive store替代实在要用事件总线也必须约定事件名前缀比如page1:update然后在组件销毁时this.$bus.$off()。3.3 路由动态路由和路由参数Vue 2项目几乎标配vue-router3.x。基础的路由配置网上到处都是我说几个实际项目中最容易出问题的地方。动态路由很多管理系统菜单是从后端返回的前端要根据菜单数据动态添加路由。vue-router 3.x提供了router.addRoute方法注意这个方法在3.x里是异步的动态添加完之后需要重新调用router.replace或者next({ ...to, replace: true })去重新进入一次导航否则路由表是更新了但你当前页面还停留在旧的404。我实际做权限路由时常用的方案是router.beforeEach里先判token再判用户已经加载过的路由列表没有就调用一个getUserMenu()接口拿到菜单后调用addRoute注册然后重新next({ ...to, replace: true })。这里有个小坑如果404路由写在静态路由表的最底部动态路由添加后刷新页面直接访问动态页面时Vue Router会用静态404兜底页面显示NotFound。解决方案是把404路由的动态部分变成最后一个addRoute注册的路由或者把path: /:pathMatch(.*)*的规则从静态表中去掉在动态路由全部注册完后再动态添加。路由参数这是新手经常混淆的点。$route.params是从路径上取的比如/user/123路由配置里路径是/user/:id$route.query是从问号后面取的比如/list?page1。在组件里监听参数变化时不要只依靠created钩子因为从一个/user/1切换到/user/2组件会复用created不会再执行。应该用watch监听$route对象watch: { $route(to, from) { this.fetchDetail(to.params.id); } }路由懒加载在Vue 2的router配置里用() import(/views/xxx.vue)代替直接import组件这样每个路由页面会被打包成单独的chunk首屏速度会快很多。这个操作几乎零成本回报却非常大。3.4 插槽slot的三种用法vue里的插槽在复杂组件设计时几乎是离不开的。Vue 2的插槽分三种默认插槽组件标签内传入的内容会渲染到子组件中的slot/slot位置。适合做弹窗内容、卡片自定义区域。具名插槽在子组件里声明多个slot用name区分外部使用时template v-slot:header。这个在写布局组件时非常能提升扩展性。作用域插槽子组件把内部数据暴露给父组件使用父组件在插槽里可以通过slotProps拿到。典型场景是表格组件的自定义列template el-table-column template v-slot:default{ row } span{{ row.status 1 ? 启用 : 禁用 }}/span /template /el-table-column /templateVue 2.6之后slot-scope废弃统一用v-slot语法。老项目里你可能会看到大量slot-scopeprops的写法能跑但建议新代码统一用新语法。3.5 计算属性computed与watch的选择这个问题是面试题也是实际开发的选择题。computed是根据依赖自动缓存的计算结果只有依赖变化才会重新计算watch是监听某个值变化后执行回调。我自己的选择标准很简单模板里要做数据运算、筛选、拼接优先用computed同步/异步操作、调用接口、执行this.$store.dispatch用watch依赖多个状态才能推断出新值用computed更清晰一个大量新人犯的错是把需要调用接口的逻辑写在computed里。computed必须是纯函数里面不能有副作用。你要是非要在computed里发请求会因为缓存机制导致请求只发一次之后数据变了也不重新请求页面表现让人摸不着头脑。按正确做法应该放在watch里配上{ immediate: true }可以在组件创建时先执行一次。4. 热搜里的实战场景从ECharts柱状图到m3u8播放再到PDF展示这一节我围绕几个搜索热词展开都是我在真实业务里接过的需求。每个场景我都会给出思路和核心代码希望能帮你快速落地。4.1 Vue 2 ECharts画两个柱状统计图vue中用echarts画两个柱状统计图实际上是两类需求一类是同一张图里两组柱状数据做对比另一类是页面上放两个独立的图表。后者简单写两个组件就行前者稍微有点设计空间。以同一图表双柱对比为例我常用的配置是this.chart echarts.init(this.$refs.chart); const option { tooltip: { trigger: axis }, legend: { data: [本年度, 上年度] }, xAxis: { type: category, data: [1月, 2月, 3月, 4月] }, yAxis: { type: value }, series: [ { name: 本年度, type: bar, barWidth: 16, data: [80, 120, 90, 150] }, { name: 上年度, type: bar, barWidth: 16, data: [60, 110, 100, 130] } ] }; this.chart.setOption(option);如果两组数据的数量级差距很大,比如一个是销售额万级,一个是订单量十级,直接放同一个y轴会导致小的柱几乎看不见。这时就要考虑双y轴,在yAxis数组里配置两个轴,再在series里各自指定yAxisIndex。Vue 2里用ECharts还有几个必注意的坑:图表必须在DOM渲染完成后初始化,所以this.$refs.chart要在this.$nextTick之后取,或者直接写在mounted里页面resize时要window.addEventListener(resize, this.resizeHandler),beforeDestroy里记得移除监听组件销毁时this.chart.dispose(),否则图表实例会占着内存如果图表容器初始化时是隐藏的,比如在tab页里,可能会渲染出0宽高,需要等tab切换后再调用resize()我在自己的项目里干脆封装了一个BaseChart.vue组件,把echarts初始化、resize、dispose全部封装好,页面里只需要传option和等着切换数据即可,大幅减少重复代码。4.2 Vue 2播放m3u8视频m3u8是HLS流媒体协议里的索引文件,里面存的是一串.ts分片地址。浏览器原生不支持m3u8直放,所以需要借助hls.js。安装:npm install hls.js在Vue 2组件里,典型的播放逻辑是:import Hls from hls.js; export default { data() { return { src: https://xxx.com/live/stream.m3u8 }; }, mounted() { this.initPlayer(); }, methods: { initPlayer() { const video this.$refs.video; if (Hls.isSupported()) { this.hls new Hls(); this.hls.loadSource(this.src); this.hls.attachMedia(video); } else if (video.canPlayType(application/vnd.apple.mpegurl)) { // iOS Safari原生支持直接给video赋src即可 video.src this.src; } else { this.$message.error(当前浏览器不支持m3u8播放); } } }, beforeDestroy() { if (this.hls) this.hls.destroy(); } };特别提醒一下:在Nginx或者Spring Boot后端部署m3u8时,响应头Content-Type必须是application/vnd.apple.mpegurl,否则有些PC浏览器会把它当普通文本下载,而不是交给hls.js处理。另外CORS也要注意,hls.js是异步去拉.ts分片的,如果视频服务器跟页面域名不一致,接口必须返回Access-Control-Allow-Origin。如果业务不复杂,也可以直接用video.js配合videojs-contrib-hls插件,但那个插件已经不再维护,新项目我不推荐,还是hls.js更活跃。4.3 Vue 2里image标签能显示PDF吗这个热搜我觉得问的人应该是在img标签里塞pdf地址,发现只显示一个空框或者直接下载。答案很直接:img标签不支持PDF渲染,它是为位图设计的,PDF是矢量文档格式,浏览器不会自动把PDF画在img里。想在一个页面里展示PDF,常用的方案有几种:方案一:iframe/embed直接嵌套iframe :srcpdfUrl width100% height600/iframe优点是真简单,浏览器原生支持,缺点是你控制不了工具栏样式,而且如果后端接口要求带token请求头,iframe就无能为力了,因为它发不了自定义header。方案二:vue-pdf组件Vue 2下常用的库是vue-pdf,基于pdf.js封装,Promise方便:npm install vue-pdf4.3.0组件里:template pdf :srcpdfUrl num-pagestotalPages $event/pdf /template script import pdf from vue-pdf; export default { components: { pdf }, data() { return { pdfUrl: , totalPages: 1 }; }, created() { this.pdfUrl pdf.createLoadingTask(https://xxx.com/file.pdf); } }; /scriptvue-pdf可以自定义翻页、缩放,适合做在线预览功能。但注意pdf.js对PDF版本有要求,离谱的加密PDF和支持嵌字体不全的容易白屏,这种时候兜底方案就是用iframe打开新页面预览。方案三:纯前端把PDF转图片— 这种方式适合只预览封面页,需要引入pdfjs-dist手动渲染canvas,复杂度高一点,但可控性好。需要的时候再上。4.4 Vue 2多文件上传多文件上传也算高频需求。最简单的方式就是原生input加multiple,再配合FormData一次性上传:input typefile multiple changehandleFilesChange /handleFilesChange(e) { const files Array.from(e.target.files); const fd new FormData(); files.forEach(file fd.append(files, file)); axios.post(/api/upload, fd, { headers: { Content-Type: multipart/form-data } }) }但业务稍微大一点,就要考虑进度条、单个文件大小校验、类型校验、失败重试。我的经验是能直接用Element UI的el-upload组件就别手搓,它自带多文件列表、进度事件、自定义请求方法,成熟稳定:el-upload action/api/upload multiple :limit5 :on-successhandleUploadSuccess :on-errorhandleUploadError :before-uploadbeforeUpload el-button选择文件/el-button /el-uploadbefore-upload里可以做格式和大小校验,返Promise.reject()可以中断上传。如果要带token,在el-upload的:headers属性传一个对象即可。如果做分片上传,思路是先读文件hash,再分段提交,最后后端合并,这个复杂些,建议等有真实大文件需求时再上,别为了炫技把项目搞得复杂化。4.5 内容折叠展开与div超出隐藏这两个是CSSJS细节,但搜索热度高,说明很多人被小问题拦住了。内容折叠展开:最基础的做法是v-if或v-show切换区块显示。但如果要那种平滑展开收起的效果,v-show是不带动画的,这时候有两条路线:路线一:用transition配合max-height技巧,给折叠容器设置CSS过渡,从max-height: 0过渡到max-height: 500px。这个方案要精确计算高度,内容一变就得改值,不太灵活。路线二:直接用keyframes自己写height动画,同样有计算问题。我个人经验是,内容折叠展开如果用Element UI,直接上el-collapse组件,内部高度动画都处理好了。自己写的话,推荐优先用grid-template-rows: 0fr - 1fr这个CSS新方案,过渡平滑而且不需要写死高度:.fold-container { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.3s ease; } .fold-container.open { grid-template-rows: 1fr; } .fold-container .fold-inner { overflow: hidden; }不过老项目对浏览器兼容性要求高的话,这个方案在IE就是废纸,还是老老实实用max-height或者v-if transition。div超出隐藏:单行文本省略是老三样:.ellipsis { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }多行文本用-webkit-line-clamp:.multi-ellipsis { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; }这个方案在Chrome、Safari、Firefox都能跑,但本质上依赖WebKit的私有属性,如果团队要求兼容某些特定环境,可以退而求其次用js截断字符串配合tooltip实现。5. 面试、交接与部署从源码交付到Spring Boot集成这个部分覆盖vue面试题vue项目源码怎么发给别人vue打包放进springboot中基于springboot vue的项目这些热搜关键词。我按你从别人手里接项目到把项目交付给别人的顺序来说。5.1 Vue 2高频面试题与底层考点面试题本质上考察的是你有没有真正理解框架的运行机制。这里我挑几个最常被问到的点展开讲。Vue 2响应式原理刚才已经详细说过,面试时先讲Object.defineProperty劫持data属性,再讲依赖收集与派发更新,最后提一下数组和新增属性的局限以及$set的作用。全程不要只背概念,最好能说一段简单的实现思路,比如初始化时遍历data,递归给每个对象属性定义getter和setter,getter里通过Dep收集Watcher,setter里通知Watcher更新。生命周期顺序:beforeCreate - created - beforeMount - mounted - beforeUpdate - updated - beforeDestroy - destroyed,每个阶段能做什么要心里有数。常考组合:created里可以访问数据但DOM还没渲染,mounted后才能操作DOM;keep-alive组件会有activated和deactivated,这两个钩子与普通生命周期是并列的。Vue.nextTick原理:Vue 2的DOM更新是异步的,你修改数据后不会立刻同步改DOM,而是把更新操作推入一个异步队列,等当前同步代码执行完再批量更新。nextTick就是在DOM更新之后执行回调的手段。面试时可以提到事件循环中的microtask/macrotask,说Vue 2内部优先用Promise.then,再依次用MutationObserver、setImmediate、setTimeout降级。v-for为什么要key:key让Vue可以识别每个节点的身份,diff算法在比较新旧节点时会优先复用同key的节点,减少DOM操作。key不要用index,尤其是在列表有增删排序时,index作为key会导致状态错乱,比如列表第一项被删除,剩下的项key整体前移,复用了错误的组件实例。computed vs watch、组件通信、slot这些我在前面都展开过,直接拿那些内容应战没大问题。5.2 项目源码怎么发给别人这个热搜可能是从把写好的项目发给同学/同事的需求来的。先说结论:绝不要把整个项目文件夹打成zip发过去,尤其是包含node_modules的,动辄几百MB,而且对方机器上依赖版本不一样大概率跑不起来。标准流程是:项目用git管理,确保.gitignore里写掉了node_modules、dist、*.local全部代码提交到git仓库,或者用压缩工具将排除node_modules和dist后的src、public、package.json、vue.config.js、.nvmrc、README.md打成一个包发给对方后,对方执行npm install安装依赖必要时把根目录的package-lock.json或yarn.lock一起发过去,这样能锁定依赖版本,避免因为版本漂移报错写一个README,写清楚Node版本、npm源、启动命令、环境变量示例如果项目里有本地环境变量文件,比如.env.development.local、.env.production,这些文件按道理不该提交到git,因为里面可能有机密地址或密钥,发源码的时候记得检查一遍。对于需要对方快速预览的,可以顺便发一个部署好的线上预览地址,或者给对方一份npm run build后的dist包,让对方用本地静态服务器打开。5.3 Vue项目打包放进Spring Bootvue打包放进springboot中是前后端联调部署里的经典操作。做法并不复杂:前端执行npm run build,生成dist目录把dist目录下的所有文件,复制到Spring Boot项目的src/main/resources/static/下重新打包Spring Boot的jar,启动后访问http://localhost:8080/就能看到前端页面但要注意几个实际问题:路由History模式404问题:如果你的Vue Router用的是history模式,直接访问http://localhost:8080/dashboard会返回404,因为后端没有这个路由的映射。解决办法是在Spring Boot里配置一个controller转发前端路由到index.html:Controller public class ViewController { RequestMapping(value /{path:[^\\.]*}) public String forward() { return forward:/index.html; } }这个配置把所有不带文件后缀的路径都转发到index.html,前端路由自己接管后续匹配。注意静态资源如.js、.css、.png仍会正常访问,因为规则排除了带点号的。接口代理:在Spring Boot中,前端打包进静态目录后,推荐让前端请求使用相对路径/api/xxx,Spring Boot的controller挂在/api命名空间下,这样部署在一个服务里最省事。本地开发时前端跨域,可以用vue.config.js配置devServer代理:module.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/api: } } } } };生产环境如果要前端静态包和后端服务分开部署,就需要在Nginx层做反向代理,把/api转发到后端服务,把其他路径指向前端静态文件。这种模式更灵活,也方便做负载均衡。5.4 tsconfig报错和VS Code标签跳转问题热搜里有failed to load tsconfig vue/tsconfig/tsconfig.web.json: tsconfig not found。这个报错一般出现在一个本来按Vue 3 TypeScript模板生成的项目,或者你创建项目时选择了TypeScript但依赖没装全。Vue 2.x TypeScript本来就比较麻烦,还需要确认几个关键点:vue/tsconfig这个包是否存在于node_modules,没有就执行npm install -D vue/tsconfigtsconfig里的extends: vue/tsconfig/tsconfig.web.json,如果你的项目用的是老版本Vue CLI,这个extends路径不一定适用,更稳的做法是直接在tsconfig里写完整配置,不依赖外部包装完依赖后重启TS Server:VS Code里CtrlShiftP,输入TypeScript: Restart TS Server至于vscode中点vue中的标签没有跳转,大多数时候原因是:装了Vue 3的Volar在写Vue 2时,解析器对标签定义不友好,建议改用Vetur,并在设置里确认vetur.validation.template: true组件没在components里注册,或者全局注册的组件路径别名没被编辑器解析确认js/ts.implicitProjectConfig.experimentalDecorators等模块解析设置,或者检查jsconfig.json/vue.config.js里的alias是否和实际路径对得上排查顺序就是先插件、再注册、后路径。5.5 Nuxt 2和Vue 2的区别nuxt和vue的区别这个问题,本质上是搞混了库和框架。Vue本身是一个用于构建用户界面的库,它解决的是视图层问题;Nuxt是在Vue之上构建的一个上层框架,把Vue Router、Vuex、SSR/静态站点生成、约定式路由、中间件、SEO优化等整合在一起。Nuxt 2对应的Vue内核是Vue 2。从Vue 2项目迁移到Nuxt 2,主要变化是:路由不再是手动配置一个router/index.js,而是按照pages目录结构自动生成;页面级数据获取要使用asyncData或nuxtServerInit;全局状态管理不再是普通Vuex,而是要求用store目录下的模块化方式。如果你的项目是做内容型网站、有SEO需求、或者需要服务端渲染首屏,那选Nuxt 2更合理;如果项目是后台管理系统、中后台工具、内部运营平台,纯Vue 2 Element UI就够,没必要上Nuxt,SSR带来的部署复杂度会明显上升。顺带说一句,Vue 2停维护后,Nuxt 2也在2024年走到了生命周期尽头。新项目要么考虑Vue 3 Nuxt 3,要么继续维护老系统不动。6. 常用问题速查:我踩过的高频坑和排查顺序这里整理一张我实际工作里遇到的高频问题速查表,都是Vue 2项目里的经典永流传型问题。现象可能原因排查与解决修改对象属性页面不更新新增属性没有响应式用$set或者提前在data里声明修改数组索引页面不更新defineProperty不劫持数组索引用splice或$set改写数组路由切换后页面空白组件没有正确import,或者命名重复检查路由懒加载路径、组件name是否重复history模式刷新404后端未做fallback配置Spring Boot转发或Nginx try_files打包后图片404publicPath配置错误vue.config.js里publicPath: ./或绝对路径部署后接口跨域前后端域名不一致开发环境配proxy,生产环境配cors或反向代理启动时报openssl错误Node版本过高升级webpack或设置NODE_OPTIONS兼容打包体积过大第三方库全量引入路由懒加载、按需加载UI组件库、CDN外链表格或列表渲染卡顿数据量过大且diff开销高分页,或对复杂行组件做track-by恒定key首屏白屏时间太长大图、大JS chunk压缩图片、拆chunk、上loading骨架屏排查顺序我一直遵循从外部到内部:先看浏览器Network请求有没有报错,再看Console有没有JS异常,最后才怀疑代码逻辑。很多新手一上来就在组件里debug半天,结果发现是后端把接口地址改了,这是很低级的浪费。还有一个我反复强调的习惯:改代码之前先复现,复现不了不要改。特别是在维护老项目时,很多人看了报错日志就猜原因然后动手改,最后不但没修复,还引入了新的问题。带好复现步骤、抓取报错现场、把核心状态打印出来再改,才是高效路径。最后分享一点个人体会这两年带过几个新人,也接盘过好几个老项目,最大的感触是:技术在迭代,但解决问题的基本思维永远是先理解原理,再动手试。Vue 2的源码和生态文档虽然不会再有大更新,可它沉淀出来的那套组件化思想、响应式设计、路由与状态管理模式,放到今天任何一个前端框架里都是共通的。所以我从不觉得学Vue 2是浪费时间,反而认为它是理解前端框架演进的一块很好的跳板。如果你现在正在做一个Vue 2项目,我的建议只有三条:把依赖版本锁死,能升级就尽早升级;把工程规范立起来,别让项目烂在样式和命名里;多写注释,尤其把这里为什么要这样写记下来,因为三个月后的你会完全忘记当时的决策原因。做技术就是这样,踩坑不可怕,可怕的是踩了坑不说出来。希望这篇持续维护着的笔记能帮到你,哪怕只是让你少走一次弯路,也算有价值了。
返回列表