随笔

View Transition API

新鲜的知识又来啦,昨天从信息流刷到 Google 的一个视频,其中提到了 View Transition API,一看效果就是前两年 Android 上面流行的无缝衔接动画,稍微尝试了下效果。

首先,目前这还是一项实验型的技术,只有 Chrome 111+ 才支持,之后 API 也可能会变,并且目前只支持 SPA 应用的跨页动画,据说目标是实现普通网站的跨页动画。

如果真能实现实现普通网站的跨页动画,那么我的博客就可以从首页的列表在跳到详情时,博客的 banner 和 title 都可以产生一个连贯的衔接效果。

主要的核心点是操作时通过调用 startViewTransition 来使浏览器产生一个快照,在回调函数里面执行更新 DOM 操作,最后对比之前保存的快照和更改后的快照来产生动画效果,通过使用相同的 view-transition-name 属性关联动画前后的元素。

浏览器默认实现了一些如淡入淡出,大小或位置变化的动画,如果想要实现一些较复杂的动画,也可以通过使用 animation 来自定义过度动画。

直接上代码:

import './index.css'

import { useRef, useState } from 'react'
import { flushSync } from 'react-dom'

export default function Index () {
  const [active, setActive] = useState(true)
  const bigImgRef = useRef()
  const imgUrl = '/images/child-find.svg'

  const handleToggle = () => {
    document.startViewTransition(() => {
      flushSync(() => {
        setActive(!active)
      })
    })
  }

  return (
    <div>
      <div>
        <button onClick={handleToggle}>Toggle</button>
      </div>
      {active && <img
        src={imgUrl}
        style={{
          width: 50,
          viewTransitionName: 'name'
        }} /> }

      {!active && <img
        src={imgUrl}
        style={{
          width: 50,
          marginLeft: 200,
          viewTransitionName: 'name'
        }} />}
    </div>
  )
}

一个典型的 React 页面,点击按钮切换显示图片,切换时产生了动画过渡效果,视频如下:

然后再实现一个自定义过渡动画的效果:

@keyframes old {
    from {
        transform: scale(1);
    }

    to {
        transform: scale(1.5);
    }
}

@keyframes new {
    0% {
        transform: rotateZ(45deg);
    }

    50% {
        transform: rotateZ(-45deg);
    }

    100% {
        transform: rotateZ(0deg);
    }
}


::view-transition-old(name) {
    animation: 1s ease old;
}

::view-transition-new(name) {
    animation: 1s 1s ease new;
}

如果你是用的 react 里面的 lazy load, 那么可能无法触发动画效果,因为该回调需要同步方法,异步可能需要加 sleep 来确保内容已经被载入

就目前效果来讲还是有些缺陷的,比如上面视频中,同时存在了两个图层,我首先使用了一个缩放的动画,然后使用了一个抖动的动画,每个动画都产生了一个图层。

目前最佳使用场景是放大,或者移动,因为这样不会产生多图层(或许是我使用的方式不对,目前网上的资料大部分都是 fade 或者 scale 的效果,没有复杂变形的案例)。


如果你是用的 react 里面的 lazy load, 那么可能无法触发动画效果,因为该回调需要同步方法,异步可能需要加 sleep 来确保内容已经被载入

参考链接:

本文链接:https://note.lilonghe.net/post/view-transition-api.html

-- EOF --