0


WPS JS宏入门案例集锦

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不传入全路径,则默认可能保存到我的文档文件夹中。

批量拆分工作表到工作簿

数据如下:

image-20220928204354007

执行代码:

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

分解出3个独立的文件:

image-20220928204807388

批量判断处理单元格数据

数据和需求如下:

image-20220928205227427

简单的方法就是直接筛选再复制粘贴,但是现在我们需要完全基于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
}

运行后:

image-20220928205430277

工资条制作

数据如下:

image-20220928203156400

执行如下代码:

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()}

拆分结果:

image-20220928203242283

注意:如果原表不止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号:

image-20221005141323296

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

function单表多列合并到一列新文件(){var vs=Range("A1").CurrentRegion.Value().flat();// 过滤掉空值并去重
    vs=Array.from(newSet(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(newSet(arr))

过滤空值:

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

最终得到一列:
在这里插入图片描述

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

原数据:

image-20220928205804819

执行代码:

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;}

成功合并得到如下结果:

image-20220928210012195

语音朗读

代码如下:

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:

functiontestAlert_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 ${newDate().toLocaleDateString()}
        </p>`;alert(foo)}

执行效果:

image-20220928210943115

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

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)returnfalse;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

本地文件读写

functionread_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"

生成文件:

image-20220928211451436

JavaScript语法补充

undefined和null的区别

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

typeofundefined// undefinedtypeofnull// objectnull===undefined// falsenull==undefined// true

typeof操作符

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

typeof"John"// 返回 string typeof3.14// 返回 numbertypeofNaN// 返回 numbertypeoffalse// 返回 booleantypeof[1,2,3,4]// 返回 objecttypeof{name:'John',age:34}// 返回 objecttypeofnewDate()// 返回 objecttypeoffunction(){}// 返回 functiontypeof myCar                  // 返回 undefined (如果 myCar 没有声明)typeofnull// 返回 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没有1parseInt('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 ... in

Array

的循环得到的是

String

而不是

Number

for…of循环

具有

iterable

类型的集合还可以通过

for ... of

循环来遍历,它是ES6引入的新的语法。

var a =['A','B','C'];var s =newSet(['A','B','C']);var m =newMap([[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 =newSet(['A','B','C']);//Set没有索引,因此回调函数的前两个参数都是元素本身
s.forEach(function(element, sameElement,set){
    console.log(element);});var m =newMap([[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)=>{ 函数声明 }单一参数=>{函数声明}()=>{函数声明}

例子:

constx=(x, y)=> x * y;constx=(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;// 1990varfn=()=>newDate().getFullYear()-this.birth;// this指向obj对象returnfn();}};
obj.getAge();// 25

由于

this

在箭头函数中已经按照词法作用域绑定了,所以,用

call()

或者

apply()

调用箭头函数时,无法对

this

进行绑定,即传入的第一个参数被忽略:

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

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

this

指向

undefined

window

要指定函数的

this

指向哪个对象,可以用函数本身的

apply

方法,它接收两个参数,第一个参数就是需要绑定的

this

变量,第二个参数是

Array

,表示函数本身的参数。

apply

修复

getAge()

调用:

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

利用

apply()

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

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

window.parseInt=function(){
    count +=1;returnoldParseInt.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

标签: javascript 前端 html

本文转载自: https://blog.csdn.net/as604049322/article/details/127097880
版权归原作者 小小明-代码实体 所有, 如有侵权,请联系我们删除。

“WPS JS宏入门案例集锦”的评论:

还没有评论