整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

JavaScript系统学习DOM系列文章之理解DOM节点关系

OM可以将任何HTML描绘成一个由多层节点构成的结构。节点分为12种不同类型,每种类型分别表示文档中不同的信息及标记。每个节点都拥有各自的特点、数据和方法,也与其他节点存在某种关系。节点之间的关系构成了层次,而所有页面标记则表现为一个以特定节点为根节点的树形结构。

节点中的各种关系可以用传统的家族关系来描述,相当于把文档树比喻成家谱。接下来,将把DOM节点关系分为属性和方法两部分进行详细说明

属性

父级属性parentNode

每个节点都有一个parentNode属性,该属性指向文档树中的父节点。对于一个节点来说,它的父节点只可能是三种类型:element节点、document节点和documentfragment节点。如果不存在,则返回null

parentElement

parentNode跟parentElement除了前者是w3c标准,后者只ie支持(chrome现在都支持)

当父节点的nodeType不是1,即不是element节点的话,它的parentElement就会是null

一般情况parentNode可以取代parentElement的所有功能

parentElement匹配的是parent为element的情况,而parentNode匹配的则是parent为node的情况。element是包含在node里的,它的nodeType是1

<div id="myDiv"></div>
<script>
console.log(myDiv.parentElement);//body
console.log(document.body.parentElement);//html
console.log(document.documentElement.parentElement);//null
console.log(document.parentElement);//null
</script>

[注意]在IE浏览器中,只有Element元素节点才有该属性,其他浏览器则是所有类型的节点都有该属性

<div id="test">123</div>
<script>
//IE浏览器返回undefined,其他浏览器返回<div id="test">123</div>
console.log(test.firstChild.parentElement);
//所有浏览器都返回<body>
console.log(test.parentElement);
</script>

子级属性

childNodes

childNodes是一个只读的类数组对象NodeList对象,它保存着该节点的第一层子节点

<ul id="myUl">
 <li><div></div></li>
</ul>
<script>
var myUl = document.getElementById('myUl');
//结果是只包含一个li元素的类数组对象[li]
console.log(myUl.childNodes);
</script>

children

children是一个只读的类数组对象HTMLCollection对象,但它保存的是该节点的第一层元素子节点

<div id="myDiv">123</div>
<script>
var myDiv = document.getElementById('myDiv');
//childNodes包含所有类型的节点,所以输出[text]
console.log(myDiv.childNodes);
//children只包含元素节点,所以输出[]
console.log(myDiv.children);
</script>

childElementCount

返回子元素节点的个数,相当于children.length

[注意]IE8-浏览器不支持

<ul id="myUl">
 <li></li>
 <li></li>
</ul>
<script>
var myUl = document.getElementById('myUl');
console.log(myUl.childNodes.length);//5,IE8-浏览器返回2,因为不包括空文本节点
console.log(myUl.children.length);//2
console.log(myUl.childElementCount);//2,IE8-浏览器返回undefined
</script>

firstChild

第一个子节点

lastChild

最后一个子节点

firstElementChild

第一个元素子节点

lastElementChild

最后一个元素子节点

上面四个属性,IE8-浏览器和标准浏览器的表现并不一致。IE8-浏览器不考虑空白文本节点,且不支持firstElementChild和lastElementChild

//ul标签和li标签之间有两个空白文本节点,所以按照标准来说,ul的子节点包括[空白文本节点、li元素节点、空白文本节点]。但在IE8-浏览器中,ul的子节点只包括[li元素节点]
<ul>
 <li></li>
</ul>
<ul id="list">
 <li>1</li>
 <li>2</li>
 <li>3</li>
</ul>
<script>
console.log(list.firstChild);//标准浏览器中返回空白文本节点,IE8-浏览器中返回<li>1</li>
console.log(list.lastChild);//标准浏览器中返回空白文本节点,IE8-浏览器中返回<li>3</li>
console.log(list.firstElementChild);//标准浏览器中<li>1</li>,IE8-浏览器中返回undefined
console.log(list.lastElementChild);//标准浏览器中<li>3</li>,IE8-浏览器中返回undefined
</script>

同级属性

nextSibling

后一个节点

previousSibling

前一个节点

nextElementSibling

后一个元素节点

previousElementSibling

前一个元素节点

与子级属性类似,上面四个属性,IE8-浏览器和标准浏览器的表现并不一致。IE8-浏览器不考虑空白文本节点,且不支持nextElementSibling和previousElementSibling

<ul>
 <li>1</li>
 <li id="myLi">2</li>
 <li>3</li>
</ul>
<script>
var myLi = document.getElementById('myLi');
console.log(myLi.nextSibling);//空白节点,IE8-浏览器返回<li>3</li>
console.log(myLi.nextElementSibling);//<li>3</li>,IE8-浏览器返回undefined
console.log(myLi.previousSibling);//空白节点,IE8-浏览器返回<li>1</li>
console.log(myLi.previousElementSibling);//<li>1</li>,IE8-浏览器返回undefined
</script>

方法

包含方法hasChildNodes()

hasChildNodes()方法在包含一个或多个子节点时返回true,比查询childNodes列表的length属性更简单

<div id="myDiv">123</div>
<script>
var myDiv = document.getElementById('myDiv');
console.log(myDiv.childNodes.length);//1
console.log(myDiv.hasChildNodes());//true
</script>
<div id="myDiv"></div>
<script>
var myDiv = document.getElementById('myDiv');
console.log(myDiv.childNodes.length);//0
console.log(myDiv.hasChildNodes());//false
</script>

contains()

contains方法接受一个节点作为参数,返回一个布尔值,表示参数节点是否为当前节点的后代节点。参数为后代节点即可,不一定是第一层子节点

<div id="myDiv">
 <ul id="myUl">
 <li id="myLi"></li>
 <li></li>
 </ul>
</div>
<script>
console.log(myDiv.contains(myLi));//true
console.log(myDiv.contains(myUl));//true
console.log(myDiv.contains(myDiv));//true
</script>

[注意]IE和safari不支持document.contains()方法,只支持元素节点的contains()方法

//IE和safari报错,其他浏览器返回true
console.log(document.contains(document.body));

关系方法

compareDocumentPosition()

compareDocumentPosition方法用于确定节点间的关系,返回一个表示该关系的位掩码

000000 0 两个节点相同

000001 1 两个节点不在同一个文档(即有一个节点不在当前文档)

000010 2 参数节点在当前节点的前面

000100 4 参数节点在当前节点的后面

001000 8 参数节点包含当前节点

010000 16 当前节点包含参数节点

100000 32 浏览器的私有用途

<div id="myDiv">
 <ul id="myUl">
 <li id="myLi1"></li>
 <li id="myLi2"></li>
 </ul>
</div>
<script>
//20=16+4,因为myUl节点被myDiv节点包含,也位于myDiv节点的后面
console.log(myDiv.compareDocumentPosition(myUl));
//10=8+2,因为myDiv节点包含myUl节点,也位于myUl节点的前面
console.log(myUl.compareDocumentPosition(myDiv));
//0,两个节点相同
console.log(myDiv.compareDocumentPosition(myDiv));
//4,myLi2在myLi1节点的后面
console.log(myLi1.compareDocumentPosition(myLi2));
//2,myLi1在myLi2节点的前面
console.log(myLi2.compareDocumentPosition(myLi1));
</script>

isSameNode()和isEqualNode()

这两个方法都接受一个节点参数,并在传入节点与引用节点相同或相等时返回true

所谓相同(same),指的是两个节点引用的是同一个对象

所谓相等(equal),指的是两个节点是相同的类型,具有相等的属性(nodeName、nodeValue等等),而且它们的attributes和childNodes属性也相等(相同位置包含相同的值)

[注意]firefox不支持isSameNode()方法,而IE8-浏览器两个方法都不支持

<script>
var div1 = document.createElement('div');
div1.setAttribute("title","test");
var div2 = document.createElement('div');
div2.setAttribute("title","test");
console.log(div1.isSameNode(div1));//true
console.log(div1.isEqualNode(div2));//true
console.log(div1.isSameNode(div2));//false
</script>

写在后面

这里列的很多方法大家可能都没见过,或者学过JQuery之后对这些方法既熟悉又陌生,大家可以把我当这些小例子运行一下,就能更直观的区分这些方法之间的关联和区别,这对我们后面的分享和学习有一定的理解。

传送门JavaScript设计模式系列

1、JavaScript设计模式之策略模式(Strategy Pattern)

2、JavaScript设计模式之职责链模式(Chain of Responsibility...)

3、JavaScript设计模式之享元模式(flyweight Pattern)

4、JavaScript设计模式之装饰者模式(Decorator Pattern)

5、JavaScript设计模式之代理模式(Proxy Pattern)

6、JavaScript设计模式之组合模式(Composite Pattern)

7、JavaScript设计模式之工厂模式(Factory Method Pattern)

8、JavaScript设计模式之中介者模式(Mediator Pattern)

....

参考文章:

https://www.cnblogs.com/xiaohuochai/p/5785297.html

http://www.voidcn.com/article/p-gasrrkzi-bpb.html

https://www.cnblogs.com/zhishaofei/p/4091865.html

一节我们说JS主要由三部分组成:ES、DOM和BOM,接下来学生就给大家简单介绍一下他们。

ECMAScript

ECMAScript是什么

ES主要定义了基础的语法结构,以及一些内置对象。

语法就是进行沟通的规则,比如我们在代码中写“弹出提示框”,这样并不会弹出来,而写“alert()”就可以弹出来了,这就是因为ES的语法是那么规定的。对于一种编程语言来说通常都会规定定义变量、判断、循环、运算、语句集(比如函数)的定义及调用等规则,ES当然也不例外,也规定了这些内容。以前学生在单位的一次讲课中说:什么是程序,程序就是流程加顺序。虽然这种说法不够严谨,不过程序的核心应该还是流程。

ES是一种面向对象的语言,所以他的语法中还定义了很多对象相关的内容,比如最常见的this、prototype等,而且还定义了一些内置的对象,比如Number、String、Array、Math以及RegExp等。

ES的通用语法是很容易学习的,只要有点其他语言的基础,入手非常简单,这也就是一般都会觉得JS入门很容易的原因。不过ES中对象相关的语法就没那么容易了,这也是ES(或者JS)的重点和难点,学生会在后面重点进行讲解,让大家彻底掌握。

发展

ES所对应的ECMA-262标准从1997年发布的第一个版本一直到现在一共发布到了六个版本,第六版于今年(2015年)6月份刚刚发布,他的正式名称是ECMAScript 2015(简称ES2015),因为是第六版所以也有的地方叫他ECMAScript6,我们看到后知道他们是同一个东西就可以了。

ES2015中增加了很多新的特性,特别是启用了class关键字(不过并不是面向类的语言,学生会在ES2015相关章节中给大家详细分析),这样使用起来就更加方便了。不过ES的本质并没有发生变化,他依然是一种基于对象的语言,在理解了其本质之后无论哪个版本都可以非常容易地掌握,他们之间的区别无非就是一些具体语法和功能上的增强。学生后面将以现在最通用的ES5.1版为基础给大家进行讲解,最后再补充ES2015中新增的内容。

另外,我们要清楚ES只是一套标准,具体的实现还需要各个浏览器的支持,不同浏览器对ES的支持也不完全相同,而且在ES的基础上不同的浏览器也都进行了自己相应的扩充,这就造成了浏览器兼容性的问题。

DOM

我们前面说过,ES的标准化主要是为了解决各大浏览器厂商(特别是微软和网景公司)对脚本语言语法的实现不统一。不过他们在浏览器上的竞争并没有因为ES的出现而终止,微软为了占领更大的市场就在自己的Internet Explorer浏览器上加入了很多专有的属性,比如VBScript和ActiveX,而使用了这些技术的网页必须使用微软的平台和浏览器才可以正常显示,这就给开发者带来了麻烦,这时W3C的一些成员公司就提议创建一套标准将页面文档的结构暴露给脚本,从而使脚本可以统一操作页面的内容,这样最后就制定出了DOM标准。

DOM是Document Object Model的缩写,表示文档对象模型,他定义了文档对象的结构及其操作方法等内容。为什么叫对象模型呢?我们前面说过ES是一种面向对象的语言,他要操作的目标是对象,而DOM就是将html文档转换(或者对应)成ES可以操作的对象的一种模型。

DOM虽然是因为浏览器而制定的,但他现在不仅可以用在浏览器所用的Html文件中,而且还可以用到很多其他格式的文件中,比如服务端经常用来配置信息的XML文件、Flex的mxml文件以及表示矢量图的SVG格式文件等,这些都符合DOM标准。

另外,DOM主要是定义了文档(可以理解为符合相应格式的页面文件)和文档对象以及其操作方法的对应关系,而跟具体的语言无关,所以DOM不仅适用于ES,还适用于很多别的语言,比如Java中的dom4j也是DOM的一种实现。而且DOM中规定操作文档的方法都是通过接口定义的,这样不同的语言就可以按照自己的语法来进行实现了。

BOM

JS的功能并不仅限于对文档的操作,有时候还需要对浏览器直接进行操作,比如查看当前页面的url地址、控制浏览器前进、后退、以及HTML5中获取位置信息、WebSocket等都需要对浏览器进行操作,而且最简单的alert、setTimeout和setInterval也是需要浏览器来完成的。

ES对浏览器操作的处理方法和对文档操作的处理方法一样,依然是将浏览器转换为一个对象,这就是浏览器对象(Browser Object),他所对应的模型就叫浏览器对象模型(Browser Object Mode),简称BOM。

HTML5

Html5是近两年非常热的一个名词,到底什么是Html5呢?

从名字就可以看出来他是和网页相关的一个东西,而网页的三大组成部分依然是文档结构、展示和动作控制,他们所对应的技术分别是html、css和JS,前两者都属于DOM中的内容(CSS作为文档的一种特殊节点或者属性,也属于DOM的一部分,而且DOM中有专门的相关标准),JS可以对DOM进行操作。

Html5的主要贡献就是扩展了html的标签(同时也去掉了一些原先的标签),比如新增了section、article、header、footer、audio、video以及备受关注的canvas标签,当然也相应地扩展了DOM,另外Html5也对BOM进行了扩展,使得JS操作浏览器的功能更加强大,而且也促进了BOM标准化。

节内容是"VBA信息获取与处理"教程中第八个专题"VBA与HTML文档"的第五节。,希望想掌握这方面知识的朋友能参考我的教程学习。

第五节 HTML文档的访问端口DOM (Document Object Model)

大家好,我们继续对HTML文档进行学习,在前几节中我们认识了网页文档上面的各种元素,那么我们又该怎么访问他们呢,是如何实现呢?其实,HTML文档,提供了访问其元素的端口,这就是HTML DOM,其定义了一套标准的针对 HTML 文档的对象访问或操作的机制。HTML DOM 定义了所有 HTML 元素的对象和属性,以及访问它们的方法。换言之,HTML DOM 是关于如何获取、修改、添加或删除 HTML 元素的标准。

1 HTML DOM (Document Object Model) 对象集合

每个载入浏览器的 HTML 文档都会成为 Document 对象。Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。Document 对象是 HTML 文档的根节点。

特别注意:Document 对象是 Window 对象的一部分,可通过 window.document 属性对其进行访问。

集合 描述

all[] 提供对文档中所有 HTML 元素的访问。

anchors[] 返回对文档中所有 Anchor 对象的引用。

applets 返回对文档中所有 Applet 对象的引用。

forms[] 返回对文档中所有 Form 对象引用。

images[] 返回对文档中所有 Image 对象引用。

links[] 返回对文档中所有 Area 和 Link 对象引用。


VBA直接支持调用的对象有限,如下:

对象 描述

Document 代表整个 HTML 文档,可被用来访问页面中的所有元素

Anchors 代表 <a> 元素集合

Body 代表 <body> 元素

Forms 代表 <form> 元素集合

Frames 代表 <frame> 元素或<iframe> 元素集合

Images 代表 <img> 元素集合

Links 代表 <link> 元素集合

Options 代表 <option> 元素集合(select元素里面可以直接使用)

Cells 代表 <td> 元素集合(table元素里面可以直接使用)

Rows 代表 <tr> 元素集合(table元素里面可以直接使用)

All 对象集合,提供对文档中所有 HTML 元素的访问。


上述VBA支持直接调用对象的元素,调用起来就非常方便了,可以用序号调用,例如forms(0),也可以按名称/ID调用,例如forms("名称/ID")。其他没法直接调用对象的元素,可以间接从通用all对象集合中去调用该元素或该元素对应的dom对象。

2 HTML DOM 文档的节点及文档树

在HTML DOM中,所有事物都是节点。DOM 是被视为节点树的 HTML文档的每一部分都是节点,整个文档被定义为一个文档节点,每个标签是一个元素节点,包含在元素中的文本是文本节点,每一个元素的属性是一个属性节点。如下:

1)整个文档是一个文档节点

2)每个 HTML 元素是元素节点

3)HTML 元素内的文本是文本节点

4)每个 HTML 属性是属性节点

5)注释是注释节点


HTML DOM 将 HTML 文档视作树结构。这种结构被称为节点树,这时一个非常形象的比喻,根节点就是html,主干就是body等,枝干就是body内含的各种元素节点,叶子和花就是元素节点关联的元素的属性(属性节点)或内含文本(文本节点)。


通过 HTML DOM,树中的所有节点均可通过 JavaScript 进行访问。所有 HTML 元素(节点)均可被修改,也可以创建或删除节点。节点树中的节点彼此拥有层级关系。父(parent)、子(child)和同胞(sibling)等术语用于描述这些关系。父节点拥有子节点。同级的子节点被称为同胞(兄弟或姐妹)。

网页文档,可以说是由元素组合而成的,也可以说是由节点连接而成的树构造的。节点是文档树结构中特有的名词,元素是节点,但是节点不一定是元素,节点还有文档节点、文本节点、属性节点等;元素是元素节点的扩展,元素可以拥有属性还有文本。初学者不是很必要纠结元素和节点的区别,这个需要甚至数据结构、类和继承等知识。可大致理解为,同一个html dom对象,提供的两个不同接口。如下的程序,你会发现,他既有支持node(节点)的相关属性和方法,也提供了element(元素)的相关属性和方法。


Sub MYNZ()

Dim ie, dmt, bd

Set ie = CreateObject("InternetExplorer.Application") '创建一个IE对象

With ie

.Visible = True '显示它

.navigate "http://www.baidu.com" '加载某个页面

Do Until .ReadyState = 4 '等待页面加载完毕

DoEvents

Loop

Set dmt = .document '将IE浏览器加载的页面文档,赋予dmt变量

Set bd = dmt.body '将文档的body赋予bd变量

End With

End Sub


代码截图:

按F8键运行截图:

3 HTML DOM 文档的对象属性

属性是节点(HTML 元素)的值,您能够获取或设置。所有 HTML 元素被定义为对象,而编程接口则是对象方法和对象属性。我们看看下面一些常见的属性:


1)innerHTML 属性 对象内部的HTML代码,是获取元素内容的最简单方法。innerHTML 属性对于获取或替换 HTML 元素的内容很有用。

下面的代码获取 id="intro" 的 <p> 元素的 innerHTML:

<script>

var txt=document.getElementById("intro").innerHTML;

document.write(txt);


2)OuterHtml:对象的HTML代码,包括对象本身的HTML标签


3)innerText:对象内部的文本


4)OuterText:对象的文本,包括对象本身的文本


5)nodeName 属性 nodeName 属性规定节点的名称。

nodeName 是只读的

元素节点的 nodeName 与标签名相同

属性节点的 nodeName 与属性名相同

文本节点的 nodeName 始终是 #text

文档节点的 nodeName 始终是 #document


注释:nodeName 始终包含 HTML 元素的大写字母标签名。


6)nodeValue 属性 nodeValue 属性规定节点的值。

元素节点的 nodeValue 是 undefined 或 null

文本节点的 nodeValue 是文本本身

属性节点的 nodeValue 是属性值


7)nodeType 属性 nodeType 属性返回节点的类型。nodeType 是只读的。

比较重要的节点类型有:


元素类型 NodeType

元素 1

属性 2

文本 3

注释 8

文档 9


以上只是给出了属性值,大家在使用的时候要注意。


本节知识点回向:


什么是HTML DOM文档的属性,常用的属性有哪些。


本节参考文件:008工作表.xlsm

积木编程的思路内涵:

在我的系列书籍中一直在强调"搭积木"的编程思路,这也是学习利用VBA的主要方法,特别是职场人员,更是要采用这种方案。其主要的内涵:

1 代码不要自己全部的录入。你要做的是把积木放在合适的位置然后去修正代码,一定要拷贝,从你的积木库中去拷贝,然后修正代码,把时间利用到高效的思考上。

2 建立自己的"积木库"。平时在学习过程中,把自己认为有用的代码放在一起,多积累,在用到的时候,可以随时拿来。你的积木库资料越多,你做程序的思路就会越广。

VBA的应用界定

VBA是利用Office实现个人小型办公自动化的有效手段(工具)。这是我对VBA的应用界定。在取代OFFICE新的办公软件没有到来之前,谁能在数据处理方面做到极致,谁就是王者。其中登峰至极的技能非VBA莫属!

我记得20年前自己初学VBA时,那时的资料甚少,只能看源码自己琢磨,真的很难。20年过去了,为了不让学习VBA的朋友重复我之前的经历,我根据自己多年VBA实际利用经验,推出了六部VBA专门教程:

第一套:VBA代码解决方案 是VBA中各个知识点的讲解,教程共147讲,覆盖绝大多数的VBA知识点,初学必备;

第二套:VBA数据库解决方案 数据库是数据处理的专业利器,教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法和实例操作,适合中级人员的学习。

第三套:VBA数组与字典解决方案 数组和字典是VBA的精华,字典是VBA代码水平提高的有效手段,值得深入的学习,是初级及中级人员代码精进的手段。

第四套:VBA代码解决方案之视频 是专门面向初学者的视频讲解,可以快速入门,更快的掌握这门技能。这套教程是第一套教程的视频讲解,听元音更易接受。

第五套:VBA中类的解读和利用 这是一部高级教程,讲解类的虚无与肉身的度化,类的利用虽然较少,但仔细的学习可以促进自己VBA理论的提高。这套教程的领会主要是读者的领悟了,领悟一种佛学的哲理。

第六套教程:《VBA信息获取与处理》是一部高级教程,涉及范围更广,实用性更强,面向中高级人员。教程共二十个专题,包括:跨应用程序信息获得、随机信息的利用、电子邮件的发送、VBA互联网数据抓取、VBA延时操作,剪切板应用、Split函数扩展、工作表信息与其他应用交互,FSO对象的利用、工作表及文件夹信息的获取、图形信息的获取以及定制工作表信息函数等等内容。

大家可以根据以上资料1→3→2→6→5或者是4→3→2→6→5的顺序逐渐深入的逐渐学习。教程提供讲解的同时提供了大量的积木,如需要可以WeChat: NZ9668


学习VBA是个过程,也需要经历一种枯燥的感觉

如太白诗云:众鸟高飞尽,孤云独去闲。相看两不厌,只有敬亭山。学习的过程也是修心的过程,修一个平静的心。在代码的世界中,心平静了,心情好了,身体自然而然就好。心静则正,内心里没有那么多邪知邪见,也就没有那么多妄想。利人就是利己。这些教程也是为帮助大家起航,助上我自己之力,我的上述教程是我多的经验的传递,

"水善利万物而不争",绵绵密密,微则无声,巨则汹涌。学习亦如此,知道什么是自己所需要的,不要蜷缩在一小块自认为天堂的世界里,待到暮年时再去做自欺欺人的言论。要努力提高自己,用一颗充满生机的心灵,把握现在,这才是进取。越是有意义的事情,困难会越多。愿力决定始终,智慧决定成败。不管遇到什么,都是风景。看淡纷争,看轻得失。茶,满也好,少也好,不要计较;浓也好,淡也好,其中自有值得品的味道。去感悟真实的时间,静下心,多学习,积累福报。而不是天天混日子,也不是天天熬日子。在后疫情更加严峻的存量残杀世界中,为自己的生存进行知识的储备,特别是新知识的储备。学习时微而无声,利用时则巨则汹涌。

每一分收获都是成长的记录,怎无凭,正是这种执着,成就了朝霞的灿烂。最后将一阙词送给致力于VBA学习的朋友,让大家感受一下学习过程的枯燥与执着:


浮云掠过,暗语无声,

唯有清风,惊了梦中啼莺。

望星,疏移北斗,

奈将往事雁同行。

阡陌人,昏灯明暗,

忍顾长亭。

多少VBA人,

暗夜中,悄声寻梦,盼却天明。

怎无凭!


回向学习利用VBA的历历往事,不胜感慨,谨以这些文字给大家,分享我多年工作实际经验的成果,随喜这些有用的东西,给确实需要利用VBA的同路人。


分享成果,随喜正能量