数据库约束和查询
一 约束意义
这个后面的字段是什么意思呢? 先前说数据类型是一种约束,约束我们只能放该类型的数据,还有其它的约束来保证数据的合法性,下面的字段就和约束有关。

编译器的编译就是一个约束,保证我们的代码一定是语法合格的。我们有可能在表将qq号写到学号上,我们应该避免这种问题,这些都是需要我们去增加约束来保证的。
二 约束介绍
1 空属性约束
添加空属性约束

我们发现NULL字段有些填YES,有些填NO,NO就是表示该字段不可以为NULL,

用户必须插入数据,不能让表格显示为NULL,注意,有时候是显示为空,而不是为NULL,后面提,接下来演示一下。

下面两个insert的sql语句报错是不同的情况,我们已经知道insert into 表名(列名称) values(列名称)这句sql语句,值得一提的是,values中没写的列,它们的值是用默认的值。而由于如果我们的列有了not null这个约束,此时不会给我们加上default null,所以values()插入时会报错说没有默认值。

后面那个报错就是我们真的插入了null,这个违背了空约束。
2 默认值约束

接下来要讲的约束,就和上表的Default字段有关。

此时我们values没有值,但是也没有报错,就是因为有了默认值。
    
之前创建表未指明default值,缺省值为NULL。


3 列描述
没有实际意义,也没有什么约束功能,就是一个对列成员的描述,让后来者可以快速知道这个表的成员意义,就像注释一样。

comment字段呢不显示在该表中,要用下面方式才可以查看。这个注释可以让程序员知道这个字段的意义,可以一定程度上约束我们输入的数据,例如我们知道这个列成员是学号,就不会数据一个班级上去。

4 显示约束
zerofill

type是成员类型可以理解,那为什么会有数字11。这个其实是显示的最大数据位数。

zerofille表示将数据增加零来扩充宽度。若数据位数大于10,则无需补零。上面不是11位吗,为什么才十个数字,因为int默认有符号,还要一个字符给符号位。
有意思的是zerofill和default是有顺序要求的,我反过来书写会报错。

5 主键约束
设定主键,主键列元素不能重复,而且该列自动设为非空约束。主键只能有一列,唯一键可以有多列。

插入几行数据进来。

主键标识一行的唯一性,我们可以来搜索某一行出来修改。

去除主键,直接alter drop,不用指定列名,因为主键只有一列,这个不是删除列,而是去除主键约束。

表已经建立好了,我们也可以增加主键,但是会检测表内是否有冲突行。

复合主键,我们可以让id和name合起来为key,也就是只有当id和name合起来都重复了才算冲突。

再来看看发现有两列都是主键了。

我们插入几条数据,发现id可以重复,名字可以重复。

此时id和name都重复就不行了。

6 自增长约束
自增长约束,首先必须是主键列,而且改列的类型是整数,显然自增长列也只有一列。而且我们还可以指定自增长的起始值。

id列无需传值,自动插入,自动增长。


我们也可以自己指定id。

随后的id从11开始自增。原因有一个auto_increment在维护。

7 唯一键约束

id必须是唯一的,感觉和主键差不多? 唯一的区别就是id可以为空,而主键不可以。

我们甚至可以让唯一键不为空,这样就和主键几乎完全一样了。可能还有其它列也是要有唯一性的,就有了唯一键,那还要主键干嘛呢,全是唯一键不就行了? 可以认为保存每个学生的数据时,每个学生都必须要有学号,必须唯一,不能有人无学号,这是主键约束,然后就是每个学生的电话号码不能重复,但是你可以为空,由此我们发现唯一键约束是约束性小的主键约束。
问1 为什么主键只有一个,这个其实和索引有关系,学了索引我们就知道,主键索引是最特殊的索引,其它的索引都是普通的,两者要维护的数据结构不同,当然要相互区分。
8 外键约束
外键是和下表的最后一个字段有关。

如果我们把班级表上的列属性都放到学生表中,此时每行都要保存id和班级名,比较冗余,

如果我们将班级表抽离出来,然后学生表每行就只保存class_id了,不用保存name了,字节数来看是节省了不少的。
接下来创建学生表和教室表。

注意,class_id在教室表中是主键,学生表中的class_id则是普通列成员,外键约束是在从表中建立的,作用后提,什么是主从表也后提。

        
我们给两张表插入一些数据。

        学生表插入时应该能够判断班级id是否存在? 如果不存在就会报错。
还有教室表如何判断能否删除? 就是要判断学生表是否无该班级学生,无就可以删除了。

所以我们本来是想要节省空间,但是却衍生了一些问题,两个表在插入删除的时候不能无脑用mysql语句了,解决: 就是我们给这两个表建立某种约束。
重新创建表,添加外键约束,在从表定义,这个就是语法而已,在从表定义,会在两个表都产生约束。


如何区分主从表? 从表的列成员是主表主键,从表列成员和主表主键建立了外键约束。主表的主键列可以是唯一键或者主键。主表,从表只是一种分别称呼两个有关联表的称呼而已,因为这两张表在遇到插入删除时处理动作不同。
这个约束建立后,从表在插入时会拿着学生的class id去关联的表中查找,不存在报错。

在主表教室表删除时,也会拿着class id去学生表查找,存在就不能删。
总而言之,学生表为了节省存储的字节,将一些重复的并且较长的教室名字段拆出,学生表称为从表,教室表称为主表,从表保存class_id,通过class_id映射教室名,查询class_id必须能对应一个教室名,也就是有唯一性,所以是主键或者唯一键,然后就是两张表要维护一个约束,使得表的增删改查要多考虑一些东西,也就是外键约束。
三 curd
先前我们大致了解了表的操作,接下来再回忆一下curd操作,方便后续查询的时候使用。
Create(创建),Retrieve(读取),Update(更新),Delete(删除)。
创建表

多行插入

插入更新

qq和name都必须是唯一的。

之后我们再插入可能会发生冲突,我们想插入失败转为更新语句,就用如下sql。
我解释一下我对下面这句sql语句的理解,冲突是从左往右比对的,所以如果name和qq都冲突,会说name冲突了,冲突就执行后面的update,但是在更新的时候更新值不能和旧的其它行冲突,可以和原先行相等。

下面这个提示都是用insert去演示一下。

replace一句就可以代替上面的两句,这个代替是先删除再插入。

读取Retrieve
主要是用select语句。
全列查询

我们把*换成特定列名称,此时我们就可以对特定列查询了,指定列。

多列

注意,这个不是不是查询多列,而是对name列重命名。

多列重命名

去重,在列前面加个distinct即可。

select后面还可以跟着表达式,显示的列名就是表达式,也可以重命名。

where字句
我们可以对一些行做筛选,这个指令在下面的查询中经常用到。

注意,在where字句中NULL用<=>运算符比较,或者用is NULL或者is not null,一个=只能用来数字和字符的比较。

还有很多其它的运算符后面在实际例子中学习。

between a0 and a1可以用来代替 >= a0 and <= a1,判断是否为null可以用如下方式。


四 查询
1 需求实战
建立表。


需求1
找英语成绩小于60的。

需求2
找语文成绩在80-90的,并且显示出来语文成绩。

这里我们就用到了and这个并且的逻辑运算符,我还可以用下面这个。

需求3
找数学成绩是58,59,98,99都找出来。

此时就用到了or这个运算符,我们也可以用下面这个代替。

需求4
在表中找一个姓孙的一行,此时就涉及模糊匹配,也是可以用一个运算符like来处理。=是精确匹配,不能用下面这两个通配符。
注意%和_的意义。
      
_只能匹配一个字符,*可以匹配任意个字符。

需求5
语文成绩好于英语成绩的。

需求6
求总分小于两百的。

为什么下面报错说total找不到了,因为select执行顺序先通过from定位表,然后识别筛选条件,最后才去select筛选,将筛选结果显示的时候才对列重命名total,所以在条件识别时sql就不认识total,所以就报错了。

只支持对列名称重命名,不支持在筛选条件重命名。

需求7
语文成绩大于80,且不姓孙的同学。

需求8
孙某同学,否则总成绩>200,并且语文<数学成绩并且英语>80。

可用括号将多个条件合并为一个单元。
NULL查询

所以找NULL不能name=NULL。
2 对结果排序
order by字句排序,用数学成绩来排序。

我们可以指定升序降序,默认是按照升序的。
3 排序练习
1 依次按照数学降序,英语降序,语文升序来排序显示,也就是说如果数学成绩相等就按照英语来排,也相等就按照语文来排序。

如果数学成绩不相等就直接按照数学来排了。都是降序可写如下简略写法。

2 查询同学总分排名。

order为什么能使用别名,还是和执行顺序有关。先select筛选再order排序,先排序再select效率太低,因为不是所有的数据都要排序的,先select筛选是指执行where,然后执行select .. from。
3 查询姓孙的同学或者姓曹的同学的数学成绩,结果按照高到低显示。
先筛选出数据,再排序。

limit可以对结果进行截取。只有一个数字表示从开始位置截取,截取行数为1。

offset可以指定起始位置。

limit 1,4是从第二行开始往后显示4行,数据排序好要显示了才到limit来限制显示,所以Limit还在select,order之后。

update
update本质也是查找,因为需要先找到需要更新的行,才能更新。
尝试1,将孙悟空的数学成绩更为80。

多列更新如下。

尝试2,将后三名同学的数学+30分。
此时我们就拿出了后三名同学成绩。

显然我们是先排序,再获取前三行,再更新,所以更新顺序排在limit后面,加了三十分后对总分排名会有影响,此时再获取前三行不一定符合原意。

4 delete删除
这里delete是删除一行,alter drop是删除表的一列,是对表结构做修改,我们学的curd都是对内容做修改。

删除总分倒数第一。由于delete和select语法格式不太一样,所以我们的总分无法重命名。

如果没有limit那就是删除整张表了。
5 截断表
清空表不会对 auto increament清零。

插入多个数据。

截断和delete表都会清空表,但是截断时会对auto increament清零。还有个区别是truncate比delete快,因为不会变成事务。
事务: 我们的sql操作痕迹一般会变成事务被记录下来,方便溯源恢复,而截断不保存,所以比delete少事,也就更快了。值得一提的是,数据库有一种内存文件来保存数据,断开时会紧急保存到磁盘上,所以如果恢复数据库,我们可以重新执行sql语句,也可以读取磁盘文件来恢复数据。
6 去重
insert和select组合,案例如下

插入数据。

下面这个可以去重,但是我们要构建一个无重复的,现在用去重的结果创建出一个表。

创建被去重表,还可以用like运算符来模仿现有表结构。

选择唯一的插入表中,此时insert可以没有value?

再修改表名,原先的duplicate_table改成其它的表名,这个最好要在一句sql语句中完成,保证原子性。

实际上不能把文件直接上传到某个目录下,因为上传会很慢,不是原子的, 一般是上传到中间目录下,然后再move转到特定目录下,move和rename是原子的,只需要更改目录的保存的文件名和innode映射即可。所以当我们在创建新的duplicate_table时,也要保证原子性,以免修改时影响上层使用。
7 聚合函数了解
7
上述函数内传一个列名。


首先*表示select选择全部行出来,select 1可以认为是加多一个全是1的列。

distinct应该放在count函数里面,因为是对数学成绩做去重,放外面就表示是对count结果做去重了。

求和

找到英语不及格的然后再求平均

下面sql同理可以实现求平均。

找英语成绩最高的。

下面这样使用不行?

name是非聚合字段,sql规定非聚合字段必须出现在group by中,因为一个组内可能有多个成员,然后每个成员的名字不同,求最大值时可能有多行最大值,所以不知道非聚合列取哪个值,所以只要看到聚合函数,然后非聚合字段又不在group by中,此时直接拦截。
8 分组查询
分组目的是为了聚合统计。

执行顺序是先定位表,然后where判断开始select筛选,然后是分组。
部门表

雇员表

而且雇员表关联了部门表的部门编号,此时部门编号是主键,部门表就是主表,而雇员表是从表。正常情况下,MySQL不是所有特性都会投入使用的,是我们在上层设计保证的,如何用编程语言实现对数据库的约束,后面提,这个的意义是为了减少约束,提高底层插入查询效率。



group by字句使用,
需求1

平均和最高都要用聚合函数来计算。

上面是将一张表看成一个组,一起做聚合统计。如下,此时我们就是分组做聚合统计了。

注意首先一个组内的deptno是一样的,这样聚合后,deptno的值就是唯一的,不会有多个不同的值,让mysql不知道选什么。
需求2

按照两个条件来分组。

需求3

我们可以先分组统计出平均工资,不可以用where,where是在分组前起作用的。

having是用于对分组聚合统计结果进行筛选。
从下面来看,having好像可以充当where,但是实际上这里用having和where含义是不一样的,having用的字段必须是select筛选出来的,而where用的字段可以是表里任意的,这就说明一个问题,where是在筛选的时候判断的,而having一定是筛选完才使用的判断结果。
下面这个结果是恰好和where产生了一样的效果,其实是不一样的,是先筛选了整表,然后having开始筛选。

此时就不能用where,因为这个时候已经select筛选完了,按照语法规定得用having。

四 内置函数
内置函数语法select + 函数名。
1 日期函数
分别获取日期,时间和时间戳

now函数返回的和时间戳相同,

date函数返回日期部分。


添加时间


日期相减。

2 时间函数使用样例

插入数据。

时间戳和时间疑似做了一种类型转换。

例子2


开始插入

例子3

1 如何确认是两分钟内的
拿表内的数据对应的时间和当前时间相减,这个相减不能我们直接+-,而是调用先前用到的函数。
下面两种where都可以。


3 字符串函数

string应该指的是char或者varchar类型。我们还可以筛选出表中的列来传给内置函数,就像先前的聚合函数使用一样。

concat函数: 链接若干个字符串。


instr函数,返回出现位置,值得一提的是string的下标是从1开始的,这样可以和找不到返回零的情况区分开来。

大小写转换函数。

left和right函数,从某个方向取len个字符。

接下来是函数使用案例,来认识最后的几个字符串函数。
1
 用contact把分数拼接起来,

2


因为ut8编码,一个字符由三个字节表示。但是如果能在ascii表上找到的,一般用一个字节表示。
3 replace函数使用


4 substring
第二个参数是起始位置,第三个参数是len。


5

这个就是先截取首字母,然后做小写转换,

最后一步拼接

下面这个是去除空格,分别是去除左右空格,左空格,右空格。

4 数学函数

abs和bin函数如下。

conv:将10从10进制转到4进制

format保留指定位精度。

负数取模

向上向下取整函数解析
向下取整是直接去掉小数,向上是直接+1,小数舍去,3.1变为4,3.9也是,- 3.1是变为-3,不是四舍五入。
5 其它函数
查用户

定义一个用户表

md5函数,将密码转为数据摘要,这样保持就用数据摘要代替密码。

用来比较的密码也要转md5。

ifnull函数

相关文章:
数据库约束和查询
一 约束意义 这个后面的字段是什么意思呢? 先前说数据类型是一种约束,约束我们只能放该类型的数据,还有其它的约束来保证数据的合法性,下面的字段就和约束有关。 编译器的编译就是一个约束,保证我们的代码一定是语法合格的。我们…...
网工日记:FTP两种工作模式的区别
FTP 的主动模式和被动模式在连接建立的发起方、数据传输端口以及对网络环境的适应性等方面存在明显区别: 1. 连接发起方 主动模式:数据连接由服务器主动发起。在控制连接建立后,客户端通过 PORT 命令告知服务器自己用于接收数据的临时端口号…...
NLP模型工程化部署
文章目录 一、理论-微服务、测试与GPU1)微服务架构2)代码测试3)GPU使用 二、实践-封装微服务,编写测试用例和脚本,并观察GPU1)微服务封装(RestFul和RPC)2)测试编写(unit_test\api_test\load_tes…...
分布式版本管理工具——git 中忽略文件的版本跟踪(初级方法及高级方法)
git工具忽略指定文件的版本跟踪 一、简单方式实现二、复杂方式实现(模式匹配)1. 相关规则2. 应用案例a) 忽略所有内容b) 忽略所有目录(不忽略当前目录的具体文件)c)忽略指定目录下的所有文件,但排除某文件d)…...
【LangChain】Chapter4 - Question and Answer Over Documents
说在前面 文档问答,是常见的一类LLM应用,给定一段可能是从 PDF文件、网页或某公司内部文档库中提取的文本,使用LLM回答关于这些文档内容的问题。这样的应用非常的强大,它可以将LLM与完全没被训练的数据相结合,可以灵活…...
TCP/IP 协议演进中的瓶颈,权衡和突破
所有(去掉 “几乎” 修饰)问题都来自于生长速度的不一致,换句话说,膨胀不是均匀的,从而产生瓶颈甚至触碰极限,TCP/IP 从协议到实现面临的多方问题与动物体型不能无限大,摩天大楼不能无限高本质上一样。 如今被高性能网…...
软件测试面试八股文,查漏补缺(附文档)
大家好,最近有不少小伙伴在后台留言,准备面试了,又不知道从何下手!为了帮大家节约时间,特意准备了一份面试相关的资料,内容非常的全面,真的可以好好补一补,希望大家在都能拿到理想的…...
IDEA工具使用介绍、IDEA常用设置以及如何集成Git版本控制工具
文章目录 一、IDEA二、建立第一个 Java 程序三、IDEA 常用设置四、IDEA 集成版本控制工具(Git、GitHub)4.1 IDEA 拉 GitHub/Git 项目4.2 IDEA 上传 项目到 Git4.3 更新提交命令 一、IDEA 1、什么是IDEA? IDEA,全称为 IntelliJ ID…...
YOLOv10-1.1部分代码阅读笔记-transformer.py
transformer.py ultralytics\nn\modules\transformer.py 目录 transformer.py 1.所需的库和模块 2.class TransformerEncoderLayer(nn.Module): 3.class AIFI(TransformerEncoderLayer): 4.class TransformerLayer(nn.Module): 5.class TransformerBlock(nn.Module)…...
机器人革新!ModbusTCP转CCLINKIE网关揭秘
在当今这个科技日新月异的时代,机器人技术正以前所未有的速度发展着,它们在工业制造、医疗服务、家庭娱乐等多个领域扮演着越来越重要的角色。而随着机器人应用的普及和多样化,如何实现不同设备之间的高效通信成为了一个亟待解决的问题。开疆…...
JWT包中的源码分析【Golang】
前言 最近在学web编程的途中,经过学长提醒,在进行登陆(Login)操作之后,识别是否登陆的标识应该要放入authorization中,正好最近也在学鉴权,就顺便来看看源码了。 正文 1. 代码示例 在进行分…...
SpringBoot数据字典字段自动生成对应code和desc
效果:接口会返回orderType,但是这个orderType是枚举的类型(1,2,3,4),我想多返回一个orderTypeDesc给前端展示,这样前端就可以直接拿orderTypeDesc使用了。 1. 定义注解 …...
TencentOS 2.4 final 安装mysql8.0备忘录
准备 tencentOS 2.4 与Red Hat Enterprise Linux 7 是兼容的。 我们首先从oracle官网上下载mysql的源文件。 下载完成后你会得到以下文件: mysql84-community-release-el7-1.noarch.rpm 安装 首先你需要切换到root用户下。 1.安装源文件 yum localinstall my…...
Hadoop HA安装配置(容器环境),大数据职业技能竞赛模块A平台搭建,jdk+zookeeper+hadoop HA
HA概述 (1) 所谓HA(High Availablity),即高可用(7*24小时不中断服务)。 (2) 实现高可用最关键的策略是消除单点故障,HA严格来说应该分为各个组件的HA机制,H…...
使用javascript读取波形文件数据,并生成动态的波形图
代码如下: // HTML5 Canvas 动态波形生成器 // 使用JS读取波形文件并生成动态波形// 创建Canvas并设置上下文 const canvas document.createElement(canvas); canvas.width 800; canvas.height 400; document.body.appendChild(canvas); const ctx canvas.getC…...
服务器系统维护与安全配置
一、硬件系统的安全防护 硬件的安全问题也可以分为两种,一种是物理安全,一种是设置安全。 1、物理安全 物理安全是指防止意外事件或人为破坏具体的物理设备,如服务器、交换机、路由器、机柜、线路等。机房和机柜的钥匙一定要管理…...
大模型Weekly 03|OpenAI o3发布;DeepSeek-V3上线即开源!
大模型Weekly 03|OpenAI o3发布;DeepSeek-V3上线即开源!DeepSeek-V3上线即开源;OpenAI 发布高级推理模型 o3https://mp.weixin.qq.com/s/9qU_zzIv9ibFdJZ5cTocOw?token47960959&langzh_CN 「青稞大模型Weekly」,持…...
Spring Boot自定义注解获取当前登录用户信息
写在前面 在项目开发过程中,难免都要获取当前登录用户的信息。通常的做法,都是开发一个获取用户信息的接口。 如果在本项目中,多处都需要获取登录用户的信息,难不成还要调用自己写的接口吗?显然不用! 以…...
js创建二维空数组
js创建二维空数组 错误使用原因分析分析1举个例子:解释: 正确创建二维数组总结: 错误使用 今天在写代码的时候,需要创建一个长度为2的空二维数组,我当时第一反应就是,使用let arr new Array(2).fill([])&…...
AF3 checkpoint_blocks函数解读
checkpoint_blocks 函数实现了一种分块梯度检查点机制 (checkpoint_blocks),目的是通过分块(chunking)执行神经网络模块,减少内存使用。在深度学习训练中,梯度检查点(activation checkpointing)是一种显存优化技术。该代码可以: 对神经网络的块(blocks)按需分块,并对…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
