WXS 是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。
WXS 代码可以编写在 WXML 文件中的
标签内或以 .wxs
为后缀名的文件内。每一个
标签和 .wxs
文件都是一个单独的模块,每个模块都有自己独立的作用域,即在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见。
WXML 和 WXS 直接在渲染层进行通讯,性能开销很低。因此 WXS 可以解决在某些场景下,频发地数据绑定以及页面与 JS 通信的性能问题,还能为页面提供一些工具方法来简化开发。
小程序的框架分为视图层(Webview)和逻辑层(App Service)。WXS 是运行在视图层的。
在单个 WXML 文件内,module 模块名需要唯一,否则后面的将会覆盖前面的。但是不同文件之间的 wxs 模块名不会相互覆盖。
wxs 模块均为单例,wxs 模块在第一次被引用时,会自动初始化为单例对象。多个页面,多个地方,多次引用,使用的都是同一个 wxs 模块对象。
如果一个 wxs 模块在定义之后,一直没有被引用,则该模块不会被解析与运行。
标签内。
// 导出 wxs 模块
// module 是当前 标签的模块名
// 每个 wxs 模块均有一个内置的 module 对象,一个 wxs 模块要想对外暴露其内部的私有变量与函数,只能通过 module.exports 实现
module.exports = {
msg : "hello world",
}
// 引用 wxs 模块
{{utils.msg}}
.wxs
为后缀名的文件内。// utils.wxs
// 导出 wxs 模块
// 每个 wxs 模块均有一个内置的 module 对象,一个 wxs 模块要想对外暴露其内部的私有变量与函数,只能通过 module.exports 实现。
var getMsg = function() {
console.log("hello world")
}
module.exports = {
getMsg: getMsg,
}
// 引入 wxs 模块
// module 是当前 标签的模块名。src 是被引用的 wxs 文件的相对路径,仅当 标签为单闭合标签或空标签时有效。
// 绑定的 WXS 函数必须用{{}}括起来
按钮
.wxs
文件不仅可以被 WXML 中的
标签引用,还可以使用 require 函数被其他的 .wxs
文件引用。// tools.wxs
var utils = require("./utils.wxs");
console.log(utils.getMsg());
WXS 与 JavaScript 是不同的语言,有自己的语法,并不和 JavaScript 一致。
WXS 中不支持 let 和 const;不支持箭头函数。
WXS 的运行环境和其他 JavaScript 代码是隔离的,WXS 中不能调用其他 JavaScript 文件中定义的函数,也不能调用小程序提供的API。
由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异。
WXS 主要有 3 种注释的方法:
// 方法一:单行注释
/*
方法二:多行注释
*/
/*
方法三:结尾注释。即从 /* 开始往后的所有 WXS 代码均被注释
WXS 语言目前共有以下几种数据类型:string、number、boolean、object、array、function、date、regexp。
生成 date 对象需要使用 getDate 函数, 返回一个当前时间的对象。
var date = getDate(1500000000000);
生成 regexp 对象需要使用 getRegExp函数。
var reg = getRegExp('(\d)(?=(?:\d{3}[+]?)+$)','g');
数据类型判断可以使用 constructor 属性,也可以使用 typeof 区分部分数据类型。
var string = "str";
console.log( string.constructor === "String" )
var func = function(){};
console.log( func.constructor === "Function" )
var object = {};
console.log( typeof object === 'object' );
var func = function(){};
console.log( typeof func === 'function' );
不支持 let 和 const 声明变量。
大致和 JS 中相同。
支持 if 语句、switch 语句、for 语句、while 语句、do while 语句。
不支持箭头函数。
可以使用 WXS 函数响应事件。WXS 函数接受 2 个参数:
event.instance
对象来表示触发事件的组件的 ComponentDescriptor 实例。目前 WXS 函数只能响应内置组件的事件,不支持响应自定义组件的事件。还不支持原生组件的事件、input 和 textarea 组件的 bindinput 事件。(2022.10.07)
// index.wxml
// 在 WXML 视图层中的组件上绑定事件处理的 WXS 函数
// touchmove.wxs
// 在 WXS 中义并导出事件处理函数
function handleTouchmove(event, ownerInstance) {
console.log(event)
}
module.exports = {
handleTouchmove: handleTouchmove
}
可以通过 WxsPropObserver 在引用该 WXS 的组件/页面的 JS 逻辑层中调用 WXS 中定义的函数。
可以通过 WXS 中 ComponentDescriptor 实例的 callMethod 方法直接调用引用该 WXS 的组件/页面的 JS 逻辑层定义的函数。
// index.wxml
// change:prop(属性前面带 change: 前缀)是在 prop 属性被设置的时候触发 WXS 函数,初始化时也会调用一次,类似 Component 定义的 properties 里面的 observer 属性
// index.js
Page({
data: {
prop: '',
},
handlePageTouchmove() {}
})
// touchmova.wxs
module.exports = {
handleWxsTouchmove: function (event, ownerInstance) {
// 可以通过 callMethod 方法来调用当前组件/页面在 JS 逻辑层定义的函数。
event.instance.callMethod('handlePageTouchmove')
},
// 当 prop 被设置的时候会触发 propObserver 函数
propObserver: function(newValue, oldValue, ownerInstance, instance) {
console.log('prop observer', newValue, oldValue)
}
}
可以通过 WXS 中 ComponentDescriptor 实例的 triggerEvent 方法来触发引用该 WXS 的自定义所在的父组件或页面中的事件,和组件的 triggerEvent 一致。
callMethod 是调用引用该 WXS 的组件/页面内部自身的方法。
triggerEvent 是触发引用该 WXS 的组件外部别人的方法,即引用该 WXS 的组件所在组件/页面的方法。
有频繁用户交互的效果在小程序上表现是比较卡顿的。例如页面有 2 个元素 A 和 B,用户在 A 上做 touchmove 手势,要求 B 也跟随移动。
一次 touchmove 事件的响应过程为:
也就是,一次 touchmove 的响应需要经过 2 次的逻辑层和渲染层的通信以及一次渲染,通信的耗时比较大。而且 setData 渲染也会阻塞其它脚本执行,导致了整个用户交互的动画过程会有延迟。
可以使用 WXS 函数用来响应小程序事件。让事件在视图层响应,从而减少通信的次数达到性能的优化。