微信小程序开发——Skyline中Worklet动画

Skyline简单介绍

Skyline是微信小程序的新的渲染引擎,其相比于Webview引擎拥有更好的性能,同时也支持更多原生的新特性,比如Worklet动画、路由跳转的转场动画、共享元素动画、全局工具栏等,这些新特性都可以让小程序拥有更加丝滑的操作,以及转场。小编在此非常推荐大家去使用Skyline进行自己的小程序开发。

Skyline目前支持按页面去升级,也就是部分页面可以继续使用Webview,部分可以使用Skyline,具体的配置方法可以参考官方文档:Skyline 渲染引擎 / 从 WebView 迁移 / 起步

本文主要介绍如何使用Skyline的Worklet动画,让你的小程序交互性能更加流畅。

Skyline的线程模型

在讲Worklet动画之前,我们先了解下Skylilne的线程模型。不同于Webview的单线程模型,Skyline改成了双线程模型,将js逻辑、DOM树构建,CSS样式计算单独放到了AppService线程,简称JS线程,而应用样式、布局(Layout)和绘制(Paint)则放在一个渲染线程,简称UI线程,以下是其架构图:

分开成两个线程后,当有需要在JS线程计算动画的过程,而在UI线程进行展示,两者直接很难去协调同步,容易出现动画不流畅的问题。因此微信小程序就提供了Worklet动画来解决这个问题。

什么是Worklet动画

Worklet动画有两个核心概念,分别是Worklet函数,和Worklet共享变量。

Worklet函数

Worklet函数就是一种既可以在JS线程中运行,也可以在UI线程中运行的函数。

Worklet函数的定义就是在函数的顶部加上'worklet'字符串标志:

scss 复制代码
function someWorklet(greeting) {
  'worklet';
  console.log(greeting);
}

// 运行在 JS 线程
someWorklet('hello') // print: hello

// 运行在 UI 线程
wx.worklet.runOnUI(someWorklet)('hello') // print: [ui] hello

Worklet函数间可以直接相互调用:

javascript 复制代码
const name = 'worklet1'

function anotherWorklet() {
  'worklet';
  return 'hello ' + name;
}

// worklet 函数间可互相调用
function someWorklet() {
  'worklet';
  const greeting = anotherWorklet();
  console.log('another worklet says ', greeting);
}

wx.worklet.runOnUI(someWorklet)() // print: [ui] another worklet says hello worklet1

Worklet函数通过wx.worklet.runOnJS来调用普通函数:

scss 复制代码
function someFunc(greeting) {
  console.log('hello', greting);
}

function someWorklet() {
  'worklet'
  // 访问非 worklet 函数时,需使用 runOnJS
  // someFunc 运行在 JS 线程
  wx.worklet.runOnJS(someFunc)('js function')
}

wx.worklet.runOnUI(someWorklet)() // print: hello js function

需要注意的是,Worklet函数不能直接调用普通的函数,需要通过wx.worklet.runOnJS来运行普通的函数,让其在JS线程中运行。

Worklet共享变量

Worklet共享变量就是在JS线程中创建,并且可以在JS线程和UI线程中共享使用的变量。

scss 复制代码
const { shared, runOnUI } = wx.worklet

const offset = shared(0)
function someWorklet() {
  'worklet'
  console.log(offset.value) // print: 1
  // 在 UI 线程修改
  offset.value = 2
  console.log(offset.value) // print: 2
}
// 在 JS 线程修改
offset.value = 1

runOnUI(someWorklet)()

Worklet的实际使用场景

我们结合下前两节的Worklet函数和Worklet共享变量,看下在实际的使用场景。我们开头提到过,Worklet动画解决的就是动画函数在JS线程和UI线程之间协调时导致的卡顿问题。那么我们来看看这个问题是如何使用Worklet动画去解决的。

驱动动画

bash 复制代码
<view id="moved-box"></view>
<view id="btn" bind:tap="tap">点击驱动小球移动</view>
javascript 复制代码
Page({
  onLoad() {
    const offset = wx.worklet.shared(0)
    this.applyAnimatedStyle('#moved-box', () => {
      'worklet';
      return {
        transform: `translateX(${offset.value}px)`
      }
    })
    this._offset = offset
  },
  tap() {
    // 点击时修改 sharedValue 值,驱动小球移动
    this._offset.value = Math.random()
  }
})

当点击按钮 #btn 时,我们用随机数给 offset 进行赋值,小球会随之移动。

applyAnimatedStyle 接口的第二个参数 updater 为一个 worklet 函数,其捕获了共享变量 offset,当 offset 的值变化时,updater 会重新执行,并将返回的新 styleObject 应用到选中节点上。

当然,光看这个例子,跟用 setData 看好像没有什么区别。但当 worklet 动画和手势结合时,就产生了质变。

结合手势系统

ini 复制代码
<pan-gesture-handler onGestureEvent="handlepan">
  <view class="circle"></view>
</pan-gesture-handler>
ini 复制代码
Page({
  onLoad() {
    const offset = wx.worklet.shared(0);
    this.applyAnimatedStyle('.circle', () => {
      'worklet';
      return {
        transform: `translateX(${offset.value}px)`
      };
    });
    this._offset = offset;
  },
  handlepan(evt) {
    'worklet';
    if (evt.state === GestureState.ACTIVE) {
      this._offset.value += evt.deltaX;
    }
  }
});

当手指在 circle 节点上移动时,会产生平滑的拖动效果。handlepan 回调触发在 UI 线程时修改了 offset 的值,而offset值改变的时候会触发this.apppAnimatedStyle的updated函数,并修改.circle的style的transform的值,触发了circle 节点的移动,整个过程都是在UI线程中进行,没有JS线程和UI线程的切换,从而让动画更加的平滑顺畅。

手势系统中的回调handlepan必须是Worklet函数

关于手势系统,我们会在接下来的文章中详细介绍。

相关推荐
特严赤傲16 小时前
uniappx 开发微信小程序 腾讯地图偏移量计算
微信小程序·uts·uniappx·地图偏移量
星光一影18 小时前
打车/网约车、代驾、顺风车/拼车、货运、租车等多种出行服务的一站式解决方案
mysql·微信小程序·php·uniapp·html5·web app
QuantumLeap丶1 天前
《uni-app跨平台开发完全指南》- 04 - 页面布局与样式基础
vue.js·微信小程序·uni-app
www_stdio1 天前
微信小程序入门:从零构建一个 Blog 小程序
微信·微信小程序
inx1771 天前
微信小程序开发实战:从结构到数据绑定的完整实现
javascript·微信小程序
云起SAAS2 天前
黄历万年历择吉日抖音快手微信小程序看广告流量主开源
微信小程序·小程序·ai编程·看广告变现轻·黄历万年历择吉日
腾讯云云开发2 天前
小程序数据库权限管理,一看就会!——CloudBase新手指南
前端·数据库·微信小程序
有点笨的蛋2 天前
从零搭建小程序首页:新手也能看懂的结构解析与实战指南
前端·微信小程序
一只小白菜~2 天前
记录一下微信小程序里使用SSE
微信小程序·小程序·sse·小程序sse·小程序eventsource
李慕婉学姐2 天前
【开题答辩过程】以《基于微信小程序垃圾分类图像识别技术实现》为例,不会开题答辩的可以进来看看
spring boot·微信小程序·vue