Excel VBA自动化入门:从零到一构建高效数据处理工具 1. 从“表格操作工”到“效率工程师”为什么你需要VBA如果你每天的工作都离不开Excel那你一定经历过这样的场景面对几十个格式混乱的报表手动复制粘贴、调整格式一坐就是大半天每周都要重复制作结构相同的分析图表步骤繁琐且容易出错或者你需要从十几个分散的Excel文件中汇总数据光是打开、复制、关闭文件就足以让人崩溃。你可能会用一些函数比如VLOOKUP、SUMIFS甚至知道数据透视表但这些工具在面对复杂、重复、需要逻辑判断的任务时依然显得力不从心。你感觉自己像个高级的“表格操作工”时间被大量重复劳动吞噬创造力和分析能力无处施展。这时VBA就该登场了。VBA全称Visual Basic for Applications是内置于Microsoft Office包括Excel、Word、PPT等中的一种编程语言。你可以把它理解为给Excel安装了一个“智能机器人”。这个机器人能看懂你写的指令代码然后不知疲倦、精准无误地替你完成所有重复性操作。学习VBA不是为了成为专业的程序员而是为了让你从一个被表格“使唤”的操作者转变为一个能“使唤”表格的效率工程师。它能将你数小时甚至数天的工作压缩到一次点击、几秒钟之内完成。更重要的是它让你掌握了一种将复杂业务流程“固化”为标准化工具的能力这是职场中极具价值的核心竞争力。从网络上的热门搜索词就能看出大家的普遍痛点批量处理、数据导入导出、自动化报表、复杂筛选、甚至是与数据库如MSSQL或其他软件如CATIA, WinCC交互。这些恰恰是VBA最擅长的领域。接下来我将从一个多年使用者的角度带你绕过枯燥的理论直接切入最实用的核心手把手构建你的第一个自动化工具并拆解几个能立刻用起来的经典案例。2. 零基础搭建你的VBA开发环境与第一个宏很多教程一上来就讲变量、循环、条件判断这很容易把初学者吓跑。我们换个顺序先让代码“动起来”看到效果再回头理解原理。第一步是找到并熟悉你的“工作台”。2.1 让开发者选项卡现身并认识VBE默认情况下Excel的菜单栏里是没有VBA相关功能的。你需要先把它调出来。打开Excel点击“文件”-“选项”。在弹出的“Excel选项”对话框中选择“自定义功能区”。在右侧“主选项卡”列表中找到并勾选“开发工具”然后点击“确定”。现在你的Excel顶部菜单栏就会出现“开发工具”选项卡。这里面最重要的两个按钮是“Visual Basic”打开VBA编辑器和“录制宏”。我们重点看编辑器。点击“Visual Basic”按钮或直接按快捷键Alt F11就会打开一个全新的窗口——VBA集成开发环境VBE。别被它吓到我们只关注几个核心部分菜单栏和工具栏和Excel类似用于执行各种命令。工程资源管理器快捷键 Ctrl R通常位于左上角。这里以树形结构展示所有打开的工作簿VBAProject及其包含的对象如工作表Sheet1, Sheet2...、当前工作簿ThisWorkbook和模块Modules。你可以把它理解为你的“项目文件管理器”。属性窗口快捷键 F4通常位于左下角。当你选中工程资源管理器里的某个对象比如一个工作表Sheet1时这里会显示该对象的属性如名称Name、是否可见Visible等你可以在这里修改。代码窗口中间最大的区域。这是你编写和查看代码的地方。每个对象工作表、工作簿、模块都有自己独立的代码窗口。提示如果工程资源管理器或属性窗口不见了可以在VBE的菜单栏“视图”中找到并重新打开它们。2.2 使用“录制宏”功能让Excel教你写代码对于初学者最好的老师就是Excel自己。“录制宏”功能可以把你所有的鼠标和键盘操作记录下来并自动翻译成VBA代码。这是理解VBA语法和对象模型最直观的方式。我们来录制一个简单的宏将A1单元格设置为加粗、红色字体并填入“Hello VBA”。在Excel中选中一个空白的单元格比如A1。点击“开发工具”选项卡下的“录制宏”。给宏起个名字比如MyFirstMacro可以设置一个快捷键如CtrlShiftH点击“确定”。此时你的所有操作都会被记录。进行操作将A1单元格的字体加粗点击“B”图标字体颜色设为红色然后输入“Hello VBA”。操作完成后点击“开发工具”选项卡下的“停止录制”。现在我们来查看生成的代码按Alt F11回到VBE。在工程资源管理器中双击“模块”文件夹下的“模块1”如果看不到在VBE菜单栏点击“插入”-“模块”。在代码窗口中你会看到类似下面的代码Sub MyFirstMacro() MyFirstMacro Macro 快捷键: CtrlShiftH Range(A1).Select Selection.Font.Bold True With Selection.Font .Color -16776961 End With ActiveCell.FormulaR1C1 Hello VBA End Sub我们来解读一下这段“机器人生成的日记”Sub MyFirstMacro() ... End Sub 定义了一个名为MyFirstMacro的宏过程。Sub是子程序的开始End Sub是结束。Range(A1).Select 选中A1单元格。Range是VBA中最核心的对象之一代表一个或一组单元格。Selection.Font.Bold True 将当前选中对象即A1的字体加粗属性设置为“真”True。With ... End With 这是一个简化代码的结构。With Selection.Font意思是“对于当前选中对象的字体属性”然后接下来的.Color -16776961就是在设置其颜色。-16776961是红色的内部颜色代码。ActiveCell.FormulaR1C1 Hello VBA 在当前活动单元格A1中输入“Hello VBA”。你可以直接运行它来验证效果在代码窗口中将光标放在Sub MyFirstMacro()这一行的任何位置然后按F5键或者点击工具栏上的绿色三角“运行”按钮。你会发现即使A1单元格原本有内容也会被清空并重新设置为加粗红色的“Hello VBA”。注意录制宏生成的代码通常不是最优的它记录了每一步“选择”Select操作这在VBA中通常是低效的。我们写代码时应尽量避免频繁的.Select和.Selection而是直接操作对象。例如上面代码可以优化为Sub MyFirstMacro_Optimized() With Range(A1) .Font.Bold True .Font.Color vbRed 使用内置常量vbRed比数字代码更易读 .Value Hello VBA End With End Sub但作为入门录制宏是无可替代的“拐杖”它能帮你快速理解对象、属性和方法之间的关系。3. VBA核心三板斧变量、循环与条件判断看懂了录制的代码我们就可以开始学习自己“造句”了。任何VBA程序都离不开三个最核心的概念变量、循环和条件判断。掌握了它们你就掌握了VBA编程的骨架。3.1 变量数据的临时储物格变量顾名思义就是可以改变的量。它是内存中一个命名的存储位置用来保存程序运行时的数据。你可以把它想象成一个个贴了标签的盒子用来临时存放数字、文字、日期等信息。在VBA中使用变量前最好先声明它这就像告诉Excel“我要准备一个什么样的盒子来装东西”。声明变量的语句是Dim。Dim myName As String 声明一个名为myName的变量类型是String文本 Dim myAge As Integer 声明一个名为myAge的变量类型是Integer整数 Dim totalSalary As Double 声明一个名为totalSalary的变量类型是Double双精度浮点数可带小数 Dim isFinished As Boolean 声明一个名为isFinished的变量类型是Boolean布尔值只有True或False声明之后就可以给变量赋值了myName 张三 myAge 30 totalSalary 8500.5 isFinished False变量可以参与计算也可以赋值给单元格Dim bonus As Double bonus totalSalary * 0.1 计算奖金 Range(B1).Value 员工 myName 奖金 bonus 符号用于连接文本实操心得养成“先声明后使用”的习惯。你可以在模块的最顶部加上Option Explicit语句这样VBA会强制你声明所有变量能有效避免因拼写错误导致的诡异bug比如把totalSalary错写成totalSalryVBA会把它当做一个新的变量其值为0导致计算结果错误。3.2 循环让重复劳动自动化循环是自动化的灵魂。想象一下你要把A列从第1行到第100行的数据都加粗。手动操作要100次用循环只需要几行代码。For...Next 循环当你明确知道要重复多少次时使用。Sub BoldFirst100Rows() Dim i As Integer i 常作为循环计数器 For i 1 To 100 Cells(i, 1).Font.Bold True Cells(行号, 列号) Cells(1,1)即A1 Next i End Sub这段代码让i从1变到100每次循环都对第i行、第1列即A列的单元格进行加粗操作。For Each...Next 循环当你需要对一个集合比如某个区域的所有单元格中的每个元素进行操作时使用更简洁。Sub BoldColumnA() Dim cell As Range 声明一个代表单元格的变量 For Each cell In Range(A1:A100) 遍历A1到A100这个区域的每一个单元格 cell.Font.Bold True Next cell End SubDo While/Loop 循环当你不确定要循环多少次只知道在某个条件满足时一直循环适合处理不确定行数的数据。Sub BoldUntilEmpty() Dim rowNum As Integer rowNum 1 Do While Cells(rowNum, 1).Value 当A列当前行的单元格不为空时继续循环 Cells(rowNum, 1).Font.Bold True rowNum rowNum 1 行号加1准备处理下一行 Loop End Sub3.3 条件判断让代码拥有“智能”程序不能只会蛮干还需要根据情况做出选择。这就需要条件判断语句If...Then...Else。Sub BonusCalculator() Dim sales As Double Dim bonus As Double sales Range(C2).Value 假设C2单元格是销售额 If sales 10000 Then bonus sales * 0.15 销售额大于等于10000奖金比例15% ElseIf sales 5000 Then bonus sales * 0.1 销售额在5000到9999之间奖金比例10% Else bonus sales * 0.05 销售额低于5000奖金比例5% End If Range(D2).Value bonus 将计算结果写入D2单元格 End Sub你还可以结合循环对一整列数据进行判断和计算这就是自动化处理的核心逻辑。4. 实战案例一一键批量处理多工作表数据现在我们把前三板斧结合起来解决一个真实的高频需求你有一个工作簿里面有12个月份的销售数据表Sheet1到Sheet12结构完全相同。现在需要快速汇总每个月的“销售总额”假设在每张表的F列并填写到一个名为“汇总”的工作表的对应月份行中。这个需求涉及了跨工作表操作、循环遍历、单元格数据读取与写入。我们一步步来构建这个宏。4.1 需求分析与代码结构规划目标将12个月份表假设名称为“1月”、“2月”...“12月”中F列的数据假设是销售总额提取出来。目的地填写到“汇总”工作表中假设“汇总”表的A列是月份名B列需要填写销售额。逻辑循环遍历每一个月份工作表名称 - 找到该工作表 - 读取其F列的数据假设数据在F2单元格- 写入“汇总”表对应的行。4.2 代码实现与逐行解读首先确保你有一个名为“汇总”的工作表并且在里面准备好了A列月份名称。然后插入一个模块写入以下代码Sub SummarizeMonthlySales() 声明变量 Dim summarySheet As Worksheet 用于代表“汇总”工作表对象 Dim monthSheet As Worksheet 用于循环中代表每个月份工作表对象 Dim monthName As String 用于存储月份名称 Dim salesValue As Double 用于存储从月份表读取的销售额 Dim i As Integer 循环计数器 Dim targetRow As Integer 用于定位“汇总”表中的目标行 设置“汇总”表对象增加错误处理防止没有该工作表时程序崩溃 On Error Resume Next 如果发生错误继续执行下一句 Set summarySheet ThisWorkbook.Worksheets(汇总) On Error GoTo 0 关闭错误处理 If summarySheet Is Nothing Then MsgBox 未找到名为‘汇总’的工作表, vbCritical Exit Sub 如果没有找到弹出提示并退出宏 End If 假设月份表名称就是“1月”、“2月”...“12月” For i 1 To 12 monthName i 月 拼接月份名称如“1月” 尝试获取对应月份的工作表对象 On Error Resume Next Set monthSheet ThisWorkbook.Worksheets(monthName) On Error GoTo 0 如果成功获取到月份表 If Not monthSheet Is Nothing Then 假设每个月份表的销售额在F2单元格 salesValue monthSheet.Range(F2).Value 在“汇总”表中查找月份名称所在的行 targetRow 0 初始化目标行号 On Error Resume Next 使用Find方法查找月份名比循环遍历更高效 targetRow summarySheet.Columns(A:A).Find(What:monthName, LookIn:xlValues, LookAt:xlWhole).Row On Error GoTo 0 If targetRow 0 Then 如果找到了将销售额写入该行的B列 summarySheet.Cells(targetRow, 2).Value salesValue Else 如果没找到在下一行添加 Dim lastRow As Integer lastRow summarySheet.Cells(summarySheet.Rows.Count, 1).End(xlUp).Row 找到A列最后一行 summarySheet.Cells(lastRow 1, 1).Value monthName summarySheet.Cells(lastRow 1, 2).Value salesValue End If 释放对象变量为下一次循环准备虽然不是必须但是好习惯 Set monthSheet Nothing Else 如果没找到这个月份表可以记录日志或忽略 Debug.Print 未找到工作表: monthName 在立即窗口打印信息按CtrlG可打开 End If Next i 完成提示 MsgBox 月度销售数据汇总完成, vbInformation End Sub4.3 代码中的关键技巧与避坑点错误处理On Error Resume Next 这是VBA中非常重要的技巧。当我们尝试去获取一个可能不存在的工作表Worksheets(“某月”)时如果它真的不存在VBA默认会报错并停止运行。On Error Resume Next告诉VBA“如果下一句代码出错别停直接跳过去执行再下一句”。然后我们用If monthSheet Is Nothing Then来判断是否获取成功。处理完后用On Error GoTo 0关闭这个“错误忽略”模式避免掩盖其他真正的错误。查找目标行Find方法 在“汇总”表中定位月份所在行我们使用了Find方法。这比用For循环从第一行遍历到最后一行要高效得多尤其是在数据量大的时候。LookAt:xlWhole表示完全匹配防止“1月”匹配到“11月”。查找最后一行summarySheet.Cells(summarySheet.Rows.Count, 1).End(xlUp).Row这是一个经典用法。Rows.Count返回工作表的总行数在较新版本Excel中是1048576。.End(xlUp)模拟了在Excel中按Ctrl ↑的效果从最后一行向上跳直到遇到第一个非空单元格。.Row则返回这个单元格的行号。这样就动态地找到了A列已有数据的最后一行。立即窗口Debug.Print 在调试代码时Debug.Print可以将信息输出到立即窗口VBE中按CtrlG调出这比用MsgBox弹窗更利于观察程序运行过程且不会中断流程。运行这个宏你就能瞬间完成12张表的数据抓取与汇总。你可以根据实际表格结构轻松修改代码中的列号如F2和查找逻辑来适配你自己的任务。5. 实战案例二智能数据清洗与格式标准化数据清洗是数据分析前的噩梦。常见问题包括多余的空格、不规范日期、数字存储为文本、合并单元格等。手动处理费时费力。我们用VBA构建一个“一键清洗”工具处理以下典型问题去除所有单元格首尾空格。将“YYYY.MM.DD”或“YYYY/MM/DD”等格式的文本统一转换为Excel标准日期格式。将存储为文本的数字转换为真正的数字。取消所有合并单元格并填充空白值。5.1 设计一个用户友好的交互界面我们可以创建一个简单的按钮让用户选择要清洗的数据区域然后执行清洗。这比硬编码区域更灵活。首先在“开发工具”选项卡下点击“插入”-“按钮窗体控件”在工作表上画一个按钮。在弹出的“指定宏”对话框中点击“新建”VBA会自动创建一个关联到该按钮的宏。我们将其命名为CleanData。5.2 分步实现清洗功能Sub CleanData() Dim rngToClean As Range Dim cell As Range Dim lastRow As Long, lastCol As Long Dim ws As Worksheet 1. 让用户选择要清洗的区域 On Error Resume Next Set rngToClean Application.InputBox( _ Prompt:请选择需要清洗的数据区域例如A1:D100:, _ Title:数据清洗工具, _ Type:8) Type:8 表示要求输入一个单元格区域引用 On Error GoTo 0 如果用户取消了选择则退出 If rngToClean Is Nothing Then MsgBox 操作已取消。, vbInformation Exit Sub End If Application.ScreenUpdating False 关闭屏幕刷新大幅提升代码运行速度 Application.Calculation xlCalculationManual 暂停公式计算 2. 遍历选中区域的每一个单元格 For Each cell In rngToClean 2.1 去除首尾空格 If VarType(cell.Value) vbString Then 先判断是否是文本类型 cell.Value Trim(cell.Value) End If 2.2 尝试将文本转换为日期 (处理常见的点或斜杠分隔) If IsDate(cell.Value) Then cell.Value CDate(cell.Value) cell.NumberFormat yyyy-mm-dd 统一设置为一种日期格式 End If 2.3 尝试将文本数字转换为数值 If VarType(cell.Value) vbString Then If IsNumeric(cell.Value) Then cell.Value CDbl(cell.Value) 转换为双精度数字 cell.NumberFormat 0.00 可设置为需要的数字格式 End If End If Next cell 3. 处理合并单元格这是一个单独的操作需要遍历区域内的合并区域 Dim mergedArea As Range For Each mergedArea In rngToClean.MergeAreas mergedArea.UnMerge 取消合并 取消合并后只有左上角单元格有值其他为空。这里可以选择填充例如用左上角的值填充整个区域 If mergedArea.Cells.Count 1 Then mergedArea.Value mergedArea.Cells(1, 1).Value End If Next mergedArea 4. 可选自动调整列宽 rngToClean.Columns.AutoFit Application.Calculation xlCalculationAutomatic 恢复公式计算 Application.ScreenUpdating True 恢复屏幕刷新 MsgBox 数据清洗完成, vbInformation End Sub5.3 代码精讲与潜在问题处理Application.InputBox 我们使用Type:8的参数这会弹出一个对话框允许用户用鼠标拖选区域非常方便。On Error Resume Next用于处理用户点击“取消”的情况。性能优化Application.ScreenUpdating False和Application.Calculation xlCalculationManual是VBA编程中极其重要的两个语句。它们能阻止Excel在代码执行过程中不断刷新界面和重新计算公式对于处理大量单元格时速度提升是数量级的从几分钟缩短到几秒。务必记得在操作结束后将其设回True和xlCalculationAutomatic。数据类型判断 使用VarType()和IsNumeric()、IsDate()函数来判断单元格内容的类型避免对非文本内容进行Trim操作或对非数字文本进行转换导致错误。合并单元格处理MergeAreas是区域Range的一个属性它返回该区域内所有独立的合并区域集合。我们遍历这个集合并对每个合并区域执行UnMerge。取消合并后通常需要将值填充到所有单元格这里我们简单地将整个区域的值都设为原左上角单元格的值。注意这个操作会改变数据结构请确保你了解其影响。错误处理的局限性 上述代码中的日期和数字转换逻辑是“尝试性”的。对于格式非常混乱的日期如“2023年5月1日”IsDate可能无法识别。对于更复杂的清洗规则如去除不可见字符、统一电话号格式等你需要编写更精细的判断和替换逻辑可能用到Replace、InStr、RegExp正则表达式等函数。这个“一键清洗”宏已经能解决80%的常见数据规整问题。你可以将它保存到个人宏工作簿Personal.xlsb这样在所有Excel文件中都可以使用。6. 实战案例三制作动态交互式查询工具很多人在搜索“excel 查询程序”、“excel多条件筛选”。Excel自带的筛选和高级筛选功能强大但每次都要手动设置条件不够直观和自动化。我们可以用VBA结合窗体控件制作一个类似简易查询系统的界面实现动态多条件筛选。目标创建一个面板用户可以通过下拉列表、文本框输入多个条件点击按钮后自动在数据表中筛选出符合所有条件的记录并将结果输出到指定位置。6.1 构建用户窗体UserForm作为查询界面VBA不仅可以操作工作表还能创建独立的对话框窗口这就是用户窗体UserForm。在VBE中右键点击你的工程VBAProject选择“插入”-“用户窗体”。在工具箱中拖拽以下控件到窗体上Label标签用于显示文字如“部门”、“姓名”。ComboBox组合框/下拉列表用于让用户从预置列表中选择如部门列表。TextBox文本框用于让用户输入文本如姓名关键字。CommandButton命令按钮如“查询”和“清空”按钮。调整控件布局和属性按F4打开属性窗口修改它们的名称如cboDepartment、txtName、btnQuery和Caption显示的文字。6.2 编写窗体与工作表交互的代码假设我们有一个名为“数据源”的工作表A到D列分别是“部门”、“姓名”、“销售额”、“日期”。我们要实现按部门和姓名模糊匹配查询。第一步初始化窗体加载部门列表。双击用户窗体非控件的空白处进入窗体的代码视图在UserForm_Initialize事件中编写代码。这个事件在窗体加载时自动运行。Private Sub UserForm_Initialize() 清空现有列表 cboDepartment.Clear 从“数据源”工作表的A列获取不重复的部门列表假设标题在A1 Dim ws As Worksheet Dim lastRow As Long Dim dict As Object 使用字典对象去重 Dim cell As Range Dim dept As Variant Set ws ThisWorkbook.Worksheets(数据源) lastRow ws.Cells(ws.Rows.Count, 1).End(xlUp).Row Set dict CreateObject(Scripting.Dictionary) 创建字典对象 For Each cell In ws.Range(A2:A lastRow) 从A2开始跳过标题 If Not dict.Exists(cell.Value) And cell.Value Then dict.Add cell.Value, cell.Value End If Next cell 将去重后的部门添加到下拉列表 cboDepartment.AddItem (全部) 增加一个“全部”选项 For Each dept In dict.Keys cboDepartment.AddItem dept Next dept cboDepartment.ListIndex 0 默认选中第一项“(全部)” 清空文本框 txtName.Value End Sub第二步为“查询”按钮编写代码。双击窗体上的“查询”按钮进入其Click事件。Private Sub btnQuery_Click() Dim wsSource As Worksheet, wsResult As Worksheet Dim lastRow As Long, lastCol As Long Dim i As Long, outputRow As Long Dim criteriaDept As String, criteriaName As String Dim match As Boolean 设置工作表对象 Set wsSource ThisWorkbook.Worksheets(数据源) Set wsResult ThisWorkbook.Worksheets(查询结果) 假设有一个“查询结果”表存放结果 获取查询条件 criteriaDept cboDepartment.Value criteriaName Trim(txtName.Value) 去除姓名条件两端的空格 清空“查询结果”表中原有的数据假设第一行是标题 wsResult.Cells.ClearContents 可以在这里复制标题行 wsSource.Rows(1).Copy Destination:wsResult.Rows(1) 获取数据源的最后一行和最后一列 lastRow wsSource.Cells(wsSource.Rows.Count, 1).End(xlUp).Row lastCol wsSource.Cells(1, wsSource.Columns.Count).End(xlToLeft).Column outputRow 2 从第二行开始输出结果 Application.ScreenUpdating False 遍历数据源每一行从第2行开始 For i 2 To lastRow match True 先假设该行匹配 条件1部门匹配 (如果未选“全部”) If criteriaDept (全部) And criteriaDept Then If wsSource.Cells(i, 1).Value criteriaDept Then match False End If End If 条件2姓名模糊匹配 (如果姓名条件不为空) If match And criteriaName Then If InStr(1, wsSource.Cells(i, 2).Value, criteriaName, vbTextCompare) 0 Then InStr函数返回子字符串的位置0表示没找到。vbTextCompare表示不区分大小写。 match False End If End If 如果所有条件都满足则复制该行到结果表 If match Then wsSource.Rows(i).Copy Destination:wsResult.Rows(outputRow) outputRow outputRow 1 End If Next i Application.ScreenUpdating True If outputRow 2 Then MsgBox 未找到匹配的记录。, vbInformation Else MsgBox 查询完成共找到 (outputRow - 2) 条记录。, vbInformation End If 自动调整结果表的列宽 wsResult.Columns.AutoFit End Sub第三步为“清空”按钮编写代码。Private Sub btnClear_Click() 重置查询条件 cboDepartment.ListIndex 0 txtName.Value End Sub6.3 运行与优化你的查询工具最后在工作表上插入一个按钮比如在“数据源”工作表为其指定一个宏这个宏只有一行代码UserForm1.Show假设你的窗体名是UserForm1。点击这个按钮你的自定义查询界面就会弹出。这个案例综合运用了用户窗体、控件事件、字典对象去重、循环判断、字符串模糊匹配InStr等知识。你可以在此基础上无限扩展增加更多条件如日期范围使用两个DTPicker日期控件、数值区间等。使用真正的筛选器对于超大数据量上述遍历方法可能较慢。可以考虑使用AdvancedFilter高级筛选方法将窗体上的条件动态写入工作表的某个区域然后执行高级筛选。美化界面调整控件字体、颜色、布局。结果导出在“查询”按钮代码中增加将结果导出为新工作簿的功能。通过这三个从易到难的实战案例你已经走过了从录制宏到自主开发功能模块的完整路径。VBA的学习关键在于“用”在解决实际问题的过程中你会不断遇到新的需求然后去搜索、尝试、调试能力自然就成长起来了。记住最好的学习资料就是Excel自带的录制宏功能和网络社区但需注意甄别信息。当你发现自己开始不耐烦于任何重复的鼠标点击时就是你该写一段VBA代码的时候了。