神的尾巴

全栈工程师、独立开发者

0%

uni-app之WXS指南

​ 当我们使用 uni-app 开发应用时,会发现想要实现一个高性能的下拉刷新或滑动删除效果,动画经常会非常卡顿。

为什么会卡顿呢?这个和 uni-app(vue)的实现原理有关。

因为 uni-app 在大部分平台实现思路和微信小程序一致,所以我们这里以微信小程序为例看一下:

微信小程序的渲染层和逻辑层分别由 2 个线程管理。

之所以分为逻辑层和渲染层,主要是为了管控,让开发者的代码只运行在逻辑层。

渲染层的界面使用了 WebView 进行渲染;逻辑层采用 JsCore 线程运行 JS 脚本。一个小程序存在多个界面,所以渲染层存在多个 WebView 线程,这两个线程的通信会经由 Native(微信客户端)做中转,逻辑层发送网络请求也经由 Native 转发。

由于交互动画,需要渲染层高频率的触发事件,逻辑层接收事件后,又需要把事件处理后的结果传递给渲染层,从而产生交互动画。

这中间频繁的通信,是影响性能的主要原因。

So,知道原因后,我们看下,uni-app/微信小程序是如何解决这个问题的。

解决方案:

我们核心思路就是减少通信,让开发者部分受管控代码能够运行在视图层,于是就有了 WXS,因为 WXS 是运行在渲染层的逻辑代码,所以和原始的逻辑层与渲染层通信的方式会不一样,这个后面会有专门的介绍。

WXS 入门指南

哪些平台支持 WXS

uni-app 的 WXS 目前支持以下几端:微信小程序、QQ 小程序、App-vue、h5。

使用 WXS 的一些限制:

  1. 目前只能响应内置组件事件、不支持自定义组件事件;
  2. 目前还不支持原生组件的事件、input 和 textarea 组件的 bindinput 事件;
  3. 只能使用 setStyle 和 setClass 进行动画设置。

目前字节跳动、百度、支付宝小程序所使用的 SJS,大部分都是配合模板使用,能支持更多渲染场景和优化渲染性能。

但是相比于 WXS 会有一些限制:

  1. 只能外部引用,不支持内联;
  2. 函数不能作为组件事件回调。

也就是说,目前,SJS 可以实现一些高性能的模板渲染解析,但是不能用于实现高性能动画。

如何使用 WXS

支持内联和外部引用

1
2
3
4
5
6
<!-- 内联 -->
<script module="test" lang="wxs">

<script>
<!-- 外部引用 -->
<script src="../../tools.wxs" module="test" lang="wxs"/>

有几个要注意的点

  1. module 所指定的模块名不可与 data、methods、computed 内的属性重名;
  2. nvue 不支持 wxs,建议使用 bindingx。

WXS 事件通讯

组件事件监听、change:prop 与 callMethod 是组件/页面 与 wxs 模块双向通讯方式。

如上图所示,通讯流程如下

  1. 首先在页面/组件,注册事件处理函数,绑定 prop 和 propChange 处理函数;
  2. 然后页面/组件修改 data 触发 change:prop;
  3. wxs 响应 change:prop 事件,进行一些初始化操作;
  4. 用户操作页面,wxs 响应注册事件,调用 setClass、setStyle 修改动画属性;
  5. 完成状态迁移后,调用 callMethod 或 triggerEvent 进行状态处理。

需要注意的点

  1. callMethod、triggerEvent 参数不允许设置 function,所以无法通过传递回调函数,进行回调操作,可以通过 change:prop 完成相关回调通知。

WXS 使用示例

touchmove 事件监听、prop:change 监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<template>
<view class="content">
<view
:prop="prop"
:change:prop="test.propObserver"
@touchmove="test.touchMove"
class="item"
>
</view>
</view>
</template>

<script module="test" lang="wxs">
var enable = false
module.exports = {
// 监听touchMove事件
touchMove(event, instance) {
console.log(event, instance)
// 返回false,不往上冒泡,相当于调用了同时调用了stopPropagation和preventDefault
},
// 监听prop修改
propObserver(newValue, oldValue, ownInstance, instance) {
console.log(newValue, oldValue, ownInstance, instance)
}
}
</script>

<script>
export default {
data() {
return {
prop: {
enable: false,
},
};
},
onLoad() {
setTimeout(() => {
// 修改prop
this.prop.enable = true;
}, 500);
},
};
</script>

<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

.item {
margin-top: 200rpx;
height: 200rpx;
width: 200rpx;
background: #007aff;
}
</style>

那今天关于 WXS 的入门指南就到这啦,想了解更多详细信息,可以参考下面的官方文档:

  1. 微信 wxs 官方文档(语法): https://developers.weixin.qq.com/miniprogram/dev/reference/wxs/
  2. 微信 wxs 官方文档(响应事件):https://developers.weixin.qq.com/miniprogram/dev/framework/view/interactive-animation.html
  3. uni-app wxs 文档:https://uniapp.dcloud.io/frame?id=wxs
觉得对你有帮助的话,请我喝杯咖啡吧~.