第5章JavaScript基础 JavaScript是小程序逻辑层的编程语言,JavaScript代码大约占小程序代码量的一半,学好JavaScript是学好小程序开发的关键。 本章主要目标  熟练掌握JavaScript语法格式;  熟练掌握JavaScript变量、数据类型、运算符、函数等基本概念;  熟练掌握小程序事件函数中this和that的使用;  熟练掌握JavaScript在小程序中的交互场景应用。 5.1JavaScript简介 JavaScript是一种轻量、解释型、支持面向对象编程风格的脚本语言,它是一种直译式、动态类型、弱类型以及基于原型的语言。JavaScript语言不仅可用于Web前端开发,也广泛用于后端开发和智能手机开发。JavaScript的标准是ECMAScript。2015年6月17日,ECMA国际组织发布了ECMAScript 的第六版,该版本正式名称为 ECMAScript 2015,但通常被称为ECMAScript 6 或者ES6。 JavaScript具有以下特性:  JavaScript是一种基于对象的脚本语言,它不仅能够创建对象,而且可以使用对象;  JavaScript是一种轻量级的编程语言;  JavaScript是可插入HTML页面的编程代码;  JavaScript插入HTML页面后,可由现在所有的浏览器执行。 正是由于JavaScript易学易用的特性,使得它在最近几年应用广泛,获得了编程界的好评,同时出现了大量基于JavaScript的开源项目。如今JavaScript不仅可以实现前端的动态交互功能,而且可以运行于后端,为用户提供高性能的后端服务。在微信小程序中,JavaScript是小程序逻辑层使用的唯一开发语言,这也客观反映出JavaScript的强大,因此学好JavaScript对实现前端的交互功能非常重要。 在iOS系统中,小程序的JavaScript代码是运行在JavaScriptCore中,然后由WKWebView来渲染。 在安卓系统中,小程序的JavaScript代码是由X5 JS core来解析,由X5内核渲染。 在微信开发者工具(IDE)中,小程序的JavaScript代码是运行在nw.js中,由Chrome WebView来渲染。其中,nw.js是基于Chromium和Node.js运行的,封装了Webkit内核和Node.js,提供了桌面应用的运行环境,让在浏览器运行的程序也可以在桌面端运行。 这3个运行环境(iOS、安卓和微信开发者工具)使用的ECMA标准是不一样的,目前ECMAScript(简称ES)有8个版本,小程序使用的是ES5和ES6标准。但截至目前,iOS 8和iOS 9并没有完全兼容到ES6的标准,即ES6中的一些语法和关键字不被兼容,所以经常会发现,在微信开发者工具里和手机真机上的代码表现不一致,对此可以用微信开发者工具里的远程调试功能,在真机上进行调试。 5.2JavaScript基础语法 本节将介绍JavaScript的基础语法,包括变量、数据类型、运算符、逻辑控制语句等。 5.2.1变量 变量是存储信息的容器,所有JavaScript变量必须以唯一的名称标识,标识称为变量名。定义变量名称的规则为: 名称可包含字母、数字、下画线; 名称必须以字母开头,对大小写敏感(x和X是不同的变量); JavaScript的关键词不能作为变量名称。 示例代码: var a = 1;//声明变量a并且赋值为数字1 var b = "abc";//声明变量a并且赋值为字符串abc 如上述代码所示,注释是指编程中用于解释说明的部分,用于提高代码的可读性。 JavaScript支持单行注释和多行注释。 单行注释用//标注; 多行注释用/*…*/标注。 5.2.2数据类型 JavaScript变量能够保存多种数据类型: 字符串、数字、逻辑值、数组、对象。本节将逐一介绍。 1. 字符串(String)类型 字符串用于存储一系列字符,使用单引号或双引号包裹字符串的内容。 示例代码: var hello = "Hello xiaochengxu"; var hello = 'Hello xiaochengxu'; 无论是单引号还是双引号,都需要成对出现,不能出现不一致现象,否则在编译时会报错。 2. 数字(Number)类型 JavaScript只有一种数字类型,数值后面的小数点可省略,用科学记数法能够表示极大值和极小值。 var x1 = 1.00;//带小数点 var x2 = 1;//不带小数点 var m = 123e5;//12300000 var n = 123e-5;//0.00123 3. 布尔(Boolean)类型 布尔(逻辑)类型只有两个值: true和false,在使用布尔值时,不能出现"false"或"true",否则会被解析为字符串。 示例代码: var x = true; var y = false; 变量x和变量y都是布尔类型,如果按照下面写法: var x = "true"; var y = "false"; 变量x和变量y都是字符串类型,字符串里面的内容分别为true和false。 4. 数组类型 JavaScript中的数组用方括号书写,数组中的元素由逗号分隔。 示例代码: var list = ["a", "b", "c", "d", "e", "f"]; 上述代码定义一个数组,数组名为list,数组中包含6个元素。数组的索引index从0到数组的个数减1,通过索引值可以取得数组中的元素。例如list[2]可以取得数组中的第3个元素。数组中包含一些常用的方法,在微信小程序中常用的Array对象方法如表5.1所示。 表5.1Array对象方法 方法名说明 pop() 删除并返回数组的最后一个元素 push()向数组的末尾添加一个或更多元素,并返回新的长度 reverse()颠倒数组中元素的顺序 shift()删除并返回数组的第一个元素 slice()从某个已有的数组返回选定的元素 sort() 对数组的元素进行排序 splice() 删除元素,并向数组添加新元素 toString() 把数组转换为字符串,并返回结果 unshift()向数组的开头添加一个或更多元素,并返回新的长度 以表5.1中的push()方法为例,示例代码如下: var fruits = ["Apple", "Banana", "Lemon", "Grape"]; fruits.push("Cherry"); for (var i = 1; i < fruits.length; i++) { console.log(fruits[i]); } 上述代码执行完以后,会在Console控制台输出“Apple,Banana,Lemon,Grape,Cherry”。 5. 对象类型 JavaScript对象用大括号来书写,内容放置在大括号中,对象的属性通过名称和值(name: value)来定义,属性之间用逗号分隔。示例代码如下: var person = { firstName: "tom", age: 23, hairColor: "black" }; 上述代码中对象(person)有3个属性: firstName、age和hairColor。 5.2.3运算符 JavaScript运算符常用于执行算术运算、赋值、比较运算、逻辑运算。 1. 算术运算符 算术运算符用于变量或值之间的算术运算,如表5.2所示。 表5.2JavaScript算术运算符 运算符描述例子 +加x=y+1 -减x=y-1 *乘x=y*1 /除x=y/1 %求余数(保留整数)x=y%1 ++累加x=++y --递减x=--y 对于两个数字型的变量,变量之间使用“+”运算符表示相加; 当两个变量都为字符型,“+”运算符表示字符串的连接; 当一个变量为字符型,另一个变量为数值型,数值型会被解析为字符型进行字符串的连接。 2. 赋值运算符 对变量进行赋值使用赋值运算符,如表5.3所示。 表5.3JavaScript赋值运算符 运算符例子等同于 =x=y +=x+=yx=x+y -=x-=yx=x-y *=x*=yx=x*y /=x/=yx=x/y %=x%=yx=x%y 3. 比较运算符 比较运算符表示变量之间的逻辑关系,如表5.4所示。 表5.4JavaScript比较运算符 运算符描述比较及结果 ==等于5=6为false ===全等(值和类型)5===5为true,5===''5''为false =!不等于5!=6为true >大于5>6为false <小于5<6为true >=大于或等于5>==6为false <=小于或等于5<==6为true 4. 逻辑运算符 逻辑运算符用于确定变量或值之间的逻辑关系,假设x=5 and y=2,逻辑运算符的使用如表5.5所示。 表5.5JavaScript逻辑运算符 运算符描述例子 &&和(x < 10 && y > 1)为true ||或(x == 3 || y == 5)为false !非!(x == y)为true 5.2.4逻辑控制语句 逻辑控制语句分为条件判断语句和循环语句。 1. 条件判断语句 条件判断语句基于分支的思想,面对不同的情况或条件执行相应的选择,通用于某些代码的判断和重复执行。 1) if语句 当小括号内的条件为true时,大括号内部的代码才会执行。语法如下: if (条件) { 当条件为true时才执行该代码 } 示例代码: if (data > 100) { console.log(data) } 上述代码中当变量data值大于100时,会在Console控制台输出这个值。 2) if…else语句 当条件为true时执行if之后的代码,当条件为false时执行else之后的代码。语法如下: if (条件) { 当条件为 true 时执行该代码 } else { 当条件为false时执行该代码 } 示例代码: if (data > 100) { console.log("输入的数字大于100") } else { console.log("输入的数字小于或等于100") } 上述代码中当变量data值大于100时,会在Console控制台输出“输入的数字大于100”,否则,会在Console控制台输出“输入的数字小于或等于100”。 3) if…else if…else语句 在多个代码块中选择满足条件的一个去执行,先判断if条件,如果条件不成立,返回false后判断else if条件,如果条件成立,返回true并执行该条else if后的代码,如果仍不成立,继续判断下一个else if的条件。如果直到else时都没有条件成立,则执行else中的代码。语法如下: if (条件1) { 当条件1为true时执行该代码 } else if (条件2) { 当条件2为true时执行该代码 } else { 当条件1和条件2都为false时执行该代码 } 示例代码: if (data < 60) { console.log("输入的数字小于60") } else if (data >=60 && data <=80) { console.log("输入的数字在60~80中") } else { console.log("输入的数字大于80") } 当变量data值小于60时,执行if之后的代码,会在Console控制台输出“输入的数字小于60”; 当变量data值为60~80时,执行else if之后的代码,输出“输入的数字在60~80中”; 当前面的条件都不满足时,执行else后面的语句,输出“输入的数字大于80”。 4) switch语句 在多个代码块中选择满足条件的一个去执行,判断表达式通常为变量,表达式的值会与case中的值做匹配,如果匹配正确,会执行该case之后的代码块,使用break可以阻止代码继续执行,当条件都不满足时执行default之后的代码。 示例代码: switch (n) { case 1: console.log("今天是星期一") break; case 2: console.log("今天是星期二") break; case 3: console.log("今天是星期三") break; case 4: console.log("今天是星期四") break; case 5: console.log("今天是星期五") break; case 6: console.log("今天是星期六") break; case 7: console.log("今天是星期日") break; default: console.log("输入有误请重新输入") } 当判断条件符合其中某一条件时,在Console控制台输入对应的星期数,然后程序执行break语句跳出循环; 当条件不满足所有case时,会执行default之后的代码,输出“输入有误请重新输入”。 2. 循环语句 循环语句通过判断条件来控制循环的次数,如果需要重复执行相关的动作就需要使用循环语句,循环语句可以提高代码的精简性。 例如,需要输出一个数组的全部元素,不使用循环语句代码如下: console.log(array[0]); console.log(array[1]); console.log(array[2]); console.log(array[3]); 使用循环语句代码如下: for (var i = 0; i < array.length; i++) { console.log(array[i]); } 上述代码通过循环将数组array中的所有元素在Console控制台输出。 1) for循环 for循环是经常使用的循环语句,语法如下: for (语句1; 语句2; 语句3) { 被执行的代码 } 语句1: 在循环开始前执行初始化操作; 语句2: 循环的条件,当返回值为true时,执行循环体,当返回值为false时,跳出该循环; 语句3: 当语句2返回值为true时执行。 示例代码: for (i = 1; i < 10; i++) { console.log(i) } console.log(i) 上述代码会在Console控制台分别输出1到9。 2) for/in循环 for/in循环用于循环对象属性,当循环体中的代码每执行一次,就会对数组的元素或者对象的属性进行一次操作。 示例代码: var person = { firstName: "tom", age: 23, hairColor: "black" }; var string = ""; var x; for (x in person) { string += person[x]; } 输出结果为: tom 23 black。 3) while循环 当条件满足时执行代码块,在每次执行完后会进行条件判断,条件为真会再次执行,直到条件不为真时跳出循环。语法如下: while (条件) { 执行其中的代码 } 示例代码: var i = 1; while (i < 10) { console.log("这是代码执行的第" + i + "次"); i++ } 变量i从初始值1,到不满足循环条件i<10,共执行了9次循环,程序在Console控制台执行了9次语句的输出。 4) do…while循环 首先执行一次do里面的代码块,如果条件为真会重复执行,当条件为假时跳出循环。语法如下: do { 执行其中的代码 } while (条件); 示例代码: var i = 1; do { console.log("这是代码执行的第" + i + "次"); } i++; while (i < 1); 首先执行do里面的代码,然后变量i变为2,不满足while里面的条件直接跳出循环。 5.2.5定义和调用函数 函数的定义使用的关键字是function,示例代码: function functionName(parameters) { 执行的代码 } 在小程序中函数的定义如下: functionName:function(e){ 执行的代码 } 函数的调用是指使用事先定义好的函数,函数本身是一种对象,示例代码: function myFunction(a, b) { return a + b; } myFunction(1, 2);//myFunction(1, 2) 返回值为3 5.2.6小程序中this和that的使用 this是JavaScript语言的一个关键字,可以调用函数。当函数运行时,this可以在函数内部使用,当函数使用场合发生变化时,this的值也会发生变化。在小程序开发中,小程序提供的API接口经常会有success、fail等回调函数来处理后续逻辑。当需要获取当前页面对象来对视图层进行渲染时,this只会指向调用函数的对象,如果想要获取页面的初始数据,在回调函数里面就不能使用this.data来获取,同时也不能使用this.setData()函数来更新数据,而是通过语句var this=that将this指向的对象复制到that中才可以执行后续操作。 5.3JavaScript在小程序中常见的交互场景 JavaScript是小程序编程中的基础语言,从本书附带案例的代码来看,JavaScript代码大约占整个小程序项目一半的代码量。全局文件app.js和所有的页面的JS文件都是由JavaScript来编写的,JavaScript代码主要实现业务逻辑处理和用户交互两方面的作用。52节主要从语法的角度介绍了JavaScript的变量、数据类型、控制语句和函数定义与调用,本节将以JavaScript在小程序中常见的交互场景出发,以案例教学的方式带领读者更深层次地理解JavaScript在小程序编程中的使用。 5.3.1购物车场景 尽管张小龙在2018微信公开课上指出,“小程序不是专门为电商准备的”,但由于强社交属性和微信支付的便捷性,电商成为小程序的重要应用场景。 51电商小程序中经常要用到购物车,购物车是JavaScript在小程序交互场景中的经典应用。本例实现一个简单的购物车,购物车初始状态和用户加购商品之后的购物车状态如图5.1和图5.2所示。 视频讲解 pages/addCaricon/addCaricon.wxml文件代码如下: 1.显示图标小案例 {{totalNum}} 数量 {{num}} + 加入购物车 图5.1购物车初始状态 图5.2加购之后的购物车 pages/addCaricon/addCaricon.js文件代码如下: Page({ data: { num: 1,//数量初始化为1 totalNum: 0,//加入购物车的商品数量初始化为0 hasCart: false,//初始化默认不加入购物车 }, //增加数量 addCount: function() { var num = this.data.num; num++;//数量增加1 this.setData({ num: num//更新数量 }) }, //加入购物车 addCart: function() { const num = this.data.num;//获取数量 var total = this.data.totalNum;//获取总数 this.setData({ hasCart: true,//用于控制加入购物车时的显示图标 totalNum: num + total//累计数量 }) wx.showToast({ title: "加入购物车成功",//弹出消息提示框 duration: 3000, }) }, }) pages/addCaricon/addCaricon.wxss文件代码如下: /*页面盒子*/ .goods-box { position: relative; padding: 0 30rpx; text-align: center; } /*购物车位置*/ .carts-icon { position: absolute; right: 600rpx; top: 490rpx; width: 70rpx; height: 70rpx; } /*购物车图标*/ .carts-icon image { width: 100%; height: 100%; } /*显示加入购物车图标*/ .carts-num { position: absolute; right: 36rpx; width: 40rpx; height: 40rpx; color:white; font-size: 26rpx; line-height: 40rpx; border-radius: 50%; background: #e4393c; } /*加入购物车导航*/ .operation { height: 80rpx; line-height: 80rpx; color:white; border-radius: 50rpx; background: #ff9600; font-size: 30rpx; } /*操作文本*/ .operation text { display: inline-block; height: 80rpx; } /*加入购物车数量*/ .operation-num { width: 160rpx; } /*加入购物车符号*/ .operation-add { width: 80rpx; margin-right: 50rpx; } 【代码讲解】addCaricon.wxml文件中“+”和“加入购物车”两个按钮绑定了点击事件。在addcart.js文件中为“+”按钮定义了事件函数addCount(),用于实现当用户点击“+”按钮时商品数量加1。为“加入购物车”按钮定义的函数addToCart(),用于实现当用户点击“加入购物车”时,一次性向购物车添加num件商品。当用户有加购行为,即点击了“加入购物车”按钮时,hasCart被赋值为true,则在购物车图标的左上角会出现当前购物车商品数量。 5.3.2下拉菜单场景 JavaScript在Web开发中经常被用来实现动态效果,在微信小程序开发者中也存在类似的场景。下拉菜单是JavaScript在小程序中常见的交互场景之一,当用户单击一级菜单时,二级菜单被弹出,当再次单击一级菜单时,二级菜单又消失。 52本例设计常见的小程序下拉菜单,图5.3是二级菜单没有弹出的状态,图5.4是二级菜单弹出的状态。 视频讲解 pages/subMenu/subMenu.wxml文件代码如下: 2.下拉菜单场景小案例 排序 时间 价格 {{item}} 图5.3下拉菜单弹出之前 图5.4下拉菜单弹出之后 pages/subMenu/subMenu.js文件代码如下: Page({ data: { li: ['默认排序', '离我最近', '价格最低', '价格最高'], shownavindex: 0//数据初始化 }, //下拉事件 listmenu: function(e) { if (this.data.openif) { this.setData({ openif: false,//当前菜单没有下拉 shownavindex: 0//控制图标样式 }) } else { this.setData({ content: this.data.li,//获取数组数据 openif: true,//当前菜单下拉 shownavindex: e.currentTarget.dataset.nav//控制图标样式 }) } } }) pages/subMenu/subMenu.wxss文件代码如下: /*页面溢出隐藏*/ .page { overflow: hidden; } /*导航外部样式*/ .nav { position: relative; z-index: 1; display: flex; flex-direction: row; background: white; } /*导航内部样式*/ .nav-item { display: flex; flex: 1; text-align: center; height: 90rpx; align-items: center; justify-content: center; font-size: 30rpx; border: 1px solid gray; } /*导航下拉图标*/ .icon { border: 10rpx solid transparent; border-top: 10rpx solid gray; margin-left: 12rpx; } /*下拉内部样式*/ .list { display: none; width: 100%; overflow-y: scroll; padding: 0 0 0 20rpx; line-height: 100rpx; background: white; } /*下拉内容样式*/ .list view { border-bottom: 1px solid gray; font-size: 32rpx; } /*点击导航内容文字后的样式*/ .nav-item.active .content { color: skyblue; } /*点击导航下拉图标后的样式*/ .nav-item.active .icon { border-bottom: 10rpx solid skyblue; border-top: 0; } /*下拉动画样式*/ .down { display: block; animation: slidown 0.5s ease-in both; } @keyframes slidown { from { transform: translateY(-100%); } to { transform: translateY(0%); } } /*收起动画样式*/ .up { display: block; animation: slidup 0.5s ease-in both; } @keyframes slidup { from { transform: translateY(0%); } to { transform: translateY(-100%); } } 【代码讲解】本例是JavaScript和样式布局结合的案例,在subMenu.js文件中设置初始值shownavindex: 0,使得导航的字体初始值为黑色。当用户点击菜单的时候激活事件函数listmenu(),此时content被赋值使得下拉菜单被弹出,shownavindex从0到1的变化使得一级菜单和向下箭头的样式也发生变化。 5.3.3栏目切换场景 在文章管理或者商品管理小程序中,往往有分类或者栏目的切换,当点击某一栏(某一区域),显示区域的文章和商品被重置为被点击的栏目下的文章和商品。 53本例设计商品栏目的切换效果,右侧显示区域根据左侧栏目的选择来显示对应的内容,运行效果如图5.5和图5.6所示。 视频讲解 图5.5“手机数码”栏目 图5.6“家用电器”栏目 pages/switchTab/switchTab.wxml文件代码如下: 3.栏目切换场景小案例 {{item}} {{item}} pages/switchTab/switchTab.js文件代码如下: Page({ data: { currentTab: 0,//初始化数据 list1: ["手机数码", "家用电器", "运动户外", "优选水果", "食品生鲜", "运动户外", "电脑办公", "体育用品", "美妆护肤"], list2: ["切换到手机数码", "切换到家用电器", "切换到运动户外", "切换到优选水果", "切换到食品生鲜", "切换到运动户外", "切换到电脑办公", "切换到体育用品", "切换到美妆护肤"], }, switchTab: function(e) { var that = this; var id = e.target.id;//获取id if (this.data.currentTab == id) { return//与currentTab值一致返回 } else { that.setData({ currentTab: id//设置currentTab值为id }); } } }) pages/switchTab/switchTab.wxss文件代码如下: /*布局样式*/ .content { display: flex; flex-direction: row; } /*左边样式*/ .left { width: 25%; font-size: 30rpx; } scroll-view { height: 90%; } /*左边元素样式*/ .left view { text-align: center; height: 100rpx; line-height: 100rpx; } /*右边样式*/ .right { width: 75%; } 【代码讲解】本例switchTab.wxml使用flex布局实现栏目和内容的左右分布,左侧是组件,右侧是组件,当用户点击左侧栏目的时候switchTab.js获取栏目的id,并把id赋值给current,此时右侧的组件的第id项被显示,从而实现了左右的同步。本例巧妙地使用了组件的current属性实现内容的切换。 5.3.4系统设置场景 大部分的App和小程序都有系统设置功能,系统设置功能主要是用户输入或者选中数据,JavaScript获取用户设置的数据来修改 视频讲解 系统配置参数。系统设计场景是JavaScript在微信小程序中常见的应用场景。 54本例以辩论赛小程序为背景,系统设置功能可以对立论、驳立论、质辩、自由辩论和总结陈词等环节的辩论时间和倒计时时间进行设置,系统设置页效果如图5.7所示,项目首页简单设计如图5.8所示。 图5.7设置页面 图5.8项目首页 app.js文件代码如下: App({ data: { configs: [{ name: "立论阶段", time: 180, voice: 15 }, { name: "驳立论阶段", time: 180, voice: 15 }, { name: "质辩环节", time: 180, voice: 15 }, { name: "自由辩论", time: 180, voice: 15 }, { name: "总结陈词", time: 180, voice: 15 }]}, onLaunch: function() { wx.setStorageSync('configs',this.data.configs); } }) pages/setting/setting.wxml文件代码如下: 立论阶段 时间限制(秒) 声音提醒 驳立论阶段 时间限制(秒) 声音提醒 质辩环节 时间限制(秒) 声音提醒 自由辩论 时间限制(秒) 声音提醒 总结陈词 时间限制(秒) 声音提醒 pages/setting/setting.js文件代码如下: Page({ data:{ configs:[] }, onLoad:function(options){ var configs = wx.getStorageSync('configs'); this.setData({configs:configs}); }, sliderChange:function(e){ var id = e.target.id; this.data.configs[id].time = e.detail.value wx.setStorageSync('configs', this.data.configs); console.log(this.data.configs) }, radioChange:function(e){ var id = e.target.id; this.data.configs[id].voice = e.detail.value wx.setStorageSync('configs', this.data.configs); console.log(this.data.configs) } }) pages/setting/setting.wxss文件代码如下: /*页面样式*/ page { background-color: skyblue; color: black; } /*标题样式*/ .title { font-size: 40rpx; height: 72rpx; line-height: 72rpx; padding-left: 20rpx; } /*分隔线样式*/ .hr { margin: 12px; width: 100%; height: 1px; background-color: grey; } /*文字样式*/ text { padding-left: 20rpx; font-size: 30rpx; } /*选项样式*/ .item { margin: 12rpx; } /*标签样式*/ .item label { margin: 10px; } pages/index/index.wxml文件代码如下: {{item.name}}设置的参数如下: 时间限制是{{item.time}},倒计时时间是{{item.voice}}秒 pages/index/index.js文件代码如下: Page({ data: { configs: [] }, onShow: function (options) { var configs = wx.getStorageSync('configs'); this.setData({ configs: configs }); }, }) pages/index/index.wxss文件代码如下: .setitem{ height: 30rpx; } view { padding-left: 10rpx; } 【代码讲解】本例中辩论赛数据configs存放在app.js文件中,通过wx.setStorageSync()和wx.getStorageSync()接口实现多个页面之间数据的共享和维护,setting页面的组件输入的数据被事件函数sliderChange()和radioChange()用来修改全局数据configs。项目需注意修改全局数据configs时的下标问题。 视频讲解 5.4实训项目——计算器小案例 本实训项目设计一个计算器,实现了加、减、乘、除运算。程序运行效果如图5.6所示。本项目没有涉及小程序复杂的接口,使用的是第4章样式与布局和第5章JavaScript基础的知识点。项目的设计思路是先编写WXML文件,然后 编写JS接收WXML的数据的代码,再编写加、减、乘、除运算的逻辑代码,最后编写WXSS文件。程序执行效果如图5.9所示。 图5.9计算器示例图 pages/calculator/addList.wxml文件代码如下: {{screenData}} back C +/- ÷ 7 8 9 × 4 5 6 - 1 2 3 + 0 . = pages/calculator/addList.js文件代码如下: Page({ data: { id1: "back", id2: "clear", id3: "negative", id4: "÷", id5: "7", id6: "8", id7: "9", id8: "×", id9: "4", id10: "5", id11: "6", id12: "-", id13: "1", id14: "2", id15: "3", id16: "+", id17: "0", id18: ".", id19: "=", screenData: "0",//屏幕数字初始化 lastInput: false,//控制输入 array: [],//定义一个空数组 }, onclickButton: function(e) { var id = e.target.id; if (id == this.data.id1) {//退格 var data = this.data.screenData; if (data == 0) { return; } data = data.substring(0, data.length - 1);//删除最后一位 if (data == "" || data == "-") {//如果为空或者符号置零 data = 0; } this.setData({ screenData: data }); this.data.array.pop(); this.data.array.push(data); } else if (id == this.data.id2) {//清屏 this.setData({ screenData: "0" }); this.data.array.length = 0; } else if (id == this.data.id3) {//正负号 var data = this.data.screenData; if (data == 0) { return; } var firstWord = data.substring(0, 1); if (firstWord == "-") { data = data.substring(1, data.length);//去掉负号 this.data.array.shift(); } else { data = "-" + data; this.data.array.unshift("-");//增加负号 } this.setData({ screenData: data }); } else if (id == this.data.id19) {//= var data = this.data.screenData; if (data == 0) { return; } var lastWord = data.substring(data.length - 1, data.length); if (isNaN(lastWord)) { return;//最后一位不是数字返回 } var num = "";//定义一个字符串 var lastInput; var array = this.data.array; var optaration = []; for (var i in array) { if (isNaN(array[i]) == false || array[i] == this.data.id18 || array[i] == this.data.id3) { num += array[i];//对小数点或者正负号进行合并处理 } else {//加减乘除单独处理 lastInput = array[i]; optaration.push(num); optaration.push(array[i]); num = ""; } } optaration.push(Number(num)); var result = Number(optaration[0]) * 1.0; for (var i = 1; i < optaration.length; i++) { if (isNaN(optaration[i])) { if (optaration[1] == this.data.id4) {//除运算 result /= Number(optaration[i + 1]); } else if (optaration[1] == this.data.id8) {//乘运算 result *= Number(optaration[i + 1]); } else if (optaration[1] == this.data.id12) {//减运算 result -= Number(optaration[i + 1]); } else if (optaration[1] == this.data.id16) {//加运算 result += Number(optaration[i + 1]); } } } this.data.array.length = 0; this.data.array.push(result); this.setData({ screenData: result + ""//将计算结果赋值用于在屏幕上显示 }); } else { if (id == this.data.id4 || id == this.data.id8 || id == this.data.id12 || id == this.data.id16) { if (this.data.lastInput == true || this.data.screenData == 0) { return;//开始不允许输入加减乘除 } } var vd = this.data.screenData; var data; if (vd == 0) { data = id; } else { data = vd + id;//用于连续输入数字 } this.setData({ screenData: data }); this.data.array.push(id); if (id == this.data.id4 || id == this.data.id8 || id == this.data.id12 || id == this.data.id16) { this.setData({ lastInput: true }); } else { this.setData({ lastInput: false }); } } } }) pages/calculator/addList.wxss文件代码如下: /*外部布局*/ .demo-box { background-color: black; padding: 10rpx; } /*输入框样式 */ .input-screen { background-color: white; border-radius: 20rpx; text-align: right; width: 710rpx; height: 120rpx; line-height: 120rpx; padding-right: 20rpx; margin-bottom: 40rpx; } /*按钮布局方式*/ .btn-group { display: flex; flex-direction: row; } /*按钮样式*/ .item { width: 150rpx; height: 150rpx; margin: 15rpx; border-radius: 100rpx; text-align: center; line-height: 150rpx; } /*按钮0样式*/ .item1 { width: 320rpx; height: 150rpx; margin: 10rpx; border-radius: 100rpx; text-align: center; line-height: 150rpx; } /*颜色样式*/ .green { color: #f7f7f7; background: #7ccd7c; } /*颜色样式*/ .blue { color: #f7f7f7; background: #0095cd; } 【代码讲解】本项目在addList.wxml文件和addList.wxss文件中完成页面的布局,为每个按钮绑定点击事件; 在JS文件中首先设置允许连续输入操作数并且不允许连续输入操作符,然后分别为每个按钮设置交互功能,包括退格、清零和正负号,接着定义等号的交互,数字在连续输入时将中间结果保存在数组中,最后实现加减乘除运算。由于考虑到篇幅问题,设计功能完整的计算器代码较多,故没有涉及运算的优先级处理,有兴趣的读者可以自行修改本项目。