作为前端还在使用GIF动画吗?换一种更优雅的方案吧

news2024/11/27 16:45:19

Web-Editor

前言

动画需求在业务开发中是很常见的功能,无论是客户端开发、Web 开发、还是桌面端开发,为了产品有更好的用户体验,UED 设计的视觉效果也愈发的复杂,一般些简单的淡入淡出,旋转效果开发花费些时间即可搞定,甚至稍微复杂些的动画多花费些时间也能完成,但主要面临几个问题:

  1. 耗时成本太高:在开发工作量很多的情况下,对开发来说无疑是增加了一大波工作量,用身边的一些同事的说法就是,连正常的业务需求都开发不完,谁还去精雕细琢那些去;
  2. 吃力不讨好:开发吭哧吭哧写完了动画交予 UED、PD 去验收时很多时候会反馈说这实现的和设计稿差距有些多,很高概率会有多次的反工。

自己手写动画太费事,那就直接用一劳永逸的方法,UED 直接出 GIF 动画,开发直接贴 GIF 图片即可,对于开发开说几个小时的动画需求几分钟即可搞定,整体来说 GIF 是一种制作简单、来源广泛(很多软件都可以生成gif动画)、兼容性强(基本上所有浏览器都支持)的轻量级的方案。

但从产品的视角、用户视角来说 GIF 的动画的弊端也是非常多的,诸如:

  1. GIF 图片保存了每一帧的内容,因此造成图片很大;为解决图片过大的问题,大多数情况下都会采用压缩的方式较小体积,但这也造成了动画模糊、失真;
  2. 用户无法直接与动画本身做交互,如停止、开始、加速等交互,也无法直接修改动画元素的属性如背景色等;

既如此,那就再引入一种新的技术方案 Lottie , 感兴趣的可以先先睹为快 Lottie-Example 。

Lottie

什么是 Lottie

Lottie 是 Airbnb 发布的一款开源动画库,它适用于 Android、iOS、Web 和 Windows 的库。 它提供了一套从设计师使用 AE(Adobe After Effects)到各端开发者实现动画的工具流。

简单来说就是 UED 和开发各司其职,UED 提供动画 json 文件即可, 开发者就可以直接运用在 iOS、Android、Web 和 React Native之上,无需其他额外操作。

今天对如何设计动画不做详细介绍,只是从前端的视角出发看看如何使用 Lottie,实现精致的动画。

Lottie-Web

Lottie-Web 是 Lottie 在 web 端的技术方案。

Lottie-Web 提供了 SVG、Canvas 和 HTML 三种渲染模式,一般使用 Svg 或 Canvas 即可。

  1. SVG 渲染器支持的特性最多,也是使用最多的渲染方式。并且 SVG 是可伸缩的,任何分辨率下不会失真;
  2. Canvas 渲染器就是根据动画的数据将每一帧的对象不断重绘出来;
  3. HTML 渲染器受限于其功能,支持的特性最少,只能做一些很简单的图形或者文字,也不支持滤镜效果。

Lottie-Web-Image

使用

安装依赖

npm i lottie-web --save 
or 
yarn add lottie-web --save

实例化

以下方法提供了一个简单的初始化过程,其他参数可参考 官网 。

function init(){
    // 读取动画容器
    const lottieContainer = document.querySelector("#container");
    if (!lottieContainer) return;
    // 实例化
    const lottieInstance = lottie.loadAnimation({
        // UED 提供的 动画的 json 文件
        path: 'https://static-cdn.canyuegongzi.xyz/lf20/lf20_jv0xz0qi.json',
        // 渲染方式
        renderer: "svg",
        // 是否循环
        loop: true,
        container: lottieContainer
    });
}

Lottie-Web-Image

至此, 开发者设计师可直接还原动画效果了,再也不会出现买家秀卖家秀的情况,也避免了开发和设计之前的互相扯皮,而且 JSON 文件,可以多端复用(Web、Android、iOS、React Native)。

动画控制

开始、结束动画

// 开始动画
function onStart() {
    lottieInstance?.play();
}

// 结束动画
function onStop() {
    lottieInstance?.stop();
}

速度修改

// 修改动画播放速度
function updateSpeed(val: number) {
    lottieInstance?.setSpeed(val);
}

Lottie-Web 提供了相当丰富的 Api 此处借花献佛从网络拷贝了一份常用的如下,其他的可参考官网。

  1. animation.play():播放,从当前帧开始播放;
  2. animation.stop():停止,并回到第0帧;
  3. animation.pause():暂停,并保持当前帧;
  4. animation.goToAndStop(value, isFrame):跳到某个时刻/帧并停止(isFrame(可省略,默认false:毫秒;true:帧)指明value的单位是毫秒还是帧);
  5. animation.goToAndPlay(value, isFrame):跳到某个时刻/帧并播放;
animation.goToAndStop(30, true)     // 跳转到第30帧并停止
animation.goToAndPlay(300)          // 跳转到第300毫秒并播放
  1. animation.playSegments(arr, forceFlag):以帧为单位,播放指定片段(arr可以包含两个数字或者两个数字组成的数组,forceFlag表示是否立即强制播放该片段);
animation.playSegments([10,20], false)          // 播放完之前的片段,播放10-20帧
animation.playSegments([[0,5],[10,18]], true)   // 直接播放0-5帧和10-18帧
  1. animation.setSpeed(speed):设置播放速度,speed为1表示正常速度;
  2. animation.setDirection(direction): 设置播放方向,1表示正向播放,-1表示反向播放
  3. animation.destroy(): 删除该动画,移除相应的元素标签等。

生命周期

Lottie-Web 提供了几个比较使用的生命周期钩子函数,开发者可根据需要做定制开发:

  1. data_ready:动画数据加载完毕;
  2. config_ready:完成初始配置后;
  3. data_failed:当无法加载动画的一部分时;
  4. loaded_images:当所有图像加载成功或错误时;
  5. DOMLoaded:将元素添加到DOM时。
animation.addEventListener('data_ready', () => { 
    console.log("data_ready")
});

进阶

上述章节中已经可以完美的运行 Lottie 动画了,但每个动画都得手动实例化,是不是很繁琐,此处笔者通过 WebComponent 技术方案做了进一步封装,方便开发者更简洁的调用, 先睹为快,快速体验 。

WuLottie 封装

import { extractClass } from '@wu-component/common';
import { h, Component, WuComponent, Prop, OnConnected, OnDisConnected, Watch } from '@wu-component/web-core-plus';
import lottie, { AnimationItem } from "lottie-web";
import css from './index.scss';

@Component({
    name: 'wu-plus-lottie',
    css: css,
})
export class WuLottie extends WuComponent implements OnConnected, OnDisConnected {
    constructor() {
        super();
    }

    public lottieInstance!: AnimationItem;

    public lottieContainer!: HTMLDivElement;

    @Prop({ type: Boolean, default: true })
    public loop: boolean;

    @Prop({ type: String, default: undefined })
    public data: string;

    @Prop({ type: Boolean, default: true })
    public autoplay: boolean;

    @Prop({ type: String, default: 'svg' })
    public renderer: 'svg' | 'canvas' | 'html'

    @Prop({ type: Object, default: {} })
    public config: Record<string, any>;

    public override connected(shadowRoot: ShadowRoot): void {
        this.init();
    }

    // 元素销毁时也同步销毁掉 lottie 动画
    public override disConnected(): void {
        this.lottieInstance.destroy();
    }

    private init(){
        // 实例化动画
        this.lottieContainer = this.shadowRoot.querySelector('.lottieWrapper');
        if (!this.lottieContainer) return;
        this.lottieInstance = lottie.loadAnimation({
            // @ts-ignore
            ...this.$reactive || {},
            path: typeof this.data === 'string' ? this.data : undefined,
            animationData: typeof this.data === 'object' ? this.data : undefined,
            container: this.shadowRoot.querySelector('.lottieWrapper'),
        });
    }

    @Watch('data')
    public dataChnage(val: string, old: string) {
        this.init();
    }

    @Watch('loop')
    public loopChnage(val: boolean, old: boolean) {
        if (!this.lottieInstance) return;
        this.lottieInstance.loop = val;

        if (val && this.lottieInstance.isPaused) {
            this.lottieInstance.play();
        }
    }

    @Watch('autoplay')
    public lautoplayChnage(val: boolean, old: boolean) {
        if (!this.lottieInstance) return;
        this.lottieInstance.autoplay = val;
    }

    public stop() {
        return this.lottieInstance && this.lottieInstance.stop();
    }

    public play() {
        return this.lottieInstance && this.lottieInstance.play();
    }

    public override render(_renderProps = {}, _store = {}) {
        return (
            <div {...extractClass({}, 'lottieWrapper', {})}> </div>
        );
    }
}


如何使用

安装依赖

npm i l@wu-component/wu-lottie --save 
or 
yarn add @wu-component/wu-lottie --save

使用

开发者无需手动实例化 Lottie, 可如同普通 HTML 标签般接入。

<wu-plus-lottie data="https://cdn.canyuegongzi.xyz/wu-component-static/lf20_r6blppzq.json"></wu-plus-lottie>

思考

了解了如何使用 Lottie ,但是在实际应用中也有一些优势和不足,要按照实际情况进行取舍。

  1. Lottie-web 文件本身仍然比较大,未压缩大小为 513k,轻量版压缩后也有 144k,经过 Gzip 后,大小为39k。所以,需要注意 Lottie-web 的加载;
  2. 效果完全依赖设计师,结果需要开发把关,如最后的 json 文件大小;
  3. 部分AE特效不支持。有少量的 AE 动画效果,Lottie 无法实现,需要格外注意 supported-features 。

虽然如此,Lottie 还是相当优秀的动画方案,多种技术方案多条路嘛,大家在日常工作中都在使用什么技术方案欢迎在评论区讨论。

方案中涉及的代码均可在 github 阅读,欢迎 Star。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/3934.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三只松鼠,“跑”不动了?

【潮汐商业评论/ 原创】 编辑部的Lisa是个典型的吃货&#xff0c;而坚果零食绝对是她的心头好。用她的话来说“坚果提供优质脂肪&#xff0c;每天吃点&#xff0c;解馋又健康啊。” 而作为网红坚果零食“开山鼻祖”之一的三只松鼠&#xff0c;最近的日子似乎并不好过。 近日…

阿里云SLB之:基于HTTPS协议的SLB应用场景(十二)

文章目录 1.配置域名解析2.配置HTTPS协议类型的SLB七层负载2.1.点击监听配置向导2.2.配置负载均衡类型2.3.设置负载均衡算法2.4.设置域名使用的SSL证书2.5.设置后端虚拟服务器组2.6.开机健康检查2.7.审核配置完成创建3.配置HTTP强转HTTPS4.配置ECS中的Nginx支持HTTPS协议5.通过…

文件传输协议

1、FTP 文件传送协议FPT&#xff08;File Transfer Protocol&#xff09;是互联网上使用的最广泛的文件传输协议。FTP提供交互式访问&#xff0c;允许客户指明文件的类型与格式&#xff0c;并允许文件具有存取权限&#xff08;如访问文件的用户必须经过授权&#xff0c;如输入有…

pg故障修复记录

一个线上实例&#xff0c;用户数据大概300g 400g的样子&#xff0c;由于用户自己修改了最大连接数&#xff0c;超过了我们设置的合理范围&#xff0c;导致自动恢复失败&#xff0c;现在需要我们手动搭建起来新的主从关系。 但是在搭建的过程中&#xff0c;出现了两个比较麻烦的…

我用python分析买房数据

首先说明&#xff0c;这是一篇技术文章。 明年打算买房&#xff0c;媳妇这段时间总去看房子&#xff0c;这种状态持续了两个月&#xff0c;最近终于消停了。现在整个市场不明朗&#xff0c;我们也不确定换到哪里。不如先整理点数据&#xff0c;至少能监控一些区域价格&#xf…

Vue利用flex布局实现TV端城市列表

Vue利用flex布局实现TV端城市列表 vue中城市列表和搜索很常见&#xff0c;这篇博客就来说说咋实现搜索和城市列表 1.实现搜索布局代码&#xff1a; <div class"search-bar"><input class"search-input" v-model"citySearchResult" :…

Java【数组】定义与使用,什么是引用类型你知道吗

文章目录前言一、数组的基本概念1.什么是数组2.数组的创建和初始化1.数组的创建2. 数组的初始化3.数组的使用4.遍历数组&#xff08;两种方式&#xff09;二、数组是引用类型1.初识JVM内存分配2.引用类型3.认识null三、数组的应用场景1.保存数据2.作为方法的参数1.参数传基本数…

STM32F407ZGT6|SPI主从模式

功能&#xff1a;主机发送数据0x34–>从机接收数据–>通过串口将数据发送出去–>串口猎人显示0x34 必备知识点 1、SPI串行外设接口特点 高速、全双工、同步、串行高速&#xff1a;发送数据的速度很快全双工&#xff1a;两设备可同时双向通信&#xff08;接收与发送&…

STM32 CAN过滤器标识符学习笔记

最近看了下STM32 CAN 通讯其中标示符过滤器设置大有讲究。特别是你要使用ST库函数时&#xff0c;当过滤器工作在屏蔽模式下&#xff0c;并且你把屏蔽位设了1也就是标示符对应位必须全部匹配才能通过&#xff0c;这是由其要小心。 举个例子吧&#xff0c;过滤器长度为32位&…

【MindSpore易点通】在开发环境中如何使用MindInsight在线调试器

背景信息 在使用开发环境训练任务过程中&#xff0c;为方便开发人员更形象地观察到实时训练任务中的数值变化情况以分析精度问题&#xff0c;ModelArts在线调节器应运而生。与离线调试器的区别在于&#xff0c;离线调试器只能待整个任务运行完成后&#xff08;收集到整个任务过…

【机器学习大杀器】Stacking堆叠模型

1.前言 Kaglle比赛中使用Stacking模型是非常常见的大杀器&#xff0c;这是为什么呢&#xff1f; 【机器学习大杀器】Stacking堆叠模型 1.前言 2.Model 3: Stacking model 2.1 description of the algorithms: 2.2 interpretation of the estimated models: 3. Extend 3.1 …

终于盼到了,Python 数据科学速查表中文版来了

近几年以来&#xff0c;Python 的应用场景越来越多&#xff0c;几乎可以应用于自然科学、工程技术、金融、通信和商业等各种领域。究其原因在于 Python 的简单易学、功能强大。 想系统地学点东西&#xff0c;发现很多不错的技术文档都是英文资料&#xff0c;发现英文竟然成为了…

数据结构考研第六章——图(内含动图)

大纲要求&#xff1a;图的相关算法相对较多&#xff0c;通常只要求掌握其基本思想和实现步骤&#xff0c;而算法的具体实现不是重点。 一、图的基本概念 图的概念&#xff1a;图G由顶点集V和边集E组成的&#xff0c;记为G&#xff08;V&#xff0c;E&#xff09;有向图&#x…

6_显示登录信息以及上传图片

目录一 显示登录信息二 账号设置修改用户图片一 显示登录信息 实现思路 书写一个拦截器 loginTicketInterceptor 在 preHandle 方法中获取用户发送请求时携带的 cookie书写一个专门获取cookie的工具类 CookieUtil查数据库,数据库是否存在该 ticket,判断该凭证是否有效,-凭证是…

【论文阅读】EDPLVO: Efficient Direct Point-Line Visual Odometry

一、公式及符号约定 这篇论文是将直接法的残差计算从点扩展到了线段&#xff0c;所以一些符号在第三章的部分提前做了约定。用Π表示投影的函数&#xff0c;也就是用像素坐标和内参矩阵以及深度信息&#xff0c;投影出点的空间坐标&#xff0c;反之Π-1表示的是将空间坐标投影…

Git使用详细教程

1. cmd面板的常用命令 clear&#xff1a;清屏cd 文件夹名称----进入文件夹cd … 进入上一级目录(两个点)dir 查看当前目录下的文件和文件夹(全拼:directory)Is 查看当前目录下的文件和文件夹touch 文件名----创建文件echo 内容 > 创建文件名----创建文件并写入内容rm 文件名…

基于udp实现回显服务器,翻译服务器

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 udp socket 要掌握的类&#xff1a; 1.DatagramSocket 2.DatagramPacket 一、udp版本回显服务器 服务端&#xff1a; 完整代码 客户端&#xff1a; 完整代码 udp版本翻译…

Spring注入和生命周期

目录 获取Bean对象&#xff08;对象装配&#xff09; 属性注入 构造注入 Setter注入 三种注入的优缺点分析 注入的注解&#xff1a; 一个类型多个bean对象的注入方式 1.让变量名等于bean的id 2.用Resource注解&#xff08;name“bean的id”&#xff09; 3.用Qualif…

Java 核心技术 0 —— Class加载 和 运行时数据区域

JVM 是 字节码的运行环境&#xff0c;负责装载class到JVM内部&#xff0c;解释编译为对应平台的机器码指令进行执行&#xff0c;对于JVM设计有权威的定义规范&#xff0c;了解 JVM 类加载各部的主要功能 和 运行时数据区域组成 很有意义。 磁盘上有一个.java文件&#xff0c;通…

【目标检测】swin-transformer训练自己的数据集

文章目录1. 数据集的制作1.1. Labelme制作数据集1.2 COCO数据集格式2. 配置swin-transformer3. 训练自己的数据集4. 训练5.参考链接1. 数据集的制作 1.1. Labelme制作数据集 pip install labelme然后在桌面搜索框中找到labelme&#xff0c;然后打开&#xff0c;或者直接在命令…