ARTICLE DETAIL

资讯详情

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

113个JS特效动画合集:从Canvas粒子到页面动效的实战指南

113个JS特效动画合集:从Canvas粒子到页面动效的实战指南 收集JS特效动画这件事我干了至少有五年。一开始只是想给自己维护的组件库配一套统一的动效选集后来发现每次做活动页、官网、数据大屏、产品落地页都会遇到几乎同样的诉求——需要一个“不落俗套”的入场动画、一个能跟着数据变的图表动效、一个鼠标滑过就炸开的粒子效果甚至是一个在页面底部滚动展示的进度条。前后攒了113个JS特效动画效果不敢说个个惊艳四座但我能负责任地讲绝大多数场景你都能从里面挑到一个能直接改、直接上、不翻车的方案。这113个特效不是靠单一来源堆出来的有从CodePen上扒的有从老项目里挖出来重新整理的也有自己从零手写的还有一些是把Canvas、Web Animations API、IntersectionObserver等技术点揉在一起做的“杂交款”。它们覆盖了粒子系统、鼠标交互、文字动效、3D场景、滚动视差、表单反馈这些主流玩法。如果你是刚入门的前端可以直接拿它当练手题库如果你是做业务的老手可以把它当“特效工具箱”关键时候翻一翻总有一款适合你。1. 113个特效动画的收集思路与分类逻辑1.1 为什么是“113”这个数字很多人会问特效这种东西要收多少才算够我的答案是收多少都不嫌多但“够用”是个非常现实的指标。我一开始收了大概七八十个覆盖主流场景后发现有些分类还是薄弱比如同样是鼠标跟随只有线条光效没有粒子拖尾只有PC端能看没有移动端适配版本。后来陆续补充到一百出头最终稳定在113个。113个不是刻意凑的而是按“场景覆盖”倒推出来的结果。我先列业务里几乎每个月都会碰到的需求类型——首屏入场、页面加载、导航反馈、按钮交互、图表动效、图片展示、文字特效、鼠标特效、背景特效、表单验证反馈、滚动动效、音频可视化等等每一类再配3到8个不同实现方案。等到所有需求类型都被覆盖时数量自然就到了113。收藏大量特效的真正价值不在于数字大而在于你需要在不同实现方式之间做横向对比。举个例子同样是鼠标跟随特效一个用原生mousemove逐帧改left和top一个用transform配合requestAnimationFrame另一个用Canvas离屏绘制三者在低端手机上的表现差距能拉到三倍以上。只有把不同方案放在一起对比你才能真正理解哪种实现更稳。1.2 按使用场景分类的核心逻辑我整理这113个特效时没有按“用没用Canvas”或者“代码长短”这种技术维度分类而是按“用户会在什么场景下看见它”来分。因为技术维度对选品没有帮助业务方只会说“我要一个看起来很炫的首页”不会说“我要一个基于Canvas的粒子系统”。按场景分类后我大致切成了十一个组入场与出场动画、加载与进度反馈、鼠标指针跟随与反馈、按钮与表单交互动效、文字特效与打字机效果、图片轮播与卡片效果、滚动渐显与视差滚动、导航菜单与侧边栏动效、背景粒子与WebGL场景、图表与数据可视化动效、音频可视化与其他趣味玩法。每组里的特效又会再细分“轻量型”和“重量型”。轻量型基本不依赖额外库纯原生JS加CSS就能跑适合用在高流量页面重量型可能需要Three.js、GSAP这类库视觉效果更炸适合品牌活动页或者需要“镇场子”的场合。这样一分类业务提需求时我能在几秒内给出合适的推荐而不是在一堆收藏链接里乱翻。2. 选特效前必须想清楚的三个问题2.1 性能预算先看消耗再谈好看从113个特效里选一个用最大的误区是“哪个炫就上哪个”。特效动画再好看如果它把主线程占满、每秒掉几十帧用户的第一反应不是“好酷”而是“这网页为什么这么卡”。选型前我会先估一笔性能账。纯CSS transform和opacity动画走的是合成器线程GPU参与度高对主线程影响最小用JavaScript逐帧操作DOM动画会频繁触发布局和重绘在主线程上消耗大量时间Canvas绘制如果没有做离屏缓存或像素级控制在低端机上更是重灾区。以我手头113个特效里的“粒子爆炸”为例同样是1000个粒子做扩散效果用纯JS每帧更新DOM样式的版本在低端安卓机上帧率能跌到个位数但改成Canvas单画布绘制后因为减少了DOM节点数和样式计算量帧率能稳定在40到50帧。这个差距不是代码水平问题是渲染路径选择问题。真正专业的做法是把特效按性能消耗分三档低消耗档适合常驻页面比如按钮反馈、滚动渐显中等消耗档适合一次性场景比如页面入场动画播完就停高消耗档只适合短时、局部、可关闭的特殊场景。我整理113个特效时每个特效都标注了基于“普通4G手机中端CPU”的性能评级就是为了避免团队里的小朋友被视觉效果冲昏头。2.2 交互层级动画是“配角”不是“主角”做特效动画最容易犯的另一个错误是让动效喧宾夺主。动画确实能吸引注意力但如果它的存在让按钮点击变得困难、让用户找不到重点、让页面内容读取被拖延它就不是加分项而是减分项。我总结过一个“动效层级”原则主行动按钮的反馈动效必须在300毫秒内完成否则用户会感觉点击后没反应页面入场动画整体时长不要超过800毫秒超过之后用户会焦虑背景特效的对比度和明度必须低于前景内容否则会干扰可读性。113个特效里有一类“背景粒子背景光效”很多初学者喜欢把粒子调得又大又亮结果数据文字完全看不清。正确做法是把粒子透明度压到20%以下、尺寸控制在4像素以内、颜色选择低饱和度的色系让它成为“能感知但不抢戏”的氛围层。适合放在登录页、404页、官网大屏但不适合放在密集数据展示的业务后台。同样特效和交互元素之间要留出“安全区”。鼠标跟随特效如果做了吸附或放大效果会影响用户点选列表项iframe内嵌页面里的特效如果不做停止逻辑滚动父页面时它还在后台跑白白消耗资源。这些细节决定了特效到底是提升体验还是制造麻烦。2.3 兼容与降级移动端不是PC的缩小版我见过太多次这样的场景特效在Chrome浏览器里丝滑流畅拿到微信内置浏览器或者部分安卓自带浏览器上要么不触发要么错位要么直接白屏。问题出在API兼容性而不是代码逻辑。113个特效里我特别标注了“基础API要求”。比如使用Pointer Events比单独使用Mouse Events要更稳妥因为它在移动端能同时处理触摸和鼠标使用IntersectionObserver做滚动检测时要考虑到部分旧浏览器不支持需要手动给出fallback使用CSS backdrop-filter做毛玻璃效果时很多安卓浏览器会直接忽略视觉效果会打折扣。降级策略是我的保留动作。所有依赖WebGL的特效我会加上“检测失败则显示静态背景”的逻辑所有依赖CSS 3D的特效我会用supports做能力检测移动端还要考虑touch-action: manipulation避免300毫秒点击延迟以及passive: true减少滚动时的性能损耗。说白了“总有一款适合您”的前提是特效适配您的用户群体。如果你的用户有30%以上还在用旧系统就老老实实选轻量级方案或者给特效配一个体面的降级效果别让技术炫技伤害真实用户。2.4 113个特效里的推荐Top 10整理一下我自己在真实项目中用得最频繁、改动成本最低、出图效果又稳的10个特效你可以直接当选型参考特效名称类型性能消耗适用场景依赖粒子文字消散Canvas文字特效中首页Banner、专场活动无鼠标线条拖尾Canvas鼠标跟随中创意官网、个人主页无数字滚动计数器数字动画低数据大屏、统计页面无滚动渐显列表DOMIntersectionObserver低博客、门户首页、落地页无3D卡片翻转CSS3DJS低产品展示、会员卡无涟漪按钮反馈Canvas/CSS低登录表单、主按钮无打字机循环效果文字特效低官网标语、聊天界面无星空背景粒子Canvas背景中登录页、404页无视差滚动物体transformJS低品牌故事、长图页面无音频跳动可视化Web AudioCanvas中高音乐类页面、活动游戏无这个表格只是113个里面的冰山一角。真正好用的时候往往是业务场景和特效之间的“一拍即合”比如运营说要做年中大促主视觉我从113个里挑出“粒子汇聚成Logo”配合“数字滚动到销量”效果直接对标外包报价大几千的定制页面。3. 几个值得反复研究的特效实现细节附核心代码3.1 粒子文字消散Canvas与离屏渲染的配合113个特效里粒子文字一直是最受欢迎的“门面担当”。原理并不复杂先把文字绘制到一个离屏Canvas上读取像素数据得到每个文字像素的坐标再把这些坐标作为粒子的目标位置让粒子从初始的随机位置飞向目标位置。一个完整的流程分三步。第一步创建离屏Canvas绘制文字并遍历getImageData提取有内容的像素点第二步把粒子的当前坐标初始化为画布底部随机位置第三步在requestAnimationFrame循环里用缓动函数让粒子逐步趋近目标坐标。核心代码长这样const targetCanvas document.getElementById(target); const ctx targetCanvas.getContext(2d); const offCanvas document.createElement(canvas); offCanvas.width targetCanvas.width; offCanvas.height targetCanvas.height; const offCtx offCanvas.getContext(2d); // 第一步离屏绘制文字 offCtx.font bold 120px Microsoft YaHei; offCtx.textAlign center; offCtx.textBaseline middle; offCtx.fillText(113, offCanvas.width / 2, offCanvas.height / 2); // 获取像素数据 const imageData offCtx.getImageData(0, 0, offCanvas.width, offCanvas.height); const pixels imageData.data; const particles []; // 每隔3个像素采样一次控制粒子数量 for (let y 0; y offCanvas.height; y 3) { for (let x 0; x offCanvas.width; x 3) { const alpha pixels[(y * offCanvas.width x) * 4 3]; if (alpha 128) { // 粒子起点从画布随机底部开始 particles.push({ x: Math.random() * offCanvas.width, y: offCanvas.height Math.random() * 100, targetX: x, targetY: y, vx: 0, vy: 0 }); } } }第二步和第三步的核心是动画循环。用指数衰减的缓动实现弹性收敛粒子速度逐步减小位移逐渐逼近目标。加一点随机速度分量可以制造“炸开再收拢”的视觉高潮。function animate() { ctx.clearRect(0, 0, targetCanvas.width, targetCanvas.height); particles.forEach(p { p.x (p.targetX - p.x) * 0.06; p.y (p.targetY - p.y) * 0.06; ctx.fillStyle p.targetColor || #0ff; ctx.fillRect(p.x, p.y, 2.2, 2.2); }); requestAnimationFrame(animate); } animate();这里有两个容易被忽略的坑。第一粒子数量不能直接取所有像素点要隔几个像素采样一次否则几万粒子直接卡死手机第二粒子颜色如果想做渐变过渡不要把rgba字符串塞进fillStyle里逐帧拼接那会产生大量字符串分配开销应该预先把颜色解析成RGB分量再拼装。还有更进阶的玩法粒子在飞行中可以读取一张渐变图的像素按位置取色实现彩虹渐变。3.2 鼠标跟随光效用事件节流与GPU加速解决卡顿鼠标跟随特效几乎每批需求里都会出现一次但不同写法差别极大。最差的写法是在mousemove回调里直接修改元素的left和top这种做法每帧都会触发强制同步布局性能极差。好一点的写法是监听pointermove事件把坐标存下来通过requestAnimationFrame统一更新更新时只改transform: translate3d让浏览器走GPU合成。我的实现模板大概是这样的const cursor document.getElementById(cursor); let mouseX window.innerWidth / 2; let mouseY window.innerHeight / 2; let currentX mouseX; let currentY mouseY; let rafId null; window.addEventListener(pointermove, (e) { mouseX e.clientX; mouseY e.clientY; if (rafId null) { rafId requestAnimationFrame(updateCursor); } }, { passive: true }); function updateCursor() { currentX (mouseX - currentX) * 0.15; currentY (mouseY - currentY) * 0.15; cursor.style.transform translate3d(${currentX - cursor.offsetWidth / 2}px, ${currentY - cursor.offsetHeight / 2}px, 0); rafId null; }事件监听器里只记录坐标动画更新全交给RAF这样即使鼠标高速移动监听频率再高实际渲染也只会在每帧执行一次。用translate3d而不是left/top也是为了让浏览器把元素提升到合成层不触发重排。在113个特效里鼠标跟随的变体非常多——光效尾巴、粒子拖尾、磁吸按钮、视差跟随。变体只是视觉分支核心逻辑都逃不开“事件节流 RAF transform”这三板斧。还有一个经验鼠标离开窗口后要主动隐藏特效元素否则光标会悬停在页面边缘影响视觉品质。3.3 滚动渐显与视差IntersectionObserver是更稳的选择滚动触发动效常用两种方式监听scroll事件计算元素位置或者用IntersectionObserver在元素进入视口时触发。前者实现简单但性能差后者是更现代的选择能异步监听元素与视口的交叉状态避免滚动事件频繁触发带来的性能浪费。我用113个特效里的“滚动渐显列表”做示范。给目标元素加上淡入和位移的起始状态用IntersectionObserver在元素进入视口时移除状态赋予过渡类实现优雅的出现效果。const observer new IntersectionObserver((entries) { entries.forEach(entry { if (entry.isIntersecting) { entry.target.classList.add(visible); observer.unobserve(entry.target); } }); }, { threshold: 0.2 }); document.querySelectorAll(.fade-item).forEach(el observer.observe(el));配合的CSS只需要定义基础状态和可见状态.fade-item { opacity: 0; transform: translateY(30px); transition: opacity 0.6s ease, transform 0.6s ease; } .fade-item.visible { opacity: 1; transform: translateY(0); }关键细节有两个。第一个是unobserve滚动渐显效果一旦触发就别再监听否则元素滚出视野再滚回来时会重复播放不仅干扰阅读还会造成不必要的观察器回调。第二个是threshold不能设置过大元素一半进入视口才触发在首屏大图场景会显得延迟严重我一般把阈值放在0.15到0.3之间既保证不会提前触发也不会让用户等太久。3.4 数字滚动与进度动画牢记easing函数数据大屏和统计类的页面数字动态增长是刚需。这种特效原理简单就是从一个起始值插值到目标值关键是缓动函数的选择和更新频率控制。用线性插值做百万级数字会显得非常机械而用easeOutExpo这类缓动函数可以让增长先快后慢视觉上更符合“滚到目标数字”的感觉。下面是一个极简实现function animateNumber(el, target, duration 1200) { const start performance.now(); const from 0; function easeOutExpo(t) { return t 1 ? 1 : 1 - Math.pow(2, -10 * t); } function update(now) { const progress Math.min((now - start) / duration, 1); const eased easeOutExpo(progress); const value Math.floor(from (target - from) * eased); el.textContent value.toLocaleString(); if (progress 1) requestAnimationFrame(update); } requestAnimationFrame(update); }使用performance.now()作为时间基准而不是在每一帧里计算差值能保证动画时间不受帧率波动影响。toLocaleString可以自动加千分位在大数字场景非常实用。113个特效里数字动画也有好几个变体增长百分比、大屏指挥官计数、排行榜分数跳动、倒计时翻牌。原理都是插值加缓动差别只是展示层样式。一个实用技巧是数字符号变化时实际是替换了DOM内容如果这个数字在列表中会被频繁更新建议用独立的Canvas或单行文本节点避免触发整块列表的重排。4. 特效落地时最常见的五个坑与排查实录4.1 特效白屏控制台却一个报错都没有这是113个特效使用现场里反馈最多的问题。特效元素区域一片空白打开控制台也没有红字报错像是代码被静默吞掉了。排查思路我一般按四步走。第一步看特效初始化时DOM是否已加载完成很多特效脚本写在head里直接查document.getElementById拿到的是null操作失效但不报错加DOMContentLoaded监听或把脚本挪到/body前即可解决。第二步检查Canvas的宽高是否设置异常有些特效依赖CSS尺寸但Canvas内部的实际像素尺寸没有同步设置看起来就是空白第三步确认是否有异步数据没返回比如音频可视化依赖audio加载没加载完就用getByteFrequencyData拿到的全是0界面自然没反应第四步检查页面是否启用了某些安全策略比如iframe嵌入了第三方域名Canvas的toDataURL或getImageData会被浏览器拦截某些粒子文字特效就会失效。4.2 一滚动页面就卡成幻灯片最常见的“页面卡顿元凶”是滚动事件里绑定了大量耗时操作。比如每个滚动事件回调里都去读取offsetTop、getBoundingClientRect或者在回调里直接改一堆元素的样式这等于让浏览器每帧都做重复的布局计算。解决办法分成三个层面。第一层能用IntersectionObserver解决的滚动检测就别用scroll监听第二层必须在scroll里做的用requestAnimationFrame把事件封装成每帧最多执行一次第三层纯视觉的视差运动要优先考虑CSSposition: sticky或者transform避免操作布局属性。还有一点容易被忽略如果你把一个全屏Canvas粒子特效放在滚动容器外面滚动时它默认一直在重绘即使看不到也在消耗GPU。正确的做法是监听滚动判定当前区域是否需要继续绘制不可见时直接cancelAnimationFrame节省的资源非常可观。4.3 在React/Vue里用特效事件总是重复触发从113个特效里选出的代码大多是原生JS直接搬到React或Vue框架里经常会出现两个问题组件卸载了事件还在或者重复触发了多个实例。核心原因是没有处理组件的生命周期。比如在React的useEffect里绑定事件如果不做清理组件每次重新挂载都会绑定一份新事件。这里我最常用的解决模板是useEffect(() { const onMove () { /* 特效逻辑 */ }; window.addEventListener(pointermove, onMove); return () window.removeEventListener(pointermove, onMove); }, []);类似的解构requestAnimationFrame也必须在cleanup里执行。框架调用原生JS特效时应该只让JS负责“渲染”不与数据流强绑定特效内部需要的数据通过ref引用注入。我一般还会给特效实例加一个destroy()方法里面统一做取消动画循环、移除事件监听、清除Canvas画布三件事组件卸载时调用它就不会出现“页面已经切换了旧特效还在后台跑”的资源泄漏。4.4 移动端点了没反应按钮像被“吃掉”移动端特效失效有几种典型表现hover效果不触发自定义光标不显示点击特效层上的按钮没反应。原因很简单移动端没有鼠标不会触发mousemove和mouseenter而覆盖在整个页面上的特效层如果不加pointer-events: none会拦截掉所有触摸点击。所以我整理113个特效时凡是全屏覆盖的鼠标跟随特效、粒子背景层CSS里强制写上pointer-events: none保证它只负责视觉呈现不参与事件流。这行代码基本能解决“按钮点不动”的诡异问题。对于需要触摸触发的交互动效我建议优先使用touchstarttouchend配合click做兼容但要注意事件可能触发两次。一个方法是记录最近一次触摸的时间戳在click回调里判断若相隔不足500毫秒则忽略或者直接使用Pointer Events统一处理鼠标和触摸事件这是我更推荐的方式。4.5 公共问题速查表问题现象可能原因排查方向解决方法特效白屏无报错DOM未就绪或Canvas尺寸为0检查初始化时机、打印宽高监听DOMContentLoaded显式设置Canvas宽高页面滚动掉帧scroll回调里频繁读写布局属性查看Performance面板、减少强制同步布局改用IntersectionObserver、用transform代替left/top事件重复触发框架生命周期未清理打印事件触发次数、检查绑定来源useEffect cleanup中解绑提供destroy方法移动端点不到按钮特效层拦截触摸检查元素堆叠和pointer-events给特效容器加pointer-events: none动画时长太慢没有设置动画总时长依赖帧数用performance.now计算AnimationProgress统一使用时间基准和缓动函数浏览器版本不一致用到了新API没有降级检查控制台警告做能力检测使用supports、特性检测和fallback方案5. 把现成特效改造成自己作品的方法论5.1 参数化改造让一个特效长成十个样子从113个特效里选中一个适合的如果想让它真正做到“适合你的项目”我强烈建议把特效里的关键数值全部抽成参数。颜色、粒子数量、动画时长、缓动函数、触发阈值、透明度、方向偏移这些数据千万不要散落在代码各处而是统一收敛成一个配置对象。比如粒子特效我可能会这样组织const config { particleCount: 1200, colors: [#ff6b6b, #4ecdc4, #ffe66d], speed: 0.08, size: 2.4, connectDistance: 100, interactive: true, reducedMotion: false };这样做的好处是显而易见的。运营临时说“我想换个主色调”你只需要改colors数组产品说“这个动效太慢了”改speed就行测试说“低端机卡”直接把particleCount降一半。参数化的灵感其实就是CSS变量的思路——把设计变量和实现逻辑分离。更进阶的玩法是在配置里加入“自动降级”逻辑。如果检测到低帧率就动态调低粒子数量或直接关闭某些高消耗特效而不是让用户忍受卡顿。我在113个特效里给一部分常驻特效加了这种自适应机制真实上线后好评率很高。5.2 让特效响应页面状态现成特效最常见的问题是“与业务脱节”它效果再漂亮也总是停留在表面。想让特效真正融入项目就要把它和页面状态绑定起来。数据大屏里的数字滚动背后的驱动是接口返回的真实数据电商活动页的粒子汇聚动画汇聚结束之后要引导用户点击按钮官网首页的滚动视差应该和每个板块的进入退出节奏同步。我可以给你一个非常落地的方式把特效的播放状态交给一个统一的事件管理器。比如用自定义事件page-section-change来通知各路特效“当前进入第几屏”需要播放的播放需要停止的停止。这种“状态驱动特效”的思路比让每个特效自己监听页面行为要干净得多。再举一个具体例子。做一个“弹窗打开时背景粒子停止运动”的效果不需要改造粒子特效本身只需要在弹窗打开时调用特效实例的pause()关闭时调用resume()。如果特效没有这两个方法你在二次封装的时候补上即可。这就是113个特效里很多代码需要做的事情——不是每个特效拿来就能用而是让它们变得“可指挥”。5.3 组合使用入场、交互、退场一次配齐单个特效再精致也很难撑起一个完整页面。真正高分的页面体验通常是由一组特效默契配合完成的。我在业务里常用的组合套路是入场阶段用大气的“粒子汇聚Logo”或“文字渐显上移”主视觉交互阶段配“鼠标跟随光效”或“3D卡片翻转”滚到数据区域时上“数字滚动计数器”和“图表柱状增长”离开页面时再来一个微妙的“元素淡出下沉”。组合特效最重要的原则是“节奏感”。入场动画和大标题动效不能同时抢占用户注意力最好区分先后顺序背景粒子始终保持在低优先级层按钮反馈只在点击瞬间出现避免常驻动画让页面显得杂乱。这套思路放在113个特效里就是一个“动效编排”的过程相当于给页面写一个剧本每个特效都有明确的上场时间和离场时机。我建议你从113个特效里先挑三个最基础、最吃的组合方式试一下首屏入场粒子文字或渐显 滚动渐显列表 数字滚动。这三个组合几乎覆盖了营销活动页的90%需求其他特效都是在这基础上做视觉加花。5.4 发布前最后一道检查清单特效做完不能直接上线我每次发版前都会过一次自己整理的检查清单。第一项是动效时长所有动画尽量控制在0.2到0.8秒之间长动画要有跳过或关闭入口第二项是减少动态页面比例首屏不要超过两个主要动效否则用户会迷失第三项是尊重用户的“减弱动态效果”偏好通过prefers-reduced-motion媒体查询把一些非必要的动效关掉第四项是检查重复触发场景比如快速点击按钮时波纹特效不能无限叠加要限制并发数量。还有一个容易忽略的细节是动效暂停与恢复。页面切到后台再切回来时requestAnimationFrame会自动暂停但有些Canvas特效在重新激活后会突然跳一下原因是它记录的时间基准没有重置。解决办法是在visibilitychange事件里重置起始时间或者干脆在不可见时暂停、可见时重新开始。最后发布前一定要做一次“低配机弱网”实机测试。你在MacBook上看到的丝滑效果在两年前的安卓手机上可能是另一番景象。把所有特效的性能评级提前做好遇到低端设备自动降级才能保证“总有一款适合您”不是一句空话。我个人整理这113个特效动画时最大的感受就是你收藏得越多越会觉得“特效并不等于炫技”。真正的功力在于判断力——在合适的页面、合适的位置、合适的时机用一个恰到好处的动效来引导用户注意力。那种“全场皆动效”的页面其实很少有人愿意多看两眼。最后再分享一个小技巧把所有经常调的数字比如动效时长、颜色、粒子上限、缓存开关统一抽成一个全局配置对象或者直接用CSS变量暴露给设计团队改。这样你的特效仓库就不再是“一次性的源码”而是一套越用越顺手的动效基础设施。113个特效只是起点真正值钱的是你围绕它们建立起来的这套选型、改造、组合、降级的完整流程。
返回列表