TOC
WXML
在小程序的WXML语法类似HTML语法,在WXML内,组件可以写成单标签模式,也可以写成双标签模式,那么要不要写成双标签,取决于是否需要在组件内包含其他内容,但是,需要注意的是,在WXML内,大小写是敏感的,比如class和Class是不同的属性,这一点需要注意;
在开发中,WXML内的内容通常情况下,都不是写死的,而是会根据服务器返回的结果来动态渲染内容,或者通过用户的操作行为来填充内容,所以,小程序和Vue一样,提供了Mustache的插值语法,通过这样的语法,可以将当前页面Page函数参数对象内的data对象内的属性动态的展示到页面中来;
Mustache语法
Mustache语法其实没什么好说的,它和Vue中的Mustache语法,基本一样,只不过在小程序内,Mustache语法并不能使用相关的一些数据处理函数对数据进行进一步处理,其他的使用方面没有太大的差别,如下;
// pages/page/page.js
Page({
data: {
name: "cce",
num1: 1,
num2: 2
}
})
<!-- pages/page/page.wxml -->
<view>
<text>{{name}}</text>
</view>
<view>
<text>{{num1 + num2}}</text>
</view>
<view>
<text>{{1+2}}</text>
</view>
- 注意:
如果我们希望在组件属性上、wx:if、wx:for等属性使用Page函数的对象参数内的data对象中的数据,那么一样,需要使用Mustache语法,如果不使用Mustache语法默认为字符串类型,同样的,如果我们希望属性的参数是一个非字符串类型,比如数字,那么我们一样需要使用Mustache语法来表示;
条件判断
在小程序的WXML内,一样也支持条件判断,即if/else语句,同样支持单分支和多分支,对比Vue,只是在语法上稍有差别,在某些情况下,我们可能需要根据条件来决定一些内容是否渲染,这个时候,我们就可以直接使用条件判断来实现;
<!-- pages/page/page.wxml -->
<view wx:if="{{false}}">1</view>
<view wx:elif="{{false}}">2</view>
<view wx:elif="{{false}}">3</view>
<view wx:else>null</view>
hidden属性
hidden属性,它就是用来指定元素是否在页面中显示的一个属性,其实它内部就是通过display: none来实现的,当hidden属性为true时,则隐藏组件,反之显示组件;
循环语句
在小程序内,同样的,有循环语句,同样的,它也Vue模版语言中的循环语句非常相似,在小程序的循环语句,为了在冲洗你渲染是能够优化性能,当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率;
所以也需要给每一个迭代出的组件加上一个wx:key属性,该属性一般会指定一个能够唯一识别当前迭代出来的对象的一个属性,比如id,但是我们需要指定,这个id并不需要使用Mustache语法包裹,直接给定一个字符串即可,它会自动去迭代出来的对象里面去寻找这个id属性,如下;
// pages/page/page.js
Page({
data: {
userinfo: [
{ id: 1, name: "cce" },
{ id: 2, name: "cfj" }
]
}
})
<!-- pages/page/page.wxml -->
<view wx:for="{{userinfo}}" wx:key="id">
<text>{{ item.name }}</text>
</view>
此外,对于wx:key官方也提供了另外一种特殊的语法,即*this,它代表的就是item,即当前迭代出来的对象,只不过,相比item而言,使用*this,我们无需使用Mustache语法包裹;
但是,这里唯一需要注意的是,*this,或item,不能是一个对象,只能是一个数字或者字符串,否则这样写是无效的,如下示例;
// pages/page/page.js
Page({
data: {
userinfo: [
{ name: "cce" },
{ name: "cfj" }
]
}
})
<!-- pages/page/page.wxml -->
<view wx:for="{{userinfo}}" wx:key="*this">
<text>{{ item.name }}</text>
</view>
索引
对于小程序来讲,它的WXML语言中的循环语句,默认会为每一个循环出来的对象,赋予一个index,即,当前迭代出来对象在容器内的索引值;
<!-- pages/page/page.wxml -->
<block wx:for="{{userinfo}}" wx:key="*this">
<text>{{ index }}</text>
</block>
// pages/page/page.js
Page({
data: {
userinfo: [
{ name: "cce" },
{ name: "cfj" }
]
}
})
标识符重命名
可以看到,在小程序内,通过wx:for循环出来的对象的标识符为item,那么在某些特殊的场景下,比如多层循环,外层循环迭代出来的对象称之为item,内层循环迭代出来的对象也称之为item,这肯定会产生问题,所以小程序给我们提供了一个方法,我们可以通过wx:for-item来指定这个迭代出来对象的标识符,如下示例;
<block wx:for="{{2}}" wx:key="*this" wx:for-item="number">
<text>{{ number }}</text>
</block>
一样的,对于索引,迭代出来每一个对象的索引标识符为index,我们也可以使用wx:for-index来指定每个索引的标识符,如下示例;
<!-- pages/page/page.wxml -->
<block wx:for="{{2}}" wx:key="*this" wx:for-item="number" wx:for-index="i">
<text>{{ number }}-{{i}}</text>
</block>
WXS
在小程序里面,给我们提供了一种新的脚本语言,即WXS(WeiXin Script),它是小程序的转有脚本语言,它结合WXML可以构建出一个完整的页面结构,官方说明,WXS和JavaScript是不同的语言,有自己的语法结构,和JavaScript并不一样,但是通过测试,基本上是一致的,所以从这里来看,我们可以认为WXS是小程序内JavaScript的一个变种,其诞生主要是为了解决一些特殊的场景;
应用场景
在学过Vue的模版语言,我们可以知道,我们在模版语言中,使用Mustache语法是非常灵活的,不仅可以直接给定一个响应式数据的标识符,还可以调用JavaScript方法、自定义函数来包装这个数据,比如{{ name.toString() }},但是在小程序内这样是不支持的;
主要原因是因为小程序是一个双线程模型,WXML和JS是运行在不同的线程当中的,如果实现这样的一个功能必定会涉及到两个线程之间来回交互,带来了一定的性能损耗;
所以就提出了WXS,WXS就完全可以解决这种问题,WXS定义的所有脚本,都将和WXML运行在一个线程内,也就是说,它就完全解决了多线程间的数据共享问题,但是我们需要知道的是,还是不要在WXS里面编写过于复杂的逻辑,因为官方设计出双线程模型就是规避脚本语言带来的线程阻塞问题,所以WXS也一样,尽量规避在WXS里面加入设计到线程阻塞的逻辑,所以在WXS一般仅做简单的运算;
限制及特点
WXS不依赖于运行时的基础库版本,可以在所有版本的小程序中运行,WXS的运行环境和JavaScript代码是隔离的,WXS中不能调用其他JavaScript文件中定义的函数,也不能调用小程序提供的API;
由于运行环境的差异,在IOS设备上的小程序运行WXS会比JavaScript代码快2~20倍,在Android设备上,二者运行效率无差异;
编写格式
WXS脚本编写主要有两种方式,可以直接将WXS脚本编写在WXML内,以wxs组件包裹,同时,也可以直接将WXS脚本存放于以wxs为后缀的文件内;
WXML内嵌模式
如果直接将WXS脚本内嵌到WXML文档内,我们需要使用到一个wxs组件,同时为了解决一个WXML文件内有多个wxs组件,所以在wxs组件上有一个必给定的属性,即module,我们需要为每一个wxs组件给定一个唯一模块名称,同时为了能够使wxs组件内的脚本被WXML文本引用,我们还必须使用CommonJS的方式,将对应的函数、变量等标识符导出,这些导出的标识符,都将存在于以module为标识符的对象内,所以我们在调用时,必须使用module的值,以对象的方式调用;
这里唯一需要注意的是,在WXS内,不允许存在ES6及以上ES版本的语法,如下示例;
<!-- pages/page/page.wxml -->
<view>
<block wx:for="{{books}}" wx:key="name">
<view>
<text decode>书名:{{ item.name }} 价格:{{ tools.getPrice(item.price) }}</text>
</view>
</block>
</view>
<wxs module="tools">
function getPrice(price) {
return "¥" + price
}
module.exports = {
getPrice: getPrice
}
</wxs>
文件模式
除了直接在WXML文件内内嵌之外,我们可以可以将这些WXS脚本代码提取出来,然后将WXS脚本的内容放在以wxs后缀的文件中也是可以的,当然,即使使用文件模式,一样需要使用module.exports进行相关需要引用的标识符导出;
那么在文件模式下,如果我们希望将这个WXS脚本在WXML内使用,我们一样需要使用一个wxs组件,并且,一样需要给定一个module属性给这个模型定义一个名称,然后以模块的方式在Mustache语法内使用,同时,为了能够找到对应的WXS文件,我们还需要使用到一个src属性,来指定WXS脚本的位置,如下示例;
<!-- pages/page/page.wxml -->
<wxs module="tools" src="/tools/get_price.wxs" />
<view>
<block wx:for="{{books}}" wx:key="name">
<view>
<text decode>书名:{{ item.name }} 价格:{{ tools.getPrice(item.price) }}</text>
</view>
</block>
</view>
// /toos/get_price.wxs
function getPrice(price) {
return "¥" + price
}
module.exports = {
getPrice: getPrice
}
变量定义
在WXS中,变量均为引用,没有声明的变量直接赋值使用,会被定义为全局变量,如果只声明变量而不赋值,则默认值为undefined,定义变量需要使用var关键字来定义局部变量,同样的,它与javascript一致,都会有变量提升;
运算符
在WXS内,也支持众多的运算符,基本上都是继承了JavaScript语言中的一些特性,在WXS中,分基本运算符、一元运算符、位运算符等,如下;
# 基本运算符
+:加法运算符;
-:减法运算符;
*:乘法运算符;
/:除法运算符;
%:取余运算符;
# 一元运算符
++:自加运算符;
--:自减运算符;
+n:正值运算符;
-n:负值运算符;
~n:否运算符;
!n:取反运算符;
# 位运算符
&:与运算符;
^:异或运算符;
|:或运算符;
# 比较运算符
>:大于运算符;
<:小于运算符;
>=:大于等于运算符;
<=:小于等于运算符;
# 等值运算符
==:等于运算符;
!=:非等于运算符;
===:全等于运算符;
!==:非全等于运算符;
# 赋值运算符
=:赋值运算符;
# 二元运算符
&&:逻辑与;
||:逻辑或;
逻辑判断
在WXS语言内,也支持逻辑判断语句,一样支持单分支、多分支等语法,如下语法示例;
if (表达式) {
代码块;
} else if (表达式) {
代码块;
} else if (表达式) {
代码块;
} else {
代码块;
}
选择判断
在WXS语言内,也支持switch语句,可以实现不同的参数,执行不同的逻辑操作,如下语法示例;
switch (表达式) {
case 变量:
语句;
case 数字:
语句;
break;
case 字符串:
语句;
default:
语句;
}
循环迭代
同样的,WXS作为一门脚本语言,同样支持For、While和While Do三大循环语句,但是需要注意的是,对于For循环它不支持ES5以上的如for...of或者for...in等语法,如下示例;
# For循环
for (语句; 语句; 语句) {
代码块;
}
# While循环
while (表达式){
代码块;
}
# While Do循环
do {
代码块;
} while (表达式)
数据类型
在WXS内,支持八种数据类型和基础类库,一眼看去,可以看到基本上和JavaScript相差无几,都是差不多的,具体的请查看官方文档;
WXS数据类型
WXS基础类库