微信小程序开发——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函数

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

相关推荐
Simon—欧阳1 小时前
微信小程序真机调试时如何实现与本地开发环境服务器交互
服务器·微信小程序·小程序
FE_C_P小麦10 小时前
AI中国象棋双人游戏开发尝试:AI_Grok
前端·微信·微信小程序
obiwan1 天前
Jenkins CI/CD 自动化构建部署微信小程序体验版
微信小程序
^Rocky2 天前
微信小程序(uniapp)实现腾讯云 IM 消息撤回
微信小程序·uni-app·腾讯云
疯狂的沙粒2 天前
uniapp开发企业微信小程序时 wx.qy.login 在uniapp中使用的时候,需要导包吗?
前端·javascript·微信小程序·小程序·uni-app
1099054182 天前
微信小程序进阶第2篇__事件类型_冒泡_非冒泡
微信小程序
疯狂的沙粒3 天前
uniapp 开发企业微信小程序时,如何在当前页面真正销毁前或者关闭小程序前调用一个api接口
微信小程序·小程序·uni-app
山河故人1633 天前
UniApp微信小程序自定义导航栏实现
微信小程序·uni-app·notepad++
魔术师ID3 天前
微信小程序学习目录
学习·微信小程序·小程序