草庐IT

WPS JS宏入门案例集锦

小小明-代码实体 2023-04-21 原文

JS宏官方API文档:https://qn.cache.wpscdn.cn/encs/doc/office_v19/index.htm

批量创建工作表/簿

批量创建工作表:

function 批量创建工作表(){
	for (var city of ["成都","上海","北京"]){
		let sht = Worksheets.Add();
		sht.Name = city;
	}
}

批量创建工作簿:

function 批量创建工作簿(){
	for (var city of ["成都","上海","北京"]){
		book = Workbooks.Add();
		book.SaveAs(`E:/tmp/${city}`);
		book.Close();
	}
}

若book.SaveAs不传入全路径,则默认可能保存到我的文档文件夹中。

批量拆分工作表到工作簿

数据如下:

执行代码:

function 批量拆分工作表(){
	for (var sh of Sheets){
		// 如果既不指定 Before 也不指定 After,则新建一个工作簿,其中包含复制的工作表。
		sh.Copy();
		ActiveWorkbook.SaveAs(`E:/VBA/wps/${sh.Name}.xlsx`);
		ActiveWorkbook.Close();
	}
}

分解出3个独立的文件:

批量判断处理单元格数据

数据和需求如下:

简单的方法就是直接筛选再复制粘贴,但是现在我们需要完全基于js宏的语法实现:

function 分数筛选(){
	var Arr1=[];
	var Arr2=Range("a2:b13").Value();
	for (var row of Arr2){
		if (row[1]>=100){
			Arr1.push(row);
		}
	}
	Range("d4").Resize(Arr1.length,2).Value2=Arr1
}

运行后:

工资条制作

数据如下:

执行如下代码:

function 工资条制作()
{
	Application.DisplayAlerts=false;
	let src=Sheets("工资表");
	for(let sht of Sheets){
		if(sht.Name=="结果") sht.Delete();
	}
	Application.DisplayAlerts=true;
	var sht=Worksheets.Add();
	sht.Name="结果";
	for(i=0;i<10;i++) {
		src.Range("a1:m4").Copy();
		sht.Cells.Item(5*i+1,1).PasteSpecial();
		src.Range(`A${i+5}:M${i+5}`).Copy();
		sht.Cells.Item(5*i+5,1).PasteSpecial();
	}
	sht.Activate()
}

拆分结果:

注意:如果原表不止10人,则修改循环次数即可。

如果允许直接在原表上修改,可以使用相对引用录制宏得到代码:

function 工资条制作2()
{
	Range("a1:m4").Select();
	for (var i=1;i<=9;i++){
			Selection.Copy();
			ActiveCell.Offset(5, 0).Range("A1:M4").Insert(xlShiftDown, undefined);
			Application.CutCopyMode = false;
			ActiveCell.Offset(5, 0).Range("A1:M4").Select();
	}
}

任意多列SN号合并到一列

原数据都是如下格式的SN号:

下面我们考虑通过宏代码合并到一列,代码如下:

function 单表多列合并到一列新文件()
{
	var vs=Range("A1").CurrentRegion.Value().flat();
	// 过滤掉空值并去重
	vs=Array.from(new Set(vs.filter(v=>v!=undefined)));
	// 一维数组默认赋值给一行,赋值给一列需要先转置二维
	vs = WorksheetFunction.Transpose(vs);
	var wb = Workbooks.Add();
	wb.Sheets(1).Range("A1").Resize(vs.length,1).Value2 = vs;
}

注意:上面的代码使用JavaScript的语法对数组进行了去重。

Array.from(new Set(arr))

过滤空值:

arr.filter(v=>v!=undefined)

最终得到一列:

批量合并工作表并添加来源表名

原数据:

执行代码:

function 合并工作表数据(){
	var NewArr=[],n=1;
	for (var ws of Sheets){
		var Arr=ws.Range("a1").CurrentRegion.Value();
		if (n++ ==1){var title=Arr[0].concat("工作表名")};
		delete Arr[0]
		Arr.forEach(ar=>NewArr.push(ar.concat(ws.Name)));
	}
	NewArr.unshift(title);
	var wb=Workbooks.Add();
	wb.Sheets(1).Range("a1").Resize(NewArr.length,NewArr[0].length).Value2=NewArr;
}

成功合并得到如下结果:

语音朗读

代码如下:

function Workbook_Open()
{
    Application.Speech.Speak("美好的一天就从这一刻开始吧!",true)
}

function Workbook_NewSheet(Sh)
{
    Application.Speech.Speak("果然狠人老表,区区几张sheet是不够你消遣的!",true)
}

function Application_WorkbookBeforeClose(Wb, Cancel)
{
    Application.Speech.Speak("就想问老板,可以下班了吗?")
}

function Application_SheetSelectionChange(Sh, Target){
	if(Sh.Name!="词汇"|Target.Value()==undefined) return;
	Application.Speech.Speak(Target.Value());
}

保存上面的代码后,当打开或关闭该文件或新建工作表都会朗读对应的文字。

对于词汇这张工作表,点击任何有值的单元格都会对其进行朗读。

Application.Speech.Speak第二个参数传入true表示异步,默认为同步。

富文本弹窗

alert函数支持传入HTML:

function testAlert_CSS(){
	let foo = `
		<h3 style="color:red">Hi</h3>
		<p style="color:green;text-shadow: 1px 1px 2px red, 0 0 1em blue, 0 0 0.2em blue;">
			Hi ${new Date().toLocaleDateString()}
		</p>`;
	alert(foo)
}

执行效果:

判断目标是否在指定区域内

function _m_isInArea(uArea,cell){
    uArea = typeof(uArea) =="string" ? Range(uArea):uArea;
    cell = typeof(cell) =="string" ? Range(cell):cell;
    if(uArea.Parent.Name!=cell.Parent.Name) return false;
    let s_row=uArea.Row,e_row=s_row+uArea.Rows.Count-1;
    let s_col=uArea.Column,e_col=s_col+uArea.Columns.Count-1;
    let t_row = cell.Row,t_col = cell.Column;
//	Console.log(`${s_row}-${e_row},${s_col}-${e_col},(${t_row},${t_col})`);
	return s_row<=t_row && t_row<=e_row && s_col<=t_col && t_col<=e_col;
}

function _m_test(){
    Console.log(_m_isInArea("A2:C20","B3"));
    Console.log(_m_isInArea("A2:C20","D3"));
}

结果:

true
false

本地文件读写

function read_write_data_txt(){
	let txtFile = "E:/tmp/a.txt";
	
    let f = FreeFile() ;
	Open(txtFile,f,jsOutput,jsWrite);
	Write(f,"123");
	Write(f,"456,789");
	Write(f,"aaa,bbb");
    Close();
    
    Console.clear()
    let fNumber = FreeFile()
    Open(txtFile, fNumber,jsInput)
    while(!EOF(fNumber)) {
    	let p=LineInput(fNumber);
    	Console.log(p)
    }
    Close(fNumber)
}
"123"
"456,789"
"aaa,bbb"

生成文件:

JavaScript语法补充

undefined和null的区别

undefined和null的区别(值相等,但类型不等) :

typeof undefined             // undefined
typeof null                  // object
null === undefined           // false
null == undefined            // true

typeof操作符

typeof 操作符可以检测变量的数据类型 :

typeof "John"                 // 返回 string 
typeof 3.14                   // 返回 number
typeof NaN                    // 返回 number
typeof false                  // 返回 boolean
typeof [1,2,3,4]              // 返回 object
typeof {name:'John', age:34}  // 返回 object
typeof new Date()             // 返回 object
typeof function () {}         // 返回 function
typeof myCar                  // 返回 undefined (如果 myCar 没有声明)
typeof null                   // 返回 object

解构赋值

var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
console.log('x = ' + x + ', y = ' + y + ', z = ' + z);
// x = hello, y = JavaScript, z = ES6
[x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
console.log('x = ' + x + ', y = ' + y + ', z = ' + z);
// x = hello, y = JavaScript, z = ES6

数组常用方法

方法描述
concat()连接两个或更多的数组,并返回结果。
copyWithin()从数组的指定位置拷贝元素到数组的另一个指定位置中。
entries()返回数组的可迭代对象。
every()检测数值元素的每个元素是否都符合条件。
fill()使用一个固定值来填充数组。
filter()检测数值元素,并返回符合条件所有元素的数组。
find()返回符合传入测试(函数)条件的数组元素。
findIndex()返回符合传入测试(函数)条件的数组元素索引。
forEach()数组每个元素都执行一次回调函数。
from()通过给定的对象中创建一个数组。
includes()判断一个数组是否包含一个指定的值。
indexOf()搜索数组中的元素,并返回它所在的位置。
isArray()判断对象是否为数组。
join()把数组的所有元素放入一个字符串。
keys()返回数组的可迭代对象,包含原始数组的键(key)。
lastIndexOf()搜索数组中的元素,并返回它最后出现的位置。
map()通过指定函数处理数组的每个元素,并返回处理后的数组。
pop()删除数组的最后一个元素并返回删除的元素。
push()向数组的末尾添加一个或更多元素,并返回新的长度。
reduce()将数组元素计算为一个值(从左到右)。
reduceRight()将数组元素计算为一个值(从右到左)。
reverse()反转数组的元素顺序。
shift()删除并返回数组的第一个元素。
slice()选取数组的的一部分,并返回一个新数组。
some()检测数组元素中是否有元素符合指定条件。
sort()对数组的元素进行排序。
splice()从数组中添加或删除元素。
unshift()向数组的开头添加一个或更多元素,并返回新的长度。

splice:

splice()方法可以从指定的索引开始删除若干元素,然后再从该位置添加若干元素:

var arr = ['Microsoft', 'Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle'];
// 从索引2开始删除3个元素,然后再添加两个元素:
arr.splice(2, 3, 'Google', 'Facebook'); // 返回删除的元素 ['Yahoo', 'AOL', 'Excite']
arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
// 只删除,不添加:
arr.splice(2, 2); // ['Google', 'Facebook']
arr; // ['Microsoft', 'Apple', 'Oracle']
// 只添加,不删除:
arr.splice(2, 0, 'Google', 'Facebook'); // 返回[],因为没有删除任何元素
arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']

concat:

concat()方法把当前的Array和另一个Array连接起来,并返回一个新的Array

var arr = ['A', 'B', 'C'];
var added = arr.concat([1, 2, 3]);
added; // ['A', 'B', 'C', 1, 2, 3]
arr; // ['A', 'B', 'C']

请注意,concat()方法并没有修改当前Array,而是返回了一个新的Array

实际上,concat()方法可以接收任意个元素和Array,并且自动把Array拆开,然后全部添加到新的Array里:

var arr = ['A', 'B', 'C'];
arr.concat(1, 2, [3, 4]); // ['A', 'B', 'C', 1, 2, 3, 4]

join:

join()方法把当前Array的每个元素都用指定的字符串连接起来,然后返回连接后的字符串:

var arr = ['A', 'B', 'C', 1, 2, 3];
arr.join('-'); // 'A-B-C-1-2-3'

如果Array的元素不是字符串,将自动转换为字符串后再连接。

map函数遇到的问题

map的语法:

array.map(function(currentValue,index,arr), thisValue)
  • currentValue: 当前元素的值
  • index : 当前元素的索引值
  • arr : 前元素属于的数组对象
  • thisValue:用作 “this” 的值。如果省略了 thisValue,或者传入 null、undefined,那么回调函数的 this 为全局对象。

利用map()把字符串变成整数 :

var arr = ['1', '2', '3'];
var r = arr.map(parseInt);
console.log(r);
//结果却是1, NaN, NaN

这是因为parseInt接受两个参数(string, radix),第二个参数指定被转换的“数字”多少进制。

arr = [1,2,3]时,arr.map(parseInt)实际为:

parseInt('1', 0);  // 按十进制转换'1'
parseInt('2', 1);  // 按一进制转换'2',但一进制中只有0没有1
parseInt('3', 2);  // 按二进制转换3,但二进制中只有0和1没有2

解决办法:

var arr = ['1', '2', '3'];
var r = arr.map(str=>parseInt(str));
console.log(r);
// 结果:1,2,3

模板字符串

var name = '小华';
var age = 20;
var message = `你好, ${name}, 你今年${age}岁了!`;

循环语句

for循环

语法:

for (语句 1; 语句 2; 语句 3) {
    被执行的代码块
}
  • 语句1 (代码块)开始前执行
  • 语句2 定义运行循环(代码块)的条件
  • 语句3 在循环(代码块)已被执行之后执行
for (var i=0,len=cars.length; i<len; i++)
{ 
    document.write(cars[i] + "<br>");
}
// 或
var i=2,len=cars.length;
for (; i<len; i++)
{ 
    document.write(cars[i] + "<br>");
}

for…in循环

for/in 语句循环遍历对象的属性:

var person={fname:"John",lname:"Doe",age:25}; 
for (x in person)  // x 为属性名
{
    txt=txt + person[x];
}

循环遍历Array的索引:

var a = ['A', 'B', 'C'];
for (var i in a) {
    console.log(i); // '0', '1', '2'
    console.log(a[i]); // 'A', 'B', 'C'
}

注意:for ... inArray的循环得到的是String而不是Number

for…of循环

具有iterable类型的集合还可以通过for ... of循环来遍历,它是ES6引入的新的语法。

var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for (var x of a) { // 遍历Array
    console.log(x);
}
for (var x of s) { // 遍历Set
    console.log(x);
}
for (var x of m) { // 遍历Map
    console.log(x[0] + '=' + x[1]);
}

for of循环和for in循环的区别

for ... in循环遍历的实际是对象的属性名称,手动给Array对象添加了额外的属性后:

当我们手动给Array对象添加了额外的属性后,for ... in循环将带来意想不到的意外效果:

var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x in a) {
    console.log(x); // '0', '1', '2', 'name'
}

for ... of循环则只循环集合本身的元素:

var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x of a) {
    console.log(x); // 'A', 'B', 'C'
}

iterable内置的forEach方法

var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
    // element: 指向当前元素的值
    // index: 指向当前索引
    // array: 指向Array对象本身
    console.log(element + ', index = ' + index);
});
var s = new Set(['A', 'B', 'C']);
//Set没有索引,因此回调函数的前两个参数都是元素本身
s.forEach(function (element, sameElement, set) {
    console.log(element);
});
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
//Map的回调函数参数依次为value、key和map本身
m.forEach(function (value, key, map) {
    console.log(value);
});

回调函数可以省略参数:

var a = ['A', 'B', 'C'];
a.forEach(function (element) {
    console.log(element);
});

while 循环

语法:

while (条件)
{
    需要执行的代码
}
// 或
do
{
    需要执行的代码
}
while (条件);

例子:

while (i<5)
{
    x=x + "The number is " + i + "<br>";
    i++;
}
do
{
    x=x + "The number is " + i + "<br>";
    i++;
}
while (i<5);

箭头函数与装饰器

ES6 新增了箭头函数,语法 :

(参数1, 参数2,, 参数N) => { 函数声明 }
单一参数 => {函数声明}
() => {函数声明}

例子:

const x = (x, y) => x * y;
const x = (x, y) => { return x * y };

箭头函数简化了函数定义,如果只包含一个表达式,可以省略{ ... }return

如果要返回一个对象,单表达式会报错:

// SyntaxError:
x => { foo: x }

因为和函数体的{ ... }有语法冲突,所以要改为:

// ok:
x => ({ foo: x })

箭头函数看上去是匿名函数的一种简写,但有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。

箭头函数的this总是指向词法作用域,也就是外层调用者obj

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
        return fn();
    }
};
obj.getAge(); // 25

由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略:

var obj = {
    birth: 2000,
    getAge: function (year) {
        var b = this.birth; // 1990
        var fn = (y) => y - this.birth; // this.birth仍是2000
        return fn.call({birth:2010}, year);
    }
};
obj.getAge(2015); // 15

在一个独立的函数调用中,根据是否是strict模式,this指向undefinedwindow

要指定函数的this指向哪个对象,可以用函数本身的apply方法,它接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是Array,表示函数本身的参数。

apply修复getAge()调用:

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}
var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};
xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空

利用apply()可实现装饰器,比如想统计一下代码一共调用了多少次:

'use strict';

var count = 0;
var oldParseInt = parseInt; // 保存原函数

window.parseInt = function () {
    count += 1;
    return oldParseInt.apply(null, arguments); // 调用原函数
};
parseInt('10');
parseInt('20');
parseInt('30');
console.log('count = ' + count); // 3

call()apply()类似,唯一区别是:

  • apply()把参数打包成Array再传入;
  • call()把参数按顺序传入。

比如调用Math.max(3, 5, 4),分别用apply()call()实现如下:

Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5

对普通函数调用,通常把this绑定为null

有关WPS JS宏入门案例集锦的更多相关文章

  1. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

  2. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  3. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  4. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  5. ES基础入门 - 2

    ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear

  6. 区块链入门教程(6)--WeBASE-Front节点前置服务安装 - 2

    文章目录1.任务背景2.任务目标3.相关知识点4.任务实操4.1安装配置JDK4.2启动FISCOBCOS4.3下载解压WeBASE-Front4.4拷贝sdk证书文件4.5启动节点4.6访问节点4.7检查运行状态5.任务总结1.任务背景FISCOBCOS其实是有控制台管理工具,用来对区块链系统进行各种管理操作。但是对于初学者来说,还是可视化界面更友好,本节就来介绍WeBASE管理平台,这是一款微众银行开源的自研区块链中间件平台,可以降低区块链使用的门槛,大幅提高区块链应用的开发效率。微众银行是腾讯牵头设立的民营银行,在国内民营银行里还是比较出名的。微众银行参与FISCOBCOS生态建设,一定

  7. Tcl脚本入门笔记详解(一) - 2

    TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是

  8. Simulink方法总结和避坑指南(一)——Simulink入门与基本调试方法 - 2

    文章目录一、项目场景二、基本模块原理与调试方法分析——信源部分:三、信号处理部分和显示部分:四、基本的通信链路搭建:四、特殊模块:interpretedMATLABfunction:五、总结和坑点提醒一、项目场景  最近一个任务是使用simulink搭建一个MIMO串扰消除的链路,并用实际收到的数据进行测试,在搭建的过程中也遇到了不少的问题(当然这比vivado里面的debug好不知道多少倍)。准备趁着这个机会,先以一个很基本的通信链路对simulink基础和相关的debug方法进行总结。  在本篇中,主要记录simulink的基本原理和基本的SISO通信传输链路(QPSK方式),计划在下篇记

  9. ruby &&= 边缘案例 - 2

    有点边缘情况,但知道为什么&&=会这样吗?我正在使用1.9.2。obj=Object.newobj.instance_eval{@bar&&=@bar}#=>nil,expectedobj.instance_variables#=>[],soobjhasno@barinstancevariableobj.instance_eval{@bar=@bar&&@bar}#ostensiblythesameas@bar&&=@barobj.instance_variables#=>[:@bar]#whywouldthisversioninitialize@bar?为了比较,||=将实例变量初始

  10. ESP32学习入门:WiFi连接网络 - 2

    目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方

随机推荐