
1. 为什么第27天的重点是组件化先把这个阶段的感觉说清楚。如果你正跟一套系统化的前端学习计划走前面大半个月基本都在跟HTML、CSS、JavaScript、Vue基础语法打交道能写出页面、能跑通指令、能搞定列表渲染和条件渲染。但到了“第二阶段Vue组件化开发”的第27天学习的重心会突然从“写代码”变成“设计代码”——组件化这个事本质上就是一门设计活。它不再问你某个语法怎么写而是问你一个页面应该被拆成哪些块、块与块之间怎么通信、谁的数据归谁管、哪个部分可以独立复用。能不能跨过这个坎直接决定你后面做项目是“堆页面”还是“搭系统”。我见过不少初学Vue的朋友循环、计算属性、侦听器玩得挺顺一进入组件化阶段就开始懵。倒不是说组件API多难而是思维方式转不过来过去写一个页面从上到下一气呵成样式、逻辑、数据全部混在一起现在突然要求你把页面“切开”切完之后还得保证它们之间能配合工作。这就像你以前是一个人做饭、一个人上菜、一个人收拾现在要变成一个后厨团队——切菜的、掌勺的、摆盘的各司其职但做出来的菜还得是同一桌席。组件化开发的难点从来不在“怎么写组件”而在“怎么切组件”。这篇博文我结合自己带团队和做项目积累的经验把这第27天真正该吃透的东西整成一份实操笔记。里面有组件划分的原则、组件通信的套路、生命周期和调试工具的用法还有大量热搜里高频出现的实战问题比如m3u8视频流播放、el-upload文件数量获取、地图组件二次打开空白、圆环进度条实现、流式输出和点击节流、iOS打包后打开白屏等。适合正在学Vue组件化的人、准备面试的前端以及做项目时被组件拆分折磨过的开发者。我尽量写得像当面聊天一样直接你跟着思路走踩过的坑基本都能避开。2. 组件化到底在解决什么问题2.1 拆组件和拆页面是两回事很多初学者对组件化最大的误解就是把“拆组件”理解成“拆页面片段”。比如看到一个后台管理页面左边是侧边栏右边是头部下面是内容区于是拆成三个组件完事。这种拆法不能说错但基本没吃到组件化的红利——你只是把一个大文件切成三个小文件数据的归属、逻辑的复用、状态的隔离这些问题一个都没解决。真正的组件化开发核心解决三件事复用、隔离、协作。复用指的是相同或相似的功能块只需要写一次比如商品卡片、分页器、弹窗确认框哪都能用隔离指的是组件内部的状态、样式、逻辑不会无意中污染外部你改A组件的内部实现B组件完全不受影响协作指的是组件之间通过明确的接口props、事件、插槽进行数据交换像一个团队里不同角色通过文档和约定来配合而不是谁都能直接改对方的代码。我自己的判断标准很简单如果一个功能块在同一个项目里出现两次以上或者它本身复杂到超过一屏再或者它承载了独立的业务含义比如“订单状态标签”“用户头像上传”那就应该拆成组件。如果只是某个页面里的一段布局没有复用价值也没有独立逻辑那就别拆拆了反而是增加父子组件通信的成本。2.2 组件划分的两条核心原则关于组件怎么切网上有各种方法论什么原子设计、容器组件和展示组件拆分、按业务域划分等等。但落到第27天这个阶段你只需要先抓住两条最实用的原则。第一条是单一职责。一个组件只做一件事。比如一个“用户信息卡片”组件它的职责就是展示用户头像、昵称、简介所有跟用户信息展示无关的逻辑都不该塞进来。如果某天你要在这个卡片里加一个“关注/取关”按钮按钮的逻辑应该通过事件抛给父组件去处理或者单独抽一个更小的按钮组件而不是直接在卡片内部写死接口调用。这样做的好处是当业务发生变化时你只需要改对应职责的那个组件不会牵一发而动全身。第二条是接口稳定。组件的对外接口props、emit的事件、插槽一旦确定下来就要尽量保持稳定。这就像手机充电口你定义了Type-C就不能三天两头改成别的口否则所有外围设备都要跟着换。实际开发中我见过太多人因为“顺手”就在子组件上乱加props或者用$parent、Vuex直接篡改子组件的内部状态短期看是省事了等组件一多依赖关系就变成一团乱麻。这里还要说一个常见误区很多人会把“组件拆得越小”当成“拆得好”。不是的。组件拆得过碎会导致props层层传递、事件满天飞调用方写一个页面要同时维护十几个组件的接口反而得不偿失。我的经验是组件最小颗粒度到“语义完整的业务单元”即可比如“日期选择器范围”“文件上传列表”这种而不是把每个都包装成组件。3. 基础设施环境、调试与依赖的坑3.1 从零搭建项目时最容易被忽略的细节第27天既然要深入组件化你肯定得有一个能跑起来的项目。如果前面已经用官方脚手架创建好了这段可以快速过如果你是换了新电脑、内网环境、或者第一次从零搭建那有几个细节非常容易踩坑。先说工具链选择。现在创建Vue项目官方推荐的是npm create vuelatest它会引导你选择是否使用TypeScript、Vue Router、Pinia、ESLint等。我的建议是如果你还在学习阶段先不要上TypeScriptJS能让你把注意力集中在组件思想上但Router和Pinia建议勾上因为组件化开发和路由、状态管理是天然强绑定的早接触早适应。包管理器方面我目前主要用pnpm因为它的依赖存储方式能省很多磁盘空间安装速度也明显比npm快。如果你所在的公司还在用npm也没必要强行切换团队统一就好。再说内网电脑的问题。有些公司开发环境是离线的或者npm官方源访问很慢。这时候最省事的办法是在联外网的机器上用pnpm把依赖全部下载成一个缓存目录然后拷贝到内网机器上设置pnpm config set offline true来离线安装。如果你只是单纯希望安装依赖快一点那就配置镜像源比如npm config set registry https://registry.npmmirror.com。这个问题热搜里也有人问“内网电脑搭建配置vue环境”典型的困难有三个node安装包不好找、依赖源连不上、devtools插件装不了。前两个靠离线安装和镜像源解决devtools的问题放在后面单独说。还有一个大家经常问的“vue项目能用IDEA开发吗”答案是能。IDEA装了Vue.js插件之后对vue文件的支持不输VS Code尤其是你在做Spring Boot Vue前后端分离项目时IDEA一个窗口同时管后端Java和前端Vue是很方便的。但如果你只用前端我还是更推荐VS Code配好Vue Language Features (Volar)和TypeScript Vue Plugin之后模板里的类型提示比IDEA要舒服。重点提醒新老项目混用的时候Volar和旧版Vetur不能同时启用很多奇怪的语法提示问题都是这俩插件打架造成的。3.2 devtools装好之后很多问题根本不叫问题搜“vue devtools插件下载”的人特别多原因也好理解组件化开发之后数据流不像以前那样写在一个文件里一眼能看完你很难凭肉眼判断某个组件当前接收到的props是什么、触发的事件有没有传出去。这时候浏览器开发者工具里的Vue面板就是救命稻草。不同浏览器的安装方式不太一样。Chrome和Edge直接在应用商店搜“Vue.js devtools”安装即可。如果你用的是内网环境或者商店访问受限可以去官方GitHub的release页面下载crx文件再通过浏览器的扩展程序管理页面手动加载。装好后打开一个Vue项目页面你会发现控制台多出一个Vue的Tab里面能看到完整的组件树、每个组件的data、computed、props以及事件时间线。调试组件通信问题的时候直接在组件树上点选组件看它的props是否正确传入再触发一次事件看父组件有没有响应基本一轮就能定位问题。还有一个高频热搜词叫“vue项目启动后network不可用”。这通常是你在npm run dev启动项目后终端里显示了一个Network: unavailable的提示然后局域网里其他设备访问不了你的页面。原因很直白Vite默认绑定的host是localhost只能本机访问。想暴露到局域网要么在启动命令里加上--host要么在vite.config.js里配置server.host: true。配置之后终端会显示一个局域网IP地址其他设备在同一网络下就可以访问了。如果你是做移动端调试用这个IP加端口在手机上打开比用localhost方便太多。3.3 自动导入Element Plus时ElMessage报未定义的坑用Element Plus是组件化开发里很常见的选择因为它的表单、表格、弹窗组件能省掉大量基础工作。但很多人在配置了按需自动导入之后发现ElMessage居然报“未定义”。这个问题的根源值得说透。Element Plus的组件分为两类一类是普通的UI组件比如按钮、输入框它们以组件的形态在模板里使用自动导入插件可以顺利识别并注入另一类是函数式组件比如ElMessage、ElNotification、ElMessageBox它们是以API调用的方式触发的不在模板里出现所以只按需导入组件不能覆盖它们。解决方法是配置unplugin-auto-import的时候把ElementPlusResolver同时配到auto-import插件里并且在项目的vite.config.js里加上对应的AutoImport配置让这些API也能被自动导入。如果你用的是完整导入也就是app.use(ElementPlus)那不存在这个问题但包体积会大一些。顺带说一句配置自动导入时还有一个容易踩的点样式文件。按需导入组件时每个组件的样式通常会随组件自动加载但如果你发现样式时有时无检查一下是不是没有引入element-plus/dist/index.css或者没有配置unplugin-element-plus的样式导入。这类问题在项目初始阶段非常消磨耐心但排查一次记住原理之后以后基本不会再犯。4. 组件通信与生命周期第27天最该吃透的核心4.1 props、emit、插槽与v-model到底怎么选组件化开发绕不开组件通信而通信手段最常见的就是props、emit、插槽、v-model这几个。很多人在第27天会混淆它们的适用场景其实可以按一句话来记props用来往里传数据emit用来往外抛事件插槽用来放“不属于子组件决定”的内容v-model是props和emit的组合语法糖。先说props。props是从父组件流向子组件的数据通道它的关键点是“单向数据流”。子组件不应该直接修改props的值否则父组件的数据会在不经意间被改掉排查问题的时候根本不知道是谁动了数据。如果你确实需要基于props的初始值创建一个内部状态可以在子组件里用data或者computed派生一个副本而不是直接改props。再说emit。子组件想通知父组件“发生某件事”就通过emits声明事件并触发它。比如一个弹窗组件关闭按钮按下时组件内部只负责触发close事件至于关闭之后父组件要做什么是父组件自己的事。这样弹窗组件就做到了“只呈现、不决策”。插槽则是把“内容”作为接口。父组件可以往子组件内部插入任意内容子组件只负责定义“哪里放内容”。这种模式很适合布局型组件比如卡片、弹窗、页面容器。插槽还支持具名插槽和作用域插槽后者可以让子组件把内部数据暴露给插槽内容使用典型场景是表格组件让调用方自定义某一列怎么渲染。最后说v-model。Vue 3里v-model的本质是把modelValue作为props传入同时监听update:modelValue事件。所以一个输入框组件可以这样封装内部input的:value绑定props的modelValueinput时emit(update:modelValue, newValue)。这样调用方直接MyInput v-modelname /用起来跟原生输入框一模一样。一个组件里还可以写多个v-model比如v-model:title和v-model:content各自对应不同的props和事件适合复杂表单组件。4.2 生命周期别靠背要在正确的时间做正确的事生命周期是Vue面试的必考点也是实际开发中特别容易出事的地方。很多人背得滚瓜烂熟create、mount、update、unmount的顺序倒背如流但一问“为什么请求要发在onMounted而不是created”就卡壳了。原因其实很简单created的时候组件实例已经创建数据已经初始化但DOM还没有生成。如果你的请求只是为了拿数据然后更新响应式状态那在created里发请求和onMounted里发请求差别不大因为数据更新会触发视图重新渲染。但如果你的请求结果需要直接操作DOM比如初始化一个图表、给某个元素绑定第三方库事件那就必须等onMounted因为只有这时this.$el或者模板里的元素才真实存在。我见过有人一进来就在created里执行document.getElementById结果拿到的永远是null换了onMounted就好了。另一个容易忽略的生命周期场景是组件缓存。如果你用了keep-alive包裹组件组件被切换走之后不会销毁而是进入deactivated状态切回来时不会重新走mounted而是触发activated。所以如果你在mounted里做了一次数据初始化或第三方库加载组件被keep-alive缓存后第二次进入时mounted不会再次执行。这个机制在对性能有要求的长列表页面里很常见但也带来一个坑如果你在mounted里监听了全局事件组件被缓存后监听器还在必须在deactivated或onUnmounted里手动移除否则容易出现事件重复触发的诡异问题。热搜里有一条“vue 加载百度地图 首次打开正常,第二次一片空白”十有八九就是keep-alive和生命周期共同造成的。首次进入组件mounted执行了地图初始化成功切换到别的页面再切回来组件走了activated而不是mounted地图没有重新初始化但容器可能被重新渲染了一遍导致地图实例和DOM容器对不上CANVAS一片空白。解决思路有两个方向要么在activated里对地图实例做检查发现容器不存在或者地图没挂载成功就重新初始化要么干脆不用keep-alive缓存地图页面每次进入都重新创建地图实例。如果你在做地图类项目建议先确定是否需要缓存别盲目套keep-alive。4.3 路由参数、路由切换与页面级组件设计组件化开发进行到第27天路由基本是绕不开的。Vue Router里的路由参数常见有三种传法query、params、state。它们各有适用场景。query是URL上的查询参数形如/detail?id1刷新页面后参数还在适合分享链接、后端直接读取的场景。params在Vue Router 4里必须配合路由配置中的动态路径使用比如/detail/:id它是URL路径的一部分刷新也还在。state则是通过history.state传递非URL可见的临时状态刷新就丢了适合“上一个页面只传本次的数据不希望用户看到参数”的场景。实际开发中我喜欢把“页面路由”和“页面内部组件”分开想路由的职责是从URL解析出当前是哪个页面以及携带了什么参数页面拿到参数后再把数据分发给它内部的子组件。这样可以避免子组件直接依赖route对象组件复用性会好很多。比如一个“商品详情页”里既有商品信息卡片又有评价列表组件评价列表组件不应该自己去读route.params.id而应该是详情页在onMounted里读好id之后通过props传给评价列表组件。这样做的好处是评价列表组件以后可以放在任何页面复用只要父组件传一个商品id给它就行。路由切换动画也是一个典型的组件化问题。热搜里有“vue中标签页丝滑切换动画”实现方案通常是router-view外面包一层transition通过CSS transition控制进入和离开的动画。原理不复杂但有几个细节要提醒如果用了keep-alive缓存页面transition的name可能要根据路由变化动态切换否则进入动画和离开动画会串另外modeout-in通常比默认的同步切换更丝滑它会先执行离开动画再执行进入动画避免两个页面同时存在造成的闪烁。5. 从热搜问题看高频实战场景怎么落地5.1 m3u8流媒体播放一个低调但高频的需求“vue播放m3u8”、“vue播放欢乐谷m.3u8”这类热搜词说明很多人在做视频相关页面。m3u8不是视频文件而是一个播放列表索引文件里面记录了一串视频分片的地址播放器按顺序拉取分片来播放。这种格式在直播和点播里很常见因为它支持码率自适应网络波动时可以自动切换清晰度。在Vue里播放m3u8最省事的方案是hls.js。它专门处理HTTP Live Streaming协议把m3u8转成浏览器原生video标签能识别的分片流。使用方式不复杂在onMounted里创建Hls实例调用loadSource(url)和attachMedia(videoElement)监听Hls.Events.MANIFEST_PARSED之后调用video.play()。这个逻辑几乎每个页面都是重复的所以第27天完全可以把它封装成一个VideoPlayer组件props接收srcm3u8地址内部负责创建Hls实例、处理浏览器原生支持hls的情况比如Safari、在组件卸载时销毁实例对外只暴露播放、暂停、跳转进度的方法。这恰好是组件化思想的绝佳练习把“播放器”这个业务单元完整封装任何页面只需要传一个地址就能用。封装视频播放组件时有三个坑要记住。第一组件卸载前一定要调用hls.destroy()否则视频分片请求会一直发浏览器卡顿不说还会浪费带宽。第二兼容性判断要前置苹果系浏览器原生支持hls不需要走hls.js你需要在代码里判断Hls.isSupported()和video.canPlayType(application/vnd.apple.mpegurl)。第三m3u8地址经常需要带鉴权token而token有时效性视频播放一段时间后token过期就会黑屏处理方式通常是在播放器内部监听错误事件发现网络错误时通过回调让父组件刷新地址。5.2 el-upload文件数量获取与iOS上的PDF预览问题“vue中怎么获取el-upload的文件数量”看着是个小问题但问的人很多说明Element Plus的上传组件在某些场景下行为不够直观。el-upload内部维护了一个文件列表但如果你直接用ref去拿组件的文件列表可能会发现自己期望的格式和实际拿到的不一样。更稳定的做法是利用组件提供的钩子on-change回调会在文件状态变更时触发你可以用uploadFiles参数拿到当前完整的文件列表再取它的length。如果你需要在用户点击上传按钮之前做校验一定要基于on-change维护一份自己的列表而不是依赖组件内部状态因为组件内部状态在受控和非受控模式下表现不一样。另一个跟移动端强相关的热搜是“vue a标签下载pdf在ios上会变成预览”。这是因为iOS上的Safari对PDF的策略是优先内置预览而不是下载。如果业务上确实需要强制下载常规思路是请求时带上响应头Content-Disposition: attachment并确认请求方式不是通过a标签直接跳转而是通过axios或fetch拿到blob之后再触发下载。这个方法在iOS上有一定效果但依然受WebView配置影响。如果你在iOS上用WKWebView加载本地Vue打包产物WebView的导航代理可能会拦截下载行为这种场景下通常需要原生端配合WebView层面能做的事情很有限。5.3 圆环进度条从需求到封装的完整练习组件化练手怎么做最有效我的建议是别一上来就搞那种几十个组件的大项目从“圆环进度条”这样的小组件开始反而更能理解封装思路。热搜里有“vue 圆环进度条”这需求在很多数据大屏、后台管理里都会出现。实现圆环进度条的方案有几个最轻量的不是canvas而是SVG。用两个circle底下一圈是底色上面一圈是进度色通过stroke-dasharray和stroke-dashoffset控制进度弧线显示多少。stroke-dasharray定义了虚线的长度模式你把它设置为圆的周长那整条线就是一个完整的圆stroke-dashoffset表示虚线起点偏移多少把偏移量设为周长减去进度对应的弧长就得到了想要的进度圆环。整个过程不涉及canvas的坐标计算代码量小而且SVG天然支持高清屏。组件的props可以这样设计percentage0到100的进度值、size圆环直径、strokeWidth线宽、color进度颜色、trackColor底色。内部用computed把percentage换算成周长和偏移量。再加一个动画监听percentage变化用一个简单的requestAnimationFrame让数字从旧值渐变到新值视觉上就平滑了。封装完成后你在任何页面只需要ProgressRing :percentage65 /就能用完全不用关心SVG细节。这才是组件化的意义内部实现可以随时换对外接口保持稳定。5.4 流式输出与点击节流两个容易被问懵的细节“vue流式输出”最近搜索热度挺高它的典型场景是AI对话用户发一句话后端不是一次性返回全部答案而是像打字机一样一段一段吐字。前端收到一段就用响应式状态把内容追加到页面上用户就能看到流式生成的过程。Vue里实现流式输出本质上是利用fetch读取ReadableStream。你用response.body.getReader()循环读取数据块解码后用TextDecoder拼接文本再通过reactive或ref更新页面。这里有个细节如果每读一个chunk就更新一次状态界面会非常卡因为Vue的响应式更新有开销。更好的做法是做小批量缓冲比如攒够50个字符再更新一次体感完全一致但性能好很多。“vue click事件截流”则是一个性能优化实战。比如一个提交按钮用户连点三次会发三个请求后端可能就创建了三条重复订单。不引入外部工具库的话可以写一个自定义指令v-throttle在绑定的按钮上监听click事件一段时间内只放行第一次触发后面的全部拦截。实现原理很Direct提前记录上一次执行的时间戳当前时间减去上次时间小于设定间隔时直接return否则放行并更新时间戳。把这段逻辑封装成指令模板里写v-throttle500就能给按钮加上500毫秒的截流不用在每个页面里重复写防抖逻辑。这是在组件化思想之外的另一个复用维度指令级复用。5.5 桌面端集成与WebView加载本地包组件化之外的兼容性话题热搜里有几条关于“vue项目怎么打包成exe”、“ios能否通过加载本地vue打包的文件打开项目”、“python中pywebview集成vue”的提问它们本质上是同一个话题Vue打包产物如何在非浏览器环境里运行。先说结论Vue项目打包出来的dist目录是纯静态资源任何能加载HTML、JavaScript、CSS的环境都能运行它包括Electron、pywebview、iOS/Android的WebView。问题通常出在两点一是资源路径二是接口地址。打包时如果base配置是绝对路径在本地file协议下资源会加载失败所以要在vite.config.js里把base设为./让资源引用变成相对路径。二是如果你用createWebHistory模式的路由在本地静态文件里直接打开会白屏因为History路由依赖服务端配置改成createHashHistoryhash模式可以避免这个问题或者用本地静态服务器托管dist目录。iOS WebView加载本地Vue包还有一个容易被忽略的点WebView的allowFileAccess和跨域限制。把打包产物放进App的Resource目录后用WKWebView的loadFileURL加载首页通常只要资源路径对就能显示。但如果你在Vue里请求了远程API会遇到混合内容或CORS的限制这些需要在原生端配置WKWebView的网络策略。pywebview也是类似逻辑它本质上是一个Python WebView的壳把dist目录指给它就行但要注意它实际渲染用的是系统WebView不同平台对Web特性的支持有差异有些太新的JavaScript语法在老WebView上可能直接报错。6. 常见问题与面试考点速查6.1 实战问题排查速查表把前面提到的高频问题整理成一张表方便你以后定位现象常见原因排查方向项目启动后Network不可用Vite默认绑定了localhost配置server.host: true重启后看终端提示的局域网IP自动导入Element Plus后ElMessage未定义函数式API没有被auto-import识别在AutoImport里配置ElementPlusResolver确认配置了正确的imports路径首次打开地图正常第二次空白keep-alive缓存导致mounted不再执行地图实例和DOM对不上在activated中判断并重新初始化地图或对地图页面不启用keep-aliveel-upload获取不到文件数量直接读组件内部状态容易被格式坑用on-change回调维护自己的fileList再取lengthiOS里点PDF变预览不是下载iOS对PDF默认预览a标签下载行为被系统拦截请求接口带Content-Disposition: attachment或blob下载必要时原生端配合本地打开dist目录白屏路由用了history模式或base路径错误改用hash模式配置base为相对路径组件卸载后定时器还在跑没有在onUnmounted里清理副作用检查setInterval、事件监听、第三方实例的销毁6.2 面试被问“组件化”时这样答不容易翻车“vue八股文”、“vue面试题大全”这类热搜词说明大家还是习惯用背题的方式准备面试。但组件化这个主题面试官其实不太想听你背“组件通信有哪些方式”而是想确认你有没有真正在项目里设计过组件。所以我给你一个答题框架建议。先说自己对组件化的理解组件化开发的核心不是语法而是通过合理拆分把复杂系统变成可维护、可复用、可独立演进的模块组合。然后用一个自己封装过的组件做例子讲清楚四件事这个组件要解决什么问题、为什么这个职责值得单独拆出来、组件的对外接口是怎么设计的props、emits、插槽、遇到了什么坑。比如你封装过一个日期范围选择组件直接说我封装了一个基于Element Plus的日期范围组件对外暴露startDate和endDate两个v-model内部处理了“跨月选择时月份面板自动切换”的细节用disabledDate限制只能选今天之后的日期。这样答比背十道题都管用。还有几个高频考点比如“key的作用是什么”“为什么循环渲染要加key”。这个题看着基础但很多人答不到点上。key的主要作用不是控制样式而是让Vue在diff的时候能识别出哪些节点是同一个节点从而精准地复用DOM、减少渲染开销避免组件状态错乱。比如你用index做key往列表头部插入一条数据所有元素的key都会变化Vue会误以为所有元素都是新元素造成不必要的重建甚至导致有状态组件比如输入框的内容错乱。所以key要选择稳定且唯一的值最好用业务id而不是数组下标。另外“vue生命周期”的面试变体也很多前面已经讲了created和onMounted的区别还有一个常见变体是“在onUnmounted里要做哪些事”。除了清理定时器和事件监听还有一个很关键的点如果组件里创建了第三方库实例比如地图、图表、播放器必须在onUnmounted里调用对应的destroy方法否则组件虽然被移除了但事件监听和定时器还挂在全局页面性能会不断下降。7. 第27天之后我的一个实在建议组件化开发学到这个阶段你会发现真正难的已经不是“会不会用某个API”而是“拿到一个模糊的需求能不能快速在脑子里规划出它的组件结构、数据流和通信方式”。这个能力说不上哪一天突然会获得它是在一个个小组件、一次次重构、一个个线上bug里慢慢磨出来的。如果你现在正好处于第27天我给你一个老实的建议这几天不要急着去啃新库也别沉迷刷面试题挑一个你之前写过的页面尝试用组件化的思路重写一遍。第一次重写肯定会发现拆分不合理、props设计冗余、事件命名混乱这很正常改第二遍就会顺手很多。我当年学Vue的时候把一个后台管理页面用不同方案重写了三次每次都有新体会。别怕慢这种“重构自己的代码”的练习比照着教程敲十遍demo都管用。最后分享一个我常用的判断习惯写组件时把自己想象成这个组件的“作者”而不是使用者。作者要考虑的不是“它现在够用就行”而是“如果别人不知道我内部怎么实现只看接口能不能顺畅地用起来”。带着这个心态写出来的组件基本不会太差。保持这个节奏后面进入第三阶段做完整项目时你会明显感觉到组件化给你带来的底气。