⚡ VBA 从零到精通

专门为你准备的 VBA 教程 · 从录制第一个宏到自己写代码 · 带模拟代码块和实战

📹 录制宏 📝 基础语法 🎯 Range/Cells 🔔 事件编程 🚀 实战案例 🐛 调试技巧
🎯 学习路线:
① 先看 认识VBA 搞懂概念 → ② 录一个宏感受一下 → ③ 学基础语法(变量+条件+循环)→ ④ 学对象操作 → ⑤ 事件编程 → ⑥ 跟着实战写代码 → ⑦ 学调试技巧

第一章 · 认识 VBA

入门
🤔 VBA 是什么?

VBA(Visual Basic for Applications)是 Excel 内置的编程语言。你可以把它理解为——
「让你能写代码控制 Excel 做任何事」的工具。

📹 宏 = 录下来的操作

你把"设置字体颜色、加粗、加边框"做一遍,Excel 录下来,以后一键重放。

📝 VBA = 宏背后的代码

录完宏后按 Alt+F11 就能看到自动生成的 VBA 代码,你也可以自己改。

🎯 为什么学 VBA?

重复工作自动化(合并报表、批量处理)、创造 Excel 没有的功能、跟数据库/邮件等外部程序交互。

⚡ 难吗?

基础操作很简单——录制宏→改改代码就能用。不需要编程基础,跟着学就行。

🔑 开启开发工具
1
打开 Excel文件选项
2
自定义功能区 → 右侧勾选 「开发工具」 → 确定
3
菜单栏出现「开发工具」选项卡,里面有 Visual Basic录制宏 按钮
✅ 搞定了!现在按 Alt + F11 打开 VBA 编辑器看看——以后写代码都在这里。
🔑 VBA 编辑器界面
1
工程资源管理器(左上):显示所有工作簿、工作表、模块,像文件夹树
2
代码窗口(右边大片区域):写代码的地方
3
属性窗口(左下):查看/修改选中对象的属性
4
立即窗口(下方,按 Ctrl+G 打开):临时测试代码用的,超好用!
💡 立即窗口小技巧:在里面输入 ?Range(\"A1\").Value 然后回车,立刻显示A1的值——不用写完整代码就能测试。

第二章 · 录制第一个宏

入门
🎯 目标:录制一个宏,把选中的单元格设为「黄底 + 粗体 + 红色字体」
1
在 A1 随便输点文字 → 选中 A1
2
开发工具录制宏 → 宏名输入 "设置标题样式"
3
快捷键设 Ctrl+Shift+H → 确定 → 开始录制
4
把 A1 设为:黄底粗体红色字体停止录制
5
选中别的单元格 → Alt+F8 → 选"设置标题样式" → 执行 ✅ 自动变样式了!
🎉 成功了!你的第一个宏诞生了。现在按 Alt+F11 看看它生成了什么代码。
📄 看看 Excel 自动生成的代码
' 按 Alt+F11 → 双击"模块1"→ 你会看到: Sub 设置标题样式() ' 设置标题样式 Macro ' 快捷键: Ctrl+Shift+H With Selection.Interior .Pattern = 1 ' xlSolid .Color = 65535 ' 黄色 End With Selection.Font.Bold = True ' 加粗 Selection.Font.Color = 255 ' 红色 End Sub
💡 代码解释:
Sub ... End Sub — 一段宏(过程)的开头和结尾
Selection — 当前选中的单元格
.Interior.Color — 单元格背景颜色
.Font.Bold — 字体粗体
' 绿色文字 — 注释,不参与运行,写给看的
✏️ 动手试试

题目:录一个宏,把选中单元格设为"蓝色底 + 白色字体 + 居中"。然后看看生成的代码。

第三章 · 基础语法

进阶
📌 变量 — 给数据起个名字
🎯 场景:你要把 A1 的值取出来,加 10,然后写回 A2。
用变量存中间结果,代码更清晰。
Sub 变量示例() Dim 销售额 As Integer ' 声明一个整数变量 Dim 税率 As Double ' 声明一个小数变量 Dim 姓名 As String ' 声明一个文本变量 销售额 = Range("A1").Value ' 从A1读值 税率 = 0.13 姓名 = "张三" Range("A2").Value = 销售额 * (1 + 税率) ' 写入结果 Range("B1").Value = 姓名 End Sub
AB
1100张三
2113
💡 变量类型速查:
Integer 整数(-32768~32767) | Long 大整数 | Double 小数
String 文本 | Boolean True/False | Date 日期
如果不确定类型,直接用 Dim x As Variant(万能类型,但慢一点)
📌 If 条件判断 — 让代码做决策
Sub 判断成绩() Dim 分数 As Integer 分数 = Range("A1").Value If 分数 >= 90 Then Range("B1").Value = "优秀" ElseIf 分数 >= 60 Then Range("B1").Value = "及格" Else Range("B1").Value = "不及格" End If End Sub
AB(运行后)
185及格
295优秀
📌 For 循环 — 重复做N次
🎯 场景:把 A1 到 A10 填上 1 到 10。
Sub 填入数字() Dim i As Integer For i = 1 To 10 Cells(i, 1).Value = i ' 第i行第1列 = i Next i End Sub
A
11
22
1010
📌 For Each 循环 — 遍历一堆东西
🎯 场景:遍历当前工作簿的所有工作表,在每个表名前面加个"【2026】"。
Sub 重命名所有工作表() Dim ws As Worksheet For Each ws In Worksheets ws.Name = "【2026】" & ws.Name Next ws End Sub
✅ 运行前:Sheet1, Sheet2, Sheet3 → 运行后:【2026】Sheet1, 【2026】Sheet2, 【2026】Sheet3
📌 Do While 循环 — 直到条件满足才停
Sub 找到空单元格() Dim 行号 As Integer 行号 = 1 Do While Cells(行号, 1).Value <> "" 行号 = 行号 + 1 ' 向下走一行 Loop Cells(行号, 1).Value = "这是第一个空行" MsgBox "第一个空行在第 " & 行号 & " 行" End Sub
💡 常用循环总结:
For i = 1 To 100 → 知道要循环多少次
For Each x In 集合 → 遍历所有对象
Do While 条件 → 不知道多少次,条件满足就停
✏️ 动手试试

题目:写一段 VBA,把 B1 到 B10 分别填上 10、20、30……100。

第四章 · 常用对象操作

进阶
🤔 什么是对象?

Excel VBA 里一切都是对象——单元格是对象、工作表是对象、工作簿也是对象
你可以对对象做两件事:读/写属性(如 .Value, .Name)和 调用方法(如 .Copy, .Delete)。

📌 Range vs Cells — 两种写单元格的方式
' Range:用地址引用 Range("A1").Value = "Hi" Range("A1:B5").Font.Bold = True Range("A1", "C10").Copy
' Cells:用行号+列号 Cells(1, 1).Value = "Hi" ' 第1行第1列 Cells(i, 2).Value = i ' 循环里超好用
📌 常用操作速查
操作VBA 代码说明
读写单元格Range("A1").Value = 100写值
读取单元格x = Range("A1").Value读值到变量
合并单元格Range("A1:C1").Merge合并A1到C1
取消合并Range("A1:C1").UnMerge拆分
设置字体颜色Range("A1").Font.Color = RGB(255,0,0)红色
设置底色Range("A1").Interior.Color = 65535黄色
加边框Range("A1").Borders.LineStyle = xlContinuous实线边框
复制Range("A1").Copy Range("B1")复制粘贴
删除行Rows(3).Delete删除第3行
插入行Rows(3).Insert在第3行上方插入
删除列Columns("C").Delete删除C列
选中Range("A1").Select选中
清空内容Range("A1:A10").ClearContents只清值,保留格式
清空全部Range("A1:A10").Clear清值和格式
找最后一行Cells(Rows.Count, 1).End(xlUp).RowA列最后有数据的行号
📌 工作表操作
' 添加/删除工作表 Worksheets.Add ' 新增 Worksheets("Sheet1").Delete ' 删除 ' 重命名 Worksheets("Sheet1").Name = "1月数据" ' 遍历所有sheet Dim ws As Worksheet For Each ws In Worksheets ws.Range("A1").Value = "已处理" Next ws
' 复制/移动工作表 Worksheets("Sheet1").Copy After:=Worksheets(Sheets.Count) ' 判断工作表是否存在 Dim 存在 As Boolean On Error Resume Next Set ws = Worksheets("1月数据") 存在 = (Not ws Is Nothing) On Error GoTo 0
📌 工作簿操作
' 打开另一个Excel文件 Workbooks.Open "C:\数据\1月.xlsx" ' 保存当前文件 ThisWorkbook.Save ' 另存为 ThisWorkbook.SaveAs "C:\备份\备份.xlsm" ' 关闭(不保存) ActiveWorkbook.Close SaveChanges:=False
✏️ 动手试试

题目:写代码把 Sheet1 的 A1 到 D10 区域设为:字体蓝色、底色浅灰、加实线边框。

第五章 · 事件编程 — 自动触发

高阶
🤔 什么是事件?

事件就是「当XX发生时,自动运行的代码」——
修改了单元格 → 自动检查数据是否合法
打开了工作簿 → 自动显示欢迎信息
选择了工作表 → 自动刷新数据

📌 Worksheet_Change — 单元格变化时触发
🎯 场景:修改 A1 时,自动弹窗显示新内容。
1
VBA 编辑器中双击左边 Sheet1
2
上边两个下拉菜单:左选 Worksheet,右选 Change
3
自动生成 Worksheet_Change 框架,在里面写代码↓
Private Sub Worksheet_Change(ByVal Target As Range) ' Target 就是被修改的那个单元格 If Target.Address = "$A$1" Then MsgBox "A1 被改成: " & Target.Value End If If Target.Column = 2 And Target.Value < 0 Then MsgBox "B列不能为负数!" Target.ClearContents End If End Sub
📌 Workbook_Open — 打开文件时触发
1
VBA 编辑器中双击 ThisWorkbook
2
左选 Workbook,右选 Open
3
写代码↓
Private Sub Workbook_Open() ' 打开工作簿时自动执行 MsgBox "欢迎使用本报表!" Worksheets("首页").Activate ' 自动跳转到首页 Range("A1").Value = "上次打开时间: " & Now() End Sub
📌 其他有用的事件
事件名写在触发时机
Worksheet_ChangeSheet 代码页单元格内容被修改
Worksheet_SelectionChangeSheet 代码页选中不同的单元格
Worksheet_BeforeDoubleClickSheet 代码页双击单元格(可取消默认行为)
Workbook_OpenThisWorkbook打开工作簿时
Workbook_BeforeCloseThisWorkbook关闭工作簿前
Workbook_SheetActivateThisWorkbook切换到任一工作表时
⚠️ 注意:事件代码必须写在对应对象的代码页(双击Sheet1或ThisWorkbook),不能写在模块里。
启用宏的文件要保存为 .xlsm 格式,否则事件不会运行。
✏️ 动手试试

题目:让 Excel 在关闭时自动保存,并弹窗提示"已保存,再见!"

第六章 · 实战案例

高阶
📌 实战 1:批量生成工资条
🎯 场景:你有一张工资总表(第1行是标题),想把每人一行拆成工资条——每个人一行标题+一行数据,方便裁开打印。
姓名基本工资奖金扣款实发
张三5,0002,0005006,500
李四6,0001,5006006,900
王五4,5003,0004007,100
Sub 生成工资条() Dim i As Long, 总行数 As Long 总行数 = Cells(Rows.Count, 1).End(xlUp).Row ' A列最后一行 For i = 总行数 To 2 Step -1 ' 从下往上!! Rows(i).Copy ' 复制当前行 Rows(i).Insert Shift:=xlDown ' 插入一行 Rows(1).Copy Rows(i) ' 把标题行粘贴进去 Next i End Sub
💡 从下往上的原因:如果从上往下插行,下面的行号会变,导致循环乱掉。从下往上就不会影响上面的行号。
📌 实战 2:把选中区域导出为 PDF(每人一个文件)
Sub 导出PDF() Dim 区域 As Range Dim 路径 As String 路径 = "C:\PDF导出\" 区域 = Selection ' 当前选中区域 区域.ExportAsFixedFormat _ Type:=xlTypePDF, _ Filename:=路径 & "报表_" & Format(Now(), "yyyymmdd") & ".pdf" MsgBox "PDF 已导出!" End Sub
📌 实战 3:数据查重 + 高亮重复
Sub 高亮重复值() Dim 区域 As Range Dim 当前 As Range, 检查 As Range Dim i As Long, j As Long Set 区域 = Range("A1:A100") ' 要检查的区域 For i = 1 To 区域.Rows.Count For j = i + 1 To 区域.Rows.Count If 区域.Cells(i).Value = 区域.Cells(j).Value _ And 区域.Cells(i).Value <> "" Then 区域.Cells(j).Interior.Color = 65535 ' 标黄 End If Next j Next i MsgBox "重复值已高亮!" End Sub
📌 实战 4:汇总所有工作表的 A1 值
Sub 汇总所有表() Dim ws As Worksheet Dim 行号 As Long 行号 = 1 ' 在"汇总"表里记录每个Sheet的A1值 For Each ws In Worksheets If ws.Name <> "汇总" Then Worksheets("汇总").Cells(行号, 1).Value = ws.Name Worksheets("汇总").Cells(行号, 2).Value = ws.Range("A1").Value 行号 = 行号 + 1 End If Next ws End Sub
✅ 运行后"汇总"表会变成:
Sheet1 | (Sheet1的A1值)
Sheet2 | (Sheet2的A1值)
Sheet3 | (Sheet3的A1值)

第七章 · 调试技巧 — 找错误

进阶
🤔 代码跑错了怎么办?

VBA 有强大的调试工具,不用猜哪里错了,直接看代码一步步执行。

F8 — 逐行执行

按一下执行一行,可以看到每行代码的效果,找到哪一行出问题。

F9 — 设置/取消断点

在某行点一下(或按F9),运行到这一行会自动暂停。

Ctrl+G — 立即窗口

输入 ?变量名 查看变量当前值,输入 变量名=新值 修改变量。

鼠标悬停 — 看变量值

调试暂停时,把鼠标放在变量上,会显示当前值。

Debug.Print

在代码里写 Debug.Print 变量名,运行后在立即窗口看输出。

On Error Resume Next

遇到错误跳过继续执行(谨慎使用,最好配合错误判断)。

📌 调试示例
Sub 调试示例() Dim x As Double, y As Double x = Range("A1").Value y = Range("B1").Value Debug.Print "x=" & x & ", y=" & y ' 在立即窗口输出 Range("C1").Value = x / y ' ← 如果y=0,这里会报错 End Sub
💡 调试步骤:
① 在怀疑有问题的行按 F9 设断点
② 运行宏(F5),会在断点处暂停,变黄色
③ 按 F8 逐行执行,同时把鼠标放到变量上看值
④ 在立即窗口(Ctrl+G)输入 ?变量名 查看
⑤ 发现问题后改代码,再跑一次

📌 实战 5:单元格按 / 拆分成多行

⭐⭐⭐ 高阶
🎯 场景:你的表里多列同时/ 分隔了数据(如 A列="张三/李四",B列="技术部/工程部"),想拆成一一对应的多行。
📋 原始数据
A
姓名
B
部门
C
职位
张三/李四技术部/工程部工程师
赵六/钱七市场部经理/主管
📋 期望结果
A
姓名
B
部门
C
职位
张三技术部工程师
李四工程部工程师
赵六市场部经理
钱七市场部主管
🎯 目标:检查所有列,有 / 就拆,各列片段按顺序配对。某列段数不够时用最后一段补齐。
Sub 拆分斜杠到多行() Dim i As Long, j As Long, k As Long Dim 列数 As Long, 最大段数 As Long, 段数 As Long Dim 文本 As String Dim 各列片段() As Variant ' 存每列的拆分结果 列数 = Cells(1, Columns.Count).End(xlToLeft).Column ' ⚠️ 从下往上遍历 For i = Cells(Rows.Count, 1).End(xlUp).Row To 1 Step -1 最大段数 = 0 ReDim 各列片段(1 To 列数) ' 第1遍:扫描所有列,拆分,算最大段数 For k = 1 To 列数 文本 = Cells(i, k).Value If InStr(文本, "/") > 0 Then 各列片段(k) = Split(文本, "/") ' 拆成数组 段数 = UBound(各列片段(k)) + 1 Else 各列片段(k) = Array(文本) ' 没/就单元素数组 段数 = 1 End If If 段数 > 最大段数 Then 最大段数 = 段数 Next k ' 如果有需要拆分的 If 最大段数 > 1 Then ' 写原行(各列取第0段) For k = 1 To 列数 Cells(i, k).Value = 各列片段(k)(0) Next k ' 插入剩余行 For j = 1 To 最大段数 - 1 Rows(i + j).Insert For k = 1 To 列数 段数 = UBound(各列片段(k)) + 1 If j < 段数 Then Cells(i + j, k).Value = 各列片段(k)(j) ' 按顺序取 Else ' 段数不够,用最后一段补齐 Cells(i + j, k).Value = 各列片段(k)(段数 - 1) End If Next k Next j ' 跳过已插入的行 i = i + 最大段数 - 1 End If Next i MsgBox "拆分完成!" End Sub
💡 升级版代码 vs 旧版:
• 旧版:只检查 A 列,其他列整段复制 → 遇到 "张三/李四"+"技术部/工程部" 会全复制过去
新版:检查所有列,有 / 的各拆各的,按位置配对 → 张三配技术部、李四配工程部 ✅
• 某列段数不够时(比如A拆了3段、B只有1段),用该列的最后一段补齐
Array(文本) 把单值也做成数组,统一处理逻辑
✏️ 动手试试

题目:如果分隔符不是 / 而是顿号(、),代码要怎么改?

⚠️ 注意事项:
• 运行前备份数据!这个操作直接修改原表,插入行后无法一键撤销
• 如果 / 两边有空格(如 "张三 / 李四"),结果会带空格,用 Trim() 去掉
段数补齐规则:不够的列用最后一段填。如 A拆出3段、B只有1段 → 3行中B列全是那1段
• 代码从第1行开始处理到最后一行,标题行如果有 / 也会被拆,建议标题行不要含 /

📖 VBA 速查表

速查
📌 变量声明
写法说明
Dim x As Integer整数(-32768~32767)
Dim x As Long长整数(-21亿~21亿)
Dim x As Double小数
Dim x As String文本
Dim x As BooleanTrue / False
Dim x As Date日期
Dim x As Range单元格区域(必须用 Set)
Dim x As Worksheet工作表(必须用 Set)
📌 常用代码片段
想做什么代码
A列的最后一个有数据的行号Cells(Rows.Count, 1).End(xlUp).Row
当前区域的行数Range("A1").CurrentRegion.Rows.Count
弹消息框MsgBox "你好"
弹输入框x = InputBox("请输入年龄")
让Excel暂时不刷新Application.ScreenUpdating = False
让Excel重新刷新Application.ScreenUpdating = True
关闭警报(删表时)Application.DisplayAlerts = False
打开警报Application.DisplayAlerts = True
等待2秒Application.Wait Now + TimeValue("00:00:02")
当前时间Now()
当前日期Date()
📌 快捷键
快捷键作用
Alt + F11打开/关闭 VBA 编辑器
Alt + F8查看/运行宏
F5运行宏 / 继续运行
F8逐行执行(调试)
F9设置/取消断点
Ctrl + G打开立即窗口
Ctrl + Break强制停止正在运行的宏