Excel宏与VBA自动化:从零基础到实战应用全解析

📅 2026/8/13 9:15:53
Excel宏与VBA自动化:从零基础到实战应用全解析
1. 项目概述为什么说Excel宏是办公效率的“核武器”如果你每天还在重复着复制粘贴、格式调整、数据汇总这些枯燥的Excel操作那说明你还没真正解锁Excel的终极生产力工具——宏。宏不是某个高深莫测的黑科技它本质上是一段记录你操作步骤的“剧本”或者是你亲手编写的一系列指令。它的核心价值在于将你手动需要点击几十次、耗费十几分钟才能完成的复杂任务变成一键执行的自动化流程。想象一下每天处理几十份格式混乱的报表原本需要一上午现在点一下按钮喝杯咖啡的功夫就全部搞定这种解放双手的感觉就是宏带来的最直接价值。从网络热词可以看出大家围绕Excel宏的探索非常活跃无论是基础的“VBA宏”、“WPS宏”还是更高级的“Python获取Excel数据”、“Excel导入数据库”都指向同一个需求如何让数据工作更智能、更省力。很多人对宏望而却步觉得那是程序员的事其实不然。宏的学习曲线非常友好你可以从最简单的“录制宏”开始完全不需要写代码就能实现自动化。而当你需要更复杂、更灵活的功能时再逐步接触VBAVisual Basic for Applications这门内置于Excel的编程语言。本教程的目标就是带你从零开始不仅学会使用宏更要理解其背后的逻辑最终能根据你的实际工作场景定制专属的自动化解决方案真正把Excel用活。2. 核心思路拆解从“记录操作”到“编写逻辑”要掌握宏必须理解它的两种核心创建方式录制宏和编写VBA代码。这是两条路径也是两个阶段。2.1 录制宏零代码的自动化起点录制宏是Excel提供的最人性化的功能。它的原理就像录音机你点击“开始录制”然后你在Excel里做的每一步操作——点击某个菜单、输入公式、设置单元格格式、排序筛选——都会被Excel忠实地记录下来。当你点击“停止录制”这些操作就被保存为一个宏模块。下次你运行这个宏Excel就会像播放录音一样完全复现你之前的操作序列。这解决了什么问题它完美应对了那些步骤固定、重复性高的任务。比如你每周都要从系统导出一份原始数据需要执行以下操作删除前两行标题、将C列格式设置为“会计专用”、在D列添加一个求和公式、最后将A列按升序排序。手动做一遍可能只要2分钟但录制为宏后未来处理任何类似表格都只需要点一下按钮。更重要的是录制宏生成的VBA代码是你学习VBA语法最好的“教科书”。你可以查看它生成的代码直观地看到“设置单元格格式”对应哪句VBA命令“排序”又是如何写的这是从使用者迈向创造者的关键一步。注意录制宏虽然方便但有个致命缺点它记录的是“绝对路径”式的操作。比如你录制时是在“Sheet1”的“A1”单元格开始操作的那么运行宏时它也会死板地去找“Sheet1”的“A1”。如果你的数据表位置或结构稍有变化宏就可能报错。因此录制宏更适合处理模板固定、数据位置严格一致的任务。2.2 VBA编程解锁无限可能的自定义自动化当你发现录制宏不够灵活时就该VBA登场了。VBA是一种面向对象的编程语言它允许你定义变量、使用循环、判断条件、调用丰富的Excel对象模型。这意味着你的宏可以“思考”和“决策”。例如你需要处理一个文件夹下所有Excel文件提取每个文件“汇总”工作表里B10单元格的值并合并到一个总表中。录制宏对此无能为力因为你无法预知文件数量和名字。但用VBA你可以写一个循环让程序自动遍历文件夹打开每一个文件读取指定位置的数据然后关闭文件继续下一个。这就是编程逻辑带来的质变从执行固定步骤到处理动态、不确定的任务。VBA的核心是操作Excel对象。你可以把Excel理解为一个由不同对象组成的结构最大的对象是ApplicationExcel应用程序本身下面有Workbook工作簿Workbook里有Worksheet工作表Worksheet里有Range单元格区域。VBA就是通过代码来指挥这些对象。例如Worksheets(“Sheet1”).Range(“A1”).Value “Hello”这句代码的意思就是在名为“Sheet1”的工作表上找到A1单元格把它的值设置为“Hello”。理解了这种对象层级关系就拿到了操作Excel的钥匙。3. 环境准备与基础操作迈出第一步在开始创作宏之前我们需要确保Excel的宏功能是开启的并熟悉最基础的操作界面。3.1 启用开发工具与宏安全性设置默认情况下Excel的菜单栏里是没有“开发工具”选项卡的而这是我们操作宏的大本营。启用方法很简单在Excel中点击“文件”-“选项”-“自定义功能区”在右侧的“主选项卡”列表中勾选“开发工具”然后确定。这时你的Excel顶部菜单栏就会出现“开发工具”选项卡。接下来是宏安全性设置。由于宏可以执行代码存在潜在风险比如来自不明来源的宏可能含有病毒Excel默认设置会禁止所有宏的运行。为了我们学习和开发需要调整这个设置。点击“开发工具”选项卡下的“宏安全性”在弹出的信任中心设置中选择“禁用所有宏并发出通知”。这个设置是最平衡的它不会自动运行任何宏但当打开包含宏的文件时Excel会在顶部给出一个安全警告栏你可以选择“启用内容”。这样既安全又不影响我们使用自己编写的宏。实操心得千万不要为了方便而选择“启用所有宏”。我曾见过有同事因为打开了带恶意宏的附件导致整个表格数据被清空。安全警告栏多点击一次“启用”换来的是长久的数据安全。3.2 你的第一个宏录制与运行让我们通过一个最简单的例子来感受宏的魅力。假设你经常需要将选中的单元格区域快速设置为加粗、红色字体、并加上边框。准备数据在一个空白工作表的A1:C5区域随意输入一些数字或文字。开始录制点击“开发工具”-“录制宏”。会弹出一个对话框。宏名给你的宏起个名字比如“快速格式化”。宏名不能有空格通常用英文或下划线连接。快捷键可以设置一个快捷键如CtrlShiftF以后按这个组合键就能直接运行宏。说明可以写一段描述方便以后回忆这个宏是干什么的。执行操作点击确定后录制开始。此时你的所有操作都会被记录。请执行选中A1:C5区域 - 点击“开始”选项卡设置字体加粗B- 将字体颜色设为红色 - 点击边框按钮选择“所有框线”。停止录制点击“开发工具”-“停止录制”。测试运行清空另一个区域如E1:G5的格式输入一些新数据。然后选中这个新区域点击“开发工具”-“宏”在列表中选择你刚录制的“快速格式化”点击“执行”。你会看到新区域瞬间被格式化成和之前一模一样。恭喜你已经创建并运行了你的第一个宏你可以点击“开发工具”-“Visual Basic”或者按AltF11打开VBA编辑器在左侧“模块”文件夹下找到新生成的模块双击就能看到Excel自动生成的VBA代码。这些代码就是你刚才操作的“翻译”。4. VBA核心语法精讲从看懂到会写要自己编写宏必须掌握一些VBA的核心语法概念。别担心我们只学最常用、最必要的部分。4.1 变量、数据类型与对象变量就像是一个个盒子用来存放数据。在VBA中使用变量前最好先声明它这能让程序更高效、更易读。声明变量的关键字是Dim。Dim myValue As Integer 声明一个名为myValue的变量类型是整数(Integer) Dim userName As String 声明一个名为userName的变量类型是字符串(String) Dim isFinished As Boolean 声明一个名为isFinished的变量类型是布尔值(True/False)常见的数据类型有Integer整数Long长整数Double双精度浮点数可带小数String文本字符串Boolean逻辑值Date日期以及最重要的Range单元格对象和Worksheet工作表对象。给变量赋值使用等号myValue 100 userName “张三” isFinished True操作Excel的核心是对象。我们通过“点号.”来访问对象的属性和方法。属性对象具有的特征如单元格的值Value、颜色Color、行高RowHeight。读取或设置属性。Dim rng As Range Set rng Worksheets(“Sheet1”).Range(“A1”) ‘将A1单元格对象赋值给变量rng rng.Value “产品名称” ‘设置A1单元格的值 currentValue rng.Value ‘读取A1单元格的值到变量currentValue方法对象可以执行的动作如选中Select、复制Copy、删除Delete。rng.Select ‘选中A1单元格 rng.Copy Destination:Worksheets(“Sheet2”).Range(“A1”) ‘将A1复制到Sheet2的A14.2 流程控制让宏学会判断和循环这是让宏变“聪明”的关键。条件判断If...Then...Else根据条件执行不同的代码块。Dim score As Integer score 85 If score 90 Then Range(“B1”).Value “优秀” ElseIf score 60 Then Range(“B1”).Value “及格” Else Range(“B1”).Value “不及格” End If循环For...Next, For Each...Next, Do While...Loop重复执行某段代码。For...Next明确知道要循环多少次。‘将A1到A10单元格依次填入1到10 Dim i As Integer For i 1 To 10 Cells(i, 1).Value i ‘Cells(行号, 列号)是另一种引用单元格的方式 Next iFor Each...Next遍历一个集合中的每个对象如一个区域中的所有单元格。Dim cell As Range For Each cell In Range(“A1:A10”) If cell.Value 5 Then ‘如果单元格值大于5 cell.Interior.Color RGB(255, 200, 200) ‘将其背景色设为浅红色 End If Next cellDo While...Loop当某个条件为真时一直循环。Dim rowNum As Integer rowNum 1 Do While Cells(rowNum, 1).Value “” ‘当A列单元格不为空时继续循环 ‘…执行一些操作… rowNum rowNum 1 ‘行号加1处理下一行 Loop4.3 过程与函数模块化你的代码把代码组织成一个个独立的功能块便于管理和调用。子过程Sub执行一系列操作不返回值。我们录制的宏就是一个Sub。Sub 清理数据() ‘这里写清理数据的代码 MsgBox “数据清理完成” ‘弹出一个提示框 End Sub函数Function执行计算并返回一个值。可以像Excel内置函数一样在工作表公式中使用。Function 计算税费(金额 As Double) As Double If 金额 5000 Then 计算税费 金额 * 0.03 Else 计算税费 金额 * 0.1 End If End Function在工作表单元格中输入计算税费(B2)就可以调用这个自定义函数。5. 实战案例解析构建常用自动化工具理论学得再多不如动手做一个项目。下面我们通过三个由浅入深的实战案例将知识融会贯通。5.1 案例一智能数据清洗与格式化工具场景每天从业务系统导出的销售数据第一行是没用的标题第二行是英文表头数据从第三行开始。需要删除前两行将“Sales”列改为“销售额”将“Date”列改为“日期”并设置为中文日期格式最后为数据区域添加边框。思路这个任务步骤固定非常适合用录制宏生成基础代码然后进行优化。录制基础宏对着一个样例文件操作一遍上述步骤录制宏。优化代码关键步骤删除行录制宏会生成类似Rows(“1:2”).Select和Selection.Delete的代码。这没问题。修改表头录制宏会记录你点击某个单元格并输入文字的动作。我们可以优化为直接给单元格赋值。‘将原代码中关于输入“销售额”和“日期”的冗长操作替换为 Cells(1, 3).Value “销售额” ‘假设原“Sales”在C列 Cells(1, 4).Value “日期” ‘假设原“Date”在D列设置日期格式录制宏生成的格式代码可能很复杂。我们可以用更清晰的方式Columns(“D:D”).NumberFormatLocal “yyyy-m-d” ‘设置D列为日期格式添加边框录制宏可能选中了整个区域再添加边框。我们可以用CurrentRegion属性动态获取数据区域这样无论数据有多少行都能正确添加边框。Dim dataRng As Range Set dataRng Range(“A1”).CurrentRegion ‘获取以A1为起点的连续数据区域 dataRng.Borders.LineStyle xlContinuous ‘设置边框线型为连续线最终代码示例Sub 智能清洗数据() ‘假设数据从A1开始 Rows(“1:2”).Delete Shift:xlUp ‘删除第1、2行下方单元格上移 Cells(1, 3).Value “销售额” Cells(1, 4).Value “日期” Columns(“D:D”).NumberFormatLocal “yyyy-m-d” Dim dataRng As Range Set dataRng Range(“A1”).CurrentRegion dataRng.Borders.LineStyle xlContinuous MsgBox “数据清洗完成”, vbInformation End Sub5.2 案例二多工作簿数据合并报告场景每月底你需要将销售一部、二部、三部提交的三个独立Excel文件结构相同中的数据合并到一份总报告中。思路这需要VBA具备操作多个文件的能力。核心是使用Workbooks.Open方法打开文件以及ThisWorkbook代表当前正在运行宏的工作簿。准备总表新建一个Excel文件作为“总报告”设计好表头如部门、产品、销售额、日期。编写合并代码Sub 合并多部门数据() Dim sourcePath As String Dim sourceFile As String Dim destSheet As Worksheet Dim lastRow As Long Dim sourceWb As Workbook Dim sourceData As Range ‘设置源文件所在文件夹路径请修改为你的实际路径 sourcePath “C:\月度销售数据\” ‘设置目标工作表 Set destSheet ThisWorkbook.Worksheets(“总报告”) ‘找到目标表最后一行有数据的行号 lastRow destSheet.Cells(destSheet.Rows.Count, “A”).End(xlUp).Row 1 ‘获取文件夹下所有.xlsx文件排除.xlsm等 sourceFile Dir(sourcePath “*.xlsx”) Do While sourceFile “” ‘打开源工作簿 Set sourceWb Workbooks.Open(sourcePath sourceFile, ReadOnly:True) ‘假设每个部门文件的数据都在“Sheet1”的A2:D100区域需根据实际情况调整 Set sourceData sourceWb.Worksheets(“Sheet1”).Range(“A2:D100”) ‘将数据复制到总报告 sourceData.Copy Destination:destSheet.Cells(lastRow, 1) ‘更新总报告的最后一行位置 lastRow destSheet.Cells(destSheet.Rows.Count, “A”).End(xlUp).Row 1 ‘关闭源工作簿不保存 sourceWb.Close SaveChanges:False ‘获取下一个文件名 sourceFile Dir Loop MsgBox “所有部门数据合并完成”, vbInformation End Sub关键点解析Dir函数用于遍历文件夹下的文件。LastRow的计算Cells(Rows.Count, “A”).End(xlUp).Row是VBA中查找A列最后一个非空单元格行号的经典写法非常高效。ReadOnly:True以只读方式打开文件避免意外修改源数据。循环逻辑打开一个文件 - 复制数据 - 关闭文件 - 处理下一个内存占用小稳定。5.3 案例三制作交互式数据查询界面用户窗体场景你制作了一个庞大的产品信息表其他同事需要频繁查询。你不想让他们直接操作原始数据表希望提供一个简单的输入框输入产品编号就能显示出所有相关信息。思路使用VBA的“用户窗体”UserForm功能创建一个图形化界面。插入用户窗体在VBA编辑器中右键点击你的工程名 - 插入 - 用户窗体。设计窗体从工具箱中拖拽控件到窗体上。一个Label标签显示“请输入产品编号”。一个TextBox文本框让用户输入编号。一个CommandButton命令按钮显示“查询”。几个额外的Label用于显示查询结果如产品名称、价格、库存等。编写查询按钮的代码双击窗体上的“查询”按钮进入代码视图。Private Sub CommandButton1_Click() ‘“查询”按钮的点击事件 Dim productID As String Dim foundRow As Long Dim i As Long Dim lastRow As Long Dim ws As Worksheet Set ws ThisWorkbook.Worksheets(“产品库”) ‘假设数据在“产品库”工作表 productID Trim(TextBox1.Value) ‘获取用户输入并去除首尾空格 If productID “” Then MsgBox “请输入产品编号”, vbExclamation Exit Sub End If ‘在A列产品编号列中查找 lastRow ws.Cells(ws.Rows.Count, “A”).End(xlUp).Row foundRow 0 For i 2 To lastRow ‘假设第一行是表头 If ws.Cells(i, 1).Value productID Then foundRow i Exit For End If Next i If foundRow 0 Then ‘找到产品将对应信息显示在窗体的Label上 Label_产品名称.Caption ws.Cells(foundRow, 2).Value ‘假设名称在B列 Label_价格.Caption Format(ws.Cells(foundRow, 3).Value, “¥#,##0.00”) ‘假设价格在C列并格式化 Label_库存.Caption ws.Cells(foundRow, 4).Value ‘假设库存在D列 Else MsgBox “未找到产品编号” productID, vbCritical ‘清空显示 Label_产品名称.Caption “” Label_价格.Caption “” Label_库存.Caption “” End If End Sub运行窗体在工作表中插入一个按钮为其指定一个宏宏的内容就是UserForm1.Show。这样点击工作表按钮就会弹出你设计的查询窗口。这个案例将VBA从后台自动化推向了前台交互极大地提升了工具的易用性和专业性。6. 高级技巧与性能优化当你的宏越来越复杂处理的数据量越来越大时一些高级技巧和优化手段就变得至关重要。6.1 关闭屏幕更新与事件触发默认情况下VBA每执行一个操作如给单元格赋值、选择区域Excel都会更新一次屏幕并触发相应事件如Worksheet_Change。对于大批量操作这会导致程序运行极其缓慢。Sub 快速处理大数据() Application.ScreenUpdating False ‘关闭屏幕更新 Application.EnableEvents False ‘禁用事件 Application.Calculation xlCalculationManual ‘将计算模式改为手动 ‘…在这里执行你的大批量数据操作代码… Application.Calculation xlCalculationAutomatic ‘恢复自动计算 Application.EnableEvents True Application.ScreenUpdating True ‘最后再打开屏幕更新 End Sub重要提示务必在宏的结尾处恢复这些设置如果因为代码错误导致宏意外中断这些设置可能不会被恢复导致Excel表现异常。一个稳妥的做法是使用错误处理机制。6.2 使用数组替代直接操作单元格这是VBA性能优化中最有效的一招。频繁读写单元格Range.Value是主要的速度瓶颈。我们可以先将单元格区域的数据一次性读入一个内存中的数组Array在数组中进行高速计算或处理然后再将结果一次性写回单元格。Sub 使用数组加速() Dim dataArr As Variant ‘声明一个变体变量用于存放数组 Dim i As Long, j As Long Dim lastRow As Long, lastCol As Long Dim ws As Worksheet Set ws ThisWorkbook.Worksheets(“Sheet1”) ‘确定数据范围 lastRow ws.Cells(ws.Rows.Count, 1).End(xlUp).Row lastCol ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column ‘将整个数据区域一次性读入数组 dataArr ws.Range(ws.Cells(1, 1), ws.Cells(lastRow, lastCol)).Value ‘在数组中进行处理例如将所有数值乘以1.1 For i 2 To UBound(dataArr, 1) ‘从第2行开始跳过标题 For j 2 To UBound(dataArr, 2) ‘从第2列开始假设第1列是文本 If IsNumeric(dataArr(i, j)) Then dataArr(i, j) dataArr(i, j) * 1.1 End If Next j Next i ‘将处理后的数组一次性写回原区域 ws.Range(ws.Cells(1, 1), ws.Cells(lastRow, lastCol)).Value dataArr End Sub对于数万行数据的处理这种方法可以将运行时间从几分钟缩短到几秒钟。6.3 错误处理让宏更健壮再完美的代码也可能遇到意外文件不存在、除数为零、用户输入了错误格式的数据。没有错误处理的宏会直接崩溃给出不友好的提示。使用On Error语句可以捕获并优雅地处理错误。Sub 带有错误处理的宏() On Error GoTo ErrorHandler ‘当发生错误时跳转到ErrorHandler标签处 ‘…你的主要代码… Exit Sub ‘正常结束时跳过错误处理部分 ErrorHandler: ‘错误处理代码 Dim errMsg As String errMsg “错误号” Err.Number vbCrLf _ “错误描述” Err.Description vbCrLf _ “发生在” Err.Source MsgBox “程序运行出错” vbCrLf vbCrLf errMsg, vbCritical ‘恢复可能被关闭的屏幕更新等设置 Application.ScreenUpdating True Application.EnableEvents True End Sub7. 调试、封装与部署7.1 VBA调试技巧调试是编程中查找和修复错误的过程。VBA编辑器提供了强大的调试工具。断点在代码行的左侧灰色区域点击可以设置一个红点断点。当程序运行到这一行时会暂停此时你可以将鼠标悬停在变量上查看其当前值。逐语句执行F8按F8键代码会一行一行地执行方便你跟踪程序流程和变量变化。本地窗口在调试状态下打开“视图”-“本地窗口”可以查看当前过程中所有变量的值和类型。立即窗口CtrlG可以在这里直接输入VBA命令并立即执行常用于测试单行代码或查询对象属性。例如输入?Range(“A1”).Value并按回车会显示A1单元格的值。7.2 宏的保存与分发保存为启用宏的工作簿包含VBA代码的文件必须保存为.xlsm格式Excel启用宏的工作簿。如果保存为.xlsx所有代码都会丢失。个人宏工作簿如果你希望某个宏在所有Excel文件中都能使用可以在录制或创建宏时在“保存在”选项中选择“个人宏工作簿”。这是一个隐藏的、随Excel启动自动加载的工作簿通常是PERSONAL.XLSB非常适合存放通用工具函数。数字签名如果你需要将带宏的文件分发给同事而他们的宏安全级别设置较高可以为你的VBA项目添加数字签名。这需要先获得一个数字证书可以在Windows中创建自签名证书然后在VBA编辑器中“工具”-“数字签名”进行设置。这样用户首次打开时会提示发布者选择信任后以后打开就不会再警告。7.3 制作自定义功能区按钮或快速访问工具栏按钮让宏更容易被调用可以将其添加到Excel的界面上。快速访问工具栏点击快速访问工具栏下拉箭头 - “其他命令” - 在“从下列位置选择命令”中选择“宏”找到你的宏点击“添加” - 确定。之后点击这个按钮即可运行宏。自定义功能区更高级通过编辑Excel的配置文件.officeUI文件或使用VBA代码可以创建自定义的功能区选项卡和按钮组。这需要更深入的学习但能让你的工具看起来像Excel原生功能一样专业。8. 常见问题与排查实录在实际使用宏的过程中你一定会遇到各种各样的问题。这里记录了一些最常见的问题和解决方法。问题现象可能原因排查与解决思路运行宏时提示“编译错误变量未定义”1. 使用了未声明的变量。2. 对象库引用丢失。1. 检查代码中所有变量是否都用Dim声明过或者是否拼写错误。2. 在VBA编辑器中点击“工具”-“引用”检查是否有丢失的引用前面有“丢失”字样取消勾选或重新定位正确文件。宏运行后Excel卡死或无响应1. 代码陷入死循环。2. 处理数据量过大未关闭屏幕更新。3. 代码逻辑错误导致资源未释放。1. 按CtrlBreak尝试中断检查循环条件是否永远为真。2. 在宏开头加入Application.ScreenUpdating False。3. 使用错误处理确保ScreenUpdating等设置被恢复。对于大量对象操作记得将对象变量设为Nothing如Set myRange Nothing。录制的宏在别的文件上运行报错录制宏使用了绝对引用如Worksheets(“Sheet1”).Select而新文件没有同名工作表或结构不同。修改代码使用相对引用或更通用的方法。例如用ActiveSheet代替Worksheets(“Sheet1”)用Selection或ActiveCell的偏移Offset属性来定位。自定义函数在工作表中不计算或显示#NAME?错误1. 函数代码所在的工作簿未打开。2. 函数放在了标准模块Module中吗3. 函数名拼写错误。1. 确保包含函数的.xlsm文件是打开的。2. 自定义函数必须放在标准模块中不能放在工作表或ThisWorkbook的代码窗口中。3. 检查工作表公式中的函数名是否与VBA中的Function名完全一致。打开文件时提示“已禁用宏”Excel的宏安全设置阻止了宏的运行。点击提示栏上的“启用内容”。如果是自己长期使用的文件可以将其所在文件夹添加到“受信任位置”文件-选项-信任中心-信任中心设置-受信任位置。代码在别人的电脑上无法运行1. 引用了对方电脑上没有的库或对象。2. 使用了对方区域设置不支持的日期/数字格式。3. 文件路径不同。1. 尽量使用Excel最通用的对象和方法。如果必须引用外部库考虑动态绑定或提供安装指引。2. 在代码中处理日期和数字时使用CDate,CDbl等转换函数避免直接使用区域特定的格式字符串。3. 使用ThisWorkbook.Path获取当前文件路径来构建相对路径避免硬编码绝对路径如C:\...。最后分享一个我用了很多年的习惯在编写任何重要的宏之前先手动备份原始数据文件。无论你的代码测试了多少遍在正式对生产数据运行前做一个备份总是最保险的。自动化是为了提高效率和准确性而备份是这份信心最坚实的后盾。当你看着自己编写的宏将繁杂的工作瞬间完成时那种成就感和解放出来的时间会让你觉得所有的学习投入都是值得的。