day15-动画和路由过渡和切换

📚 目录

  1. 介绍
  2. 介绍
    1. Animation
    2. Curve
    3. AnimationController
    4. Tween
    5. 监听动画
  3. 自定义路由切换动画
  4. Hero飞行动画
  5. 交织动画
  6. 动画切换组件
    1. AnimatedSwitcher
    2. AnimatedSwitcher封装
  7. 动画过渡组件

本文学习和引用自《Flutter实战·第二版》:作者:杜文

1. 介绍

在任何系统的UI框架中,动画实现的原理都是相同的,即:在一段时间内,快速地多次改变UI外观;由于人眼会产生视觉暂留,所以最终看到的就是一个“连续”的动画。我们将UI的一次改变称为一个动画帧,对应一次屏幕刷新,而决定动画流畅度的一个重要指标就是帧率FPS,即每秒的动画帧数。帧率越高则动画就会越流畅!一般情况下,对于人眼来说,动画帧率超过16 FPS,就基本能看了,超过 32 FPS就会感觉相对平滑,而超过 32 FPS,大多数人基本上就感受不到差别了。由于动画的每一帧都是要改变UI输出,是比较耗资源的,而在Flutter中,理想情况下是可以实现 60FPS 的,这和原生应用能达到的帧率是基本是持平的。

2. Flutter中动画抽象

为了方便开发者创建动画,不同的UI系统对动画都进行了一些抽象,比如在 Android 中可以通过XML来描述一个动画然后设置给View。Flutter中也对动画进行了抽象,主要涉及 Animation、Curve、Controller、Tween这四个角色,它们一起配合来完成一个完整动画

2-1. Animation

Animation是一个抽象类,它本身和UI渲染没有任何关系,它主要的功能是保存动画的插值和状态。Animation对象是一个在一段时间内依次生成一个区间(Tween)之间值的类。Animation对象在整个动画执行过程中输出的值可以是线性的、曲线的、一个步进函数或者任何其他曲线函数等等,这由Curve来决定。 根据Animation对象的控制方式,动画可以正向运行(从起始状态开始,到终止状态结束),也可以反向运行,甚至可以在中间切换方向。我们可以通过Animation来监听动画每一帧以及执行状态的变化:

  • addListener():用于给Animation添加帧监听器,在每一帧都会被调用。帧监听器中最常见的行为是改变状态后调用setState()来触发UI重建。

  • addStatusListener():给Animation添加“动画状态改变”监听器;动画开始、结束、正向或反向时会调用状态改变的监听器。

2-2. Curve

动画过程可以是匀速的、匀加速的或者先加速后减速等。Flutter中通过Curve(曲线)来描述动画过程,我们把匀速动画称为线性的,而非匀速动画称为非线性的。

曲线动画过程
linear匀速的
decelerate匀减速
ease开始加速,后面减速
easeIn开始慢,后面快
easeOut开始快,后面慢
easeInOut开始慢,然后加速,最后再减速
  • 指定动画曲线
final CurvedAnimation curve = CurvedAnimation(parent: controller, curve: Curves.easeIn);
  • 定义一个正弦曲线
class ShakeCurve extends Curve {double transform(double t) {return math.sin(t * math.PI * 2);}
}

2-3. AnimationController

AnimationController用于控制动画,它包含动画的启动forward()、停止stop() 、反向播放 reverse()等方法。AnimationController会在动画的每一帧,就会生成一个新的值。默认情况下,AnimationController在给定的时间段内线性的生成从 0.0 到1.0(默认区间)的数字。

  • 创建animation对象
final AnimationController controller = AnimationController(// 动画时长duration: const Duration(milliseconds: 2000),// 指定生成数字的区间lowerBound: 10.0,upperBound: 20.0,// 绑定State对象vsync: this
);

2-4. Tween

默认情况下,AnimationController对象值的范围是[0.0,1.0]。如果我们需要构建UI的动画值在不同的范围或不同的数据类型,则可以使用Tween来添加映射以生成不同的范围或数据类型的值。

final Tween doubleTween = Tween<double>(begin: -200.0, end: 0.0);

2-5. 监听动画

我们可以通过Animation的addStatusListener()方法来添加动画状态改变监听器。Flutter中,有四种动画状态,在AnimationStatus枚举类中定义。

属性值描述
dismissed动画在起始点停止
forward动画正在正向执行
reverse动画正在反向执行
completed动画在终点停止
  • 完整动画例子:
import 'package:flutter/material.dart';/// 定义
class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}/// 实现 需要继承TickerProvider,如果有多个AnimationController,则应该继承TickerProviderStateMixin
class HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {late Animation<double> animation;late AnimationController controller;void initState() {super.initState();controller = AnimationController(duration: const Duration(seconds: 3),vsync: this);// 使用弹性曲线animation = CurvedAnimation(parent: controller, curve: Curves.bounceIn);// 匀速图片宽高从0变到300animation = Tween(begin: 0.0, end: 300.0).animate(controller)..addListener(() {setState(() => {});});animation.addStatusListener((status) {if (status == AnimationStatus.completed) {// 动画执行结束时反向执行动画controller.reverse();} else if (status == AnimationStatus.dismissed) {// 动画恢复到初始状态时执行动画(正向)controller.forward();}});// 启动动画(正向执行)controller.forward();}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Flutter Home'),),body: Container(alignment: Alignment.center,child: Image.asset('static/portrait.png',width: animation.value,height: animation.value),));}void dispose() {controller.dispose();super.dispose();}
}

3. 自定义路由切换动画

Material组件库中提供了一个MaterialPageRoute组件,它可以使用和平台风格一致的路由切换动画,如在iOS上会左右滑动切换,而在Android上会上下滑动切换。现在,我们如果在Android上也想使用左右切换风格,该怎么做?一个简单的作法是可以直接使用CupertinoPageRoute。

Navigator.push(context, CupertinoPageRoute(  builder: (context)=>PageB(),));
  • 使用PageRouteBuilder来自定义路由切换动画
import 'package:flutter/material.dart';
import 'package:demo1/views/login/view.dart';/// 定义
class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}/// 实现
class HomePageState extends State<HomePage> {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Flutter Home'),),body: Container(alignment: Alignment.center,child: Image.asset('static/portrait.png',width: 200.0,height: 200.0),),floatingActionButton: FloatingActionButton(onPressed: () {Navigator.push(context,PageRouteBuilder(transitionDuration: const Duration(milliseconds: 500),pageBuilder: (BuildContext context, Animation<double> animation,Animation secondaryAnimation) {return FadeTransition(// 使用渐隐渐入过渡,opacity: animation,// 其他页面child: const LoginPage(),);},),);},child: const Text('跳'),),);}
}

4. Hero飞行动画

在Flutter中将图片从一个路由“飞”到另一个路由称为hero动画,尽管相同的动作有时也称为 共享元素转换。实现 Hero 动画只需要用Hero组件将要共享的 widget 包装起来,并提供一个相同的 tag 即可。

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
import 'package:demo1/views/login/view.dart';/// 定义
class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}/// 实现
class HomePageState extends State<HomePage> {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Flutter Home'),),body: Container(alignment: Alignment.center,child: InkWell(onTap: () {Navigator.push(context, PageRouteBuilder(pageBuilder: (BuildContext context,animation,secondaryAnimation,) {return FadeTransition(opacity: animation,child: Scaffold(appBar: AppBar(title: const Text("原图"),),body: HeroAnimationB(),),);},));},child: Hero(tag: 'xxxxx',child: ClipOval(child: Image.asset('static/portrait.png', width: 50.0),),),),));}
}/// 大图
class HeroAnimationB extends StatelessWidget {Widget build(BuildContext context) {return Center(child: Hero(tag: 'xxxxx',child: Image.asset('static/portrait.png'),),);}
}

5. 交织动画

有些时候我们可能会需要一些复杂的动画,这些动画可能由一个动画序列或重叠的动画组成。要实现这种效果,使用交织动画比较简单。要创建交织动画,需要使用多个动画对象,并且使用一个AnimationController控制所有的动画对象,给每一个动画对象指定时间间隔。

import 'package:flutter/material.dart';/// 定义
class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}/// 实现
class HomePageState extends State<HomePage> with TickerProviderStateMixin {late AnimationController myController;void initState() {super.initState();myController = AnimationController(duration: const Duration(milliseconds: 2000),vsync: this,);}handlePlayAnimation() async {try {//先正向执行动画await myController.forward().orCancel;//再反向执行动画await myController.reverse().orCancel;} on TickerCanceled {//捕获异常。可能发生在组件销毁时,计时器会被取消。}}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Flutter Home'),),body: Container(alignment: Alignment.center,child: Column(children: [ElevatedButton(onPressed: () => handlePlayAnimation(),child: const Text("Start Animation"),),Container(width: 300.0,height: 300.0,decoration: BoxDecoration(color: Colors.black.withOpacity(0.1),border: Border.all(color: Colors.black.withOpacity(0.5),),),//调用我们定义的交错动画Widgetchild: StaggerAnimation(controller: myController),),],),));}
}/// 动画组件
class StaggerAnimation extends StatelessWidget {StaggerAnimation({Key? key,required this.controller,}) : super(key: key) {// 高度动画height = Tween<double>(begin: .0,end: 300.0,).animate(CurvedAnimation(parent: controller,curve: const Interval(0.0, 0.6, //间隔,前60%的动画时间curve: Curves.ease,),),);// 颜色动画color = ColorTween(begin: Colors.green,end: Colors.red,).animate(CurvedAnimation(parent: controller,curve: const Interval(0.0, 0.6, //间隔,前60%的动画时间curve: Curves.ease,),),);// 偏移动画padding = Tween<EdgeInsets>(begin: const EdgeInsets.only(left: .0),end: const EdgeInsets.only(left: 100.0),).animate(CurvedAnimation(parent: controller,curve: const Interval(0.6, 1.0, //间隔,后40%的动画时间curve: Curves.ease,),),);}late final Animation<double> controller;late final Animation<double> height;late final Animation<EdgeInsets> padding;late final Animation<Color?> color;Widget handleBuildAnimation(BuildContext context, child) {return Container(alignment: Alignment.bottomCenter,padding: padding.value,child: Container(color: color.value,width: 50.0,height: height.value,),);}Widget build(BuildContext context) {return AnimatedBuilder(builder: handleBuildAnimation,animation: controller,);}
}

6. 动画切换组件

开发中,我们经常会遇到切换UI元素的场景,比如Tab切换、路由切换。为了增强用户体验,通常在切换时都会指定一个动画,以使切换过程显得平滑。Flutter SDK中提供了一个AnimatedSwitcher组件,它定义了一种通用的UI切换抽象。

6-1. AnimatedSwitcher

AnimatedSwitcher 可以同时对其新、旧子元素添加显示、隐藏动画。也就是说在AnimatedSwitcher的子元素发生变化时,会对其旧元素和新元素做动画。当AnimatedSwitcher的 child 发生变化时(类型或 Key 不同),旧 child 会执行隐藏动画,新 child 会执行执行显示动画。默认情况,AnimatedSwitcher会对新旧child执行“渐隐”和“渐显”动画。

import 'package:flutter/material.dart';/// 定义
class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}/// 实现
class HomePageState extends State<HomePage> {int myCount = 0;Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Flutter Home'),),body: Container(alignment: Alignment.center,child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [AnimatedSwitcher(duration: const Duration(milliseconds: 500),transitionBuilder: (Widget child, Animation<double> animation) {// 执行缩放动画return ScaleTransition(scale: animation, child: child);},child: Text('$myCount',// 显示指定key,不同的key会被认为是不同的Text,这样才能执行动画key: ValueKey<int>(myCount),style: Theme.of(context).textTheme.headline4,),),ElevatedButton(child: const Text('+1'),onPressed: () {setState(() {myCount += 1;});},)],),));}
}

6-2. AnimatedSwitcher封装

封装一个通用的SlideTransitionX 来实现左出右入,上入下出等 出入动画。修改direction的值即可修改方向。

import 'package:flutter/material.dart';
/// 定义
class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}/// 实现
class HomePageState extends State<HomePage> {int myCount = 0;Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Flutter Home'),),body: Container(alignment: Alignment.center,child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [AnimatedSwitcher(duration: const Duration(milliseconds: 500),transitionBuilder: (Widget child, Animation<double> animation) {// 执行缩放动画return SlideTransitionX(direction: AxisDirection.down, // 上入下出position: animation,child: child);},child: Text('$myCount',// 显示指定key,不同的key会被认为是不同的Text,这样才能执行动画key: ValueKey<int>(myCount),style: Theme.of(context).textTheme.headline4,),),ElevatedButton(child: const Text('+1'),onPressed: () {setState(() {myCount += 1;});},)],),));}
}/// 封装的动画容器
class SlideTransitionX extends AnimatedWidget {SlideTransitionX({Key? key,required Animation<double> position,this.transformHitTests = true,this.direction = AxisDirection.down,required this.child,}) : super(key: key, listenable: position) {switch (direction) {case AxisDirection.up:_tween = Tween(begin: const Offset(0, 1), end: const Offset(0, 0));break;case AxisDirection.right:_tween = Tween(begin: const Offset(-1, 0), end: const Offset(0, 0));break;case AxisDirection.down:_tween = Tween(begin: const Offset(0, -1), end: const Offset(0, 0));break;case AxisDirection.left:_tween = Tween(begin: const Offset(1, 0), end: const Offset(0, 0));break;}}final bool transformHitTests;final Widget child;final AxisDirection direction;late final Tween<Offset> _tween;Widget build(BuildContext context) {final position = listenable as Animation<double>;Offset offset = _tween.evaluate(position);if (position.status == AnimationStatus.reverse) {switch (direction) {case AxisDirection.up:offset = Offset(offset.dx, -offset.dy);break;case AxisDirection.right:offset = Offset(-offset.dx, offset.dy);break;case AxisDirection.down:offset = Offset(offset.dx, -offset.dy);break;case AxisDirection.left:offset = Offset(-offset.dx, offset.dy);break;}}return FractionalTranslation(translation: offset,transformHitTests: transformHitTests,child: child,);}
}

7. 动画过渡组件

在Widget属性发生变化时会执行过渡动画的组件统称为”动画过渡组件“,而动画过渡组件最明显的一个特征就是它会在内部自管理AnimationController。而为了方便使用者可以自定义动画的曲线、执行时长、方向等,通常都需要使用者自己提供一个AnimationController对象来自定义这些属性值。如此一来,使用者就必须得手动管理AnimationController,这又会增加使用的复杂性。因此,如果也能将AnimationController进行封装,则会大大提高动画组件的易用性。Flutter SDK中也预置了很多动画过渡组件,如下:

组件名功能
AnimatedPadding在padding发生变化时会执行过渡动画到新状态
AnimatedPositioned配合Stack一起使用,当定位状态发生变化时会执行过渡动画到新的状态。
AnimatedOpacity在透明度opacity发生变化时执行过渡动画到新状态
AnimatedAlign当alignment发生变化时会执行过渡动画到新的状态
AnimatedContainer当Container属性发生变化时会执行过渡动画到新的状态
AnimatedDefaultTextStyle当字体样式发生变化时,子组件中继承了该样式的文本组件会动态过渡到新样式
import 'package:flutter/material.dart';/// 定义
class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}/// 实现
class HomePageState extends State<HomePage> {double myHeight = 100;Color myColor = Colors.red;Widget build(BuildContext context) {var duration = const Duration(milliseconds: 400);return Scaffold(appBar: AppBar(title: const Text('Flutter Home'),),body: Container(alignment: Alignment.center,child: AnimatedContainer(duration: duration,height: myHeight,color: myColor,child: TextButton(onPressed: () {if (myHeight < 300) {setState(() {myHeight = 300;myColor = Colors.blue;});} else {setState(() {myHeight = 100;myColor = Colors.red;});}},child: const Text('点击执行变化',style: TextStyle(color: Colors.white),))),));}
}

本次分享就到这儿啦,我是鹏多多,如果您看了觉得有帮助,欢迎评论,关注,点赞,转发,我们下次见~

往期文章

  • 手把手教你搭建规范的团队vue项目,包含commitlint,eslint,prettier,husky,commitizen等等
  • Web Woeker和Shared Worker的使用以及案例
  • Vue2全家桶+Element搭建的PC端在线音乐网站
  • vue3+element-plus配置cdn
  • 助你上手Vue3全家桶之Vue3教程
  • 助你上手Vue3全家桶之VueX4教程
  • 助你上手Vue3全家桶之Vue-Router4教程
  • 超详细!Vue的九种通信方式
  • 超详细!Vuex手把手教程
  • 使用nvm管理node.js版本以及更换npm淘宝镜像源
  • vue中利用.env文件存储全局环境变量,以及配置vue启动和打包命令
  • 超详细!Vue-Router手把手教程

个人主页

  • CSDN
  • GitHub
  • 简书
  • 博客园
  • 掘金

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

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

相关文章

C#中HttpWebRequest的用法

前言 HttpWebRequest是一个常用的类&#xff0c;用于发送和接收HTTP请求。在C#中使用HttpWebRequest可以实现各种功能&#xff0c;包括发送GET和POST请求、处理Cookie、设置请求头、添加参数等。本文将深入介绍HttpWebRequest的用法&#xff0c;并给出一些常见的示例。 目录 前…

Java面试总结——集合篇

摘自javaguide的集合总体框架图&#xff1a; List, Set, Queue, Map 的区别 List&#xff1a;底层基于object[]数组&#xff0c;存储的元素有序、可重复。 Set&#xff1a;底层基于HashMap实现&#xff0c;存储的元素无序&#xff0c;不可重复。 Queue&#xff1a;单…

科研院校和研究所都在用功率放大器做哪些实验

科研院校和研究所在科研工作中常常使用功率放大器进行实验。功率放大器是一种电子设备&#xff0c;其主要功能是将输入信号的功率增加到预定的输出功率水平&#xff0c;并保持信号的波形不失真。它在各个学科领域都有广泛的应用&#xff0c;包括通信、无线电、雷达、生物医学等…

vue3 使用<script lang=“ts“ setup>加上lang=“ts“后编译错误

报错信息 报错原因 加上了langts解决 下载typescript和loader npm install typescript ts-loader --save-dev配置vue.config.js 添加下面的代码 configureWebpack: { resolve: { extensions: [".ts", ".tsx", ".js", ".json"] }…

Axure中继器的使用

一.中继器介绍 在Axure中&#xff0c;中继器&#xff08;Relays&#xff09;是一种功能强大的元件&#xff0c;可以用于创建可重复使用的模板或组件。中继器允许您定义一个主要的模板&#xff0c;并在页面中重复使用该模板的实例。以下是中继器的作用和优缺点&#xff1a; 作…

Wireshark在移动网络中的应用

第一章&#xff1a;Wireshark基础及捕获技巧 1.1 Wireshark基础知识回顾 1.2 高级捕获技巧&#xff1a;过滤器和捕获选项 1.3 Wireshark与其他抓包工具的比较 第二章&#xff1a;网络协议分析 2.1 网络协议分析&#xff1a;TCP、UDP、ICMP等 2.2 高级协议分析&#xff1a;HTTP…

2023 英特尔On技术创新大会直播 |我感受到的AI魅力

文章目录 前言英特尔技术创新大会 的来历芯生无限 赋能AI创新后记 前言 近年来&#xff0c;人工智能&#xff08;Artificial Intelligence&#xff09;的应用与发展呈现出爆发式增长的态势&#xff0c;成为科技领域最为引人注目的热门话题之一。作为全球领先的半导体公司&…

workflow系列教程(5-1)HTTP Server

往期教程 如果觉得写的可以,请给一个点赞关注支持一下 观看之前请先看,往期的博客教程,否则这篇博客没办法看懂 workFlow c异步网络库编译教程与简介 C异步网络库workflow入门教程(1)HTTP任务 C异步网络库workflow系列教程(2)redis任务 workflow系列教程(3)Series串联任务流…

Boto3按名字搜索AWS Image并返回Image的相关参数 (Python)

文章目录 小结问题及解决参考 小结 本文记录使用Python脚本和Boto3按名字搜索AWS Image并返回AWS Image的相关参数。 问题及解决 记得操作之前拿到相应的权限&#xff1a; export AWS_ACCESS_KEY_ID"xxxxxxxxxxxxxxxxxxxxxxxxxx"export AWS_SECRET_ACCESS_KEY&qu…

《Linux C编程实战》笔记:进程操作之ID,优先级

获得进程ID getpid函数 这个函数都用了很多次了&#xff0c;看一下定义和例子就行了 #include<sys/types.h> #include <unistd.h> pid_t getpid(void); 示例程序1 #include<cstdlib> #include<malloc.h> #include<cstring> #include <cs…

Tomcat (Linux系统)详解全集

点击标题进入对应模块学习&#xff0c;你也可以完全拿捏Tomcat&#xff01; 1 Tomcat及JDK下载安装&#xff08;Linux系统&#xff09; 2 Tomcat目录介绍 3 Tomcat的启动关闭及日志说明 4 完美解决Tomcat启动慢的三种方法 5 Tomcat管理功能使用 6 Tomcat主配置文件&#xff08;…

SSM整合实战(Spring、SpringMVC、MyBatis)

五、SSM整合实战 目录 一、SSM整合理解 1. 什么是SSM整合&#xff1f;2. SSM整合核心理解五连问&#xff01; 2.1 SSM整合涉及几个IoC容器&#xff1f;2.2 每个IoC容器盛放哪些组件&#xff1f;2.3 IoC容器之间是什么关系&#xff1f;2.4 需要几个配置文件和对应IoC容器关系&…

Python工程部署到Linux云服务器

安装python # 更新源 sudo yum install epel-release# 更新源 sudo yum update# 安装python3 sudo yum install python3# 验证 python3 -V安装pip # 安装 sudo yum install python3-pip# 升级 python3 -m pip install --upgrade pip安装virtualenv、virtualenvwrapper sudo …

Ubuntu中常用的基本操作指令及其功能

文件和目录操作&#xff1a; ls&#xff1a;列出当前目录下的文件和子目录。cd&#xff1a;切换目录。例如&#xff0c;cd /home/user 切换到 /home/user 目录。pwd&#xff1a;显示当前工作目录。mkdir&#xff1a;创建新目录。例如&#xff0c;mkdir new_directory 创建一个名…

2.vue学习(8-13)

文章目录 8.数据绑定9.el与data的2种写法10.理解mvvm11.object.defineProperty12. 理解数据代理13 vue中的数据代理 8.数据绑定 单向数据绑定就是我们学的v-bind的方式&#xff0c;vue对象变了&#xff0c;页面才变。但是页面变了&#xff0c;vue对象不会变。 双向数据绑定需要…

时序预测 | Python实现LSTM-Attention电力需求预测

时序预测 | Python实现LSTM-Attention电力需求预测 目录 时序预测 | Python实现LSTM-Attention电力需求预测预测效果基本描述程序设计参考资料预测效果 基本描述 该数据集因其每小时的用电量数据以及 TSO 对消耗和定价的相应预测而值得注意,从而可以将预期预测与当前最先进的行…

vue 学习笔记

生命周期 1&#xff09;定义&#xff1a;vue实例从创建到销毁的过程 2&#xff09;钩子函数 2.1&#xff09;beforeCreate&#xff1a;vue实例初始化之前调用&#xff0c;这个阶段vue实例刚刚在内存中创建&#xff0c;此时data和methods这些都没初始化好。 2.2&#xff09;Cre…

【算法】红黑树

一、红黑树介绍 红黑树是一种自平衡二叉查找树&#xff0c;是在计算机科学中用到的一种数据结构&#xff0c;典型的用途是实现关联数组。 红黑树是在1972年由Rudolf Bayer发明的&#xff0c;当时被称为平衡二叉B树&#xff08;symmetric binary B-trees&#xff09;。后来&am…

6.1 接口- java核心卷1

6.1 接口 任何实现Comparable接口的类都要包含compareTo方法&#xff0c;该方法参数为Object对象&#xff0c;返回整型数值 Array类的sort方法对Employee对象排序&#xff1a; 1.Employee类实现Comparable接口 2.重写compareTo方法&#xff0c;用Double.compare&#xff08;…

Go、Python、Java、JavaScript等语言的求余(取模)计算

余数符号规则&#xff1a; Go&#xff08;%&#xff09;&#xff1a; 余数与被除数符号一致 Java&#xff08;%&#xff09;&#xff1a; 余数与被除数符号一致 JavaScript&#xff08;%&#xff09;&#xff1a; 余数与被除数符号一致 Python&#xff08;%&#xff09;…