js动态设置关键侦@keyframes

js动态设置关键侦@keyframes

1.前置知识

关键侦@keyframes规则通过在动画序列中定义关键侦的样式来控制CSS动画序列的中间步骤

css 复制代码
@keyframes slidein {
  from {
    transform: translateX(0%);
  }

  to {
    transform: translateX(100%);
  }
}
// from 等价于 0%;to 等价与 100%
// 或者
@keyframes slidein {
  0% {
    top: 0;
    left: 0;
  }
  30% {
    top: 50px;
  }
  68%,
  72% {
    left: 50px;
  }
  100% {
    top: 100px;
    left: 100%;
  }
}

注意 ,如果在CSS中定义了两个相同名字的keyframes,后这会覆盖前者

如上图所示,定义了两个相同的动画侦之后,最终在浏览器中应用的是后者

2.js动态控制keyframes

背景

在 Vue 项目中由于 css 样式是直接写在 style 标签中的,那些值都是事先写死的,比如说上面的 translateX(disX),disX 是通过 js 动态计算出来的。如果要实现动画的效果是通过js动态计算出来的,会比较困难。所以可以通过 js 去设置 styleSheet 里面的样式规则,从而能够动态的控制 keyframes

StyleSheet是javaScript中表示样式表的接口,而styleSheet是一个DOM元素的对应属性,用于获取该元素所关联的样式表

  • 获取样式表:通过styleSheet属性可以获取元素关联的样式表
js 复制代码
// 获取第一个样式表
const firstStyleSheet = document.styleSheet[0]
// document.styleSheet 可以理解为一个二维数组(但是不是数组)
// 有多个样式表,每个样式表中都有多条规则
  • 插入样式列表:通过样式列表的insertRules方法可以在样式列表中插入新的规则
js 复制代码
const styleSheet = document.styleSheet[0]
styleSheet.insertRule(`.styleSheetCls { width: 200px; height: 200px}`,0)
// insertRule 方法中的第二个参数表示将样式插入样式表的哪里
// 这个规则会出现在第一个样式表的第一条
  • 删除样式规则:使用样式表的deleteRule方法可以删除指定位置的规则
js 复制代码
const styleSheet = document.styleSheet[0]
styleSheet.deleteRule(0)
// 删除第一个样式表的第一条

我们可以通过styleSheet的insertRule方法动态的添加关键侦样式

html 复制代码
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>动态添加 Keyframes</title>
  <style id="dynamic-styles"></style>
</head>
<body>
  <div id="myDiv"></div>

  <script>
    // 获取样式表
    // 这里始终将新的 keyframes 规则添加在第一个样式表的第一条
    const styleSheet = document.styleSheet[0];
	let dis = 0
    //... 动态计算 dis 的值
    
    // 动态创建 @keyframes
    const keyframesName = 'dynamicAnimation';
    const keyframesRule = `@keyframes ${keyframesName} {
      0% { transform: translateX(${dis}px); }
      25% { transform: translateX(-${dis}px) rotate(0.5deg); }
      50% { transform: translateX(${dis}px) rotate(-0.5deg); }
      75% { transform: translateX(-${dis}px) rotate(0.5deg); }
      100% { transform: translateX(0); }
    }`
     `@keyframes dynamicAnimation{
      0% { transform: translateX(5px); }
      100% { transform: translateX(0); }
    }`
    // 每次添加新的规则之前,可以将之前的规则给删除掉,这样就可以避免第一个样式表的规则里面有多条重复名称的 keyframes,避免相同名字的 keyframes 前者被后者覆盖
    // 获取第一个样式表的第一条规则的名称
    const firstRules = styleSheet.rules || styleSheet.cssRules
    // 这里是以防第一条规则不是 keyframes 规则,从而导致获取 name 失败
    const ruleName = firstRules[0].name ? firstRules[0].name : ''
    if(ruleName === keyframesName) {
        /**
        * 这里能够直接删除,是因为我始终将 keyframes 添加在第一个样式表的第一条规则中
        * 如果不能确定样式位置,那么就需要遍历整个样式表,找到目标样式表的位置
        * document.styleSheet 可以理解为一个二维数组(但是不是数组,不适合使用数组的遍历方式进行遍历)
        * 有多个样式表,每个表中都有多条规则
        **/ 
        styleSheet.deleteRule(0)
    }
    // 这里始终将新的 keyframes 规则添加在第一个样式表的第一条
    styleSheet.insertRule(keyframesRule, 0);

    // 动态应用 @keyframes
    const myDiv = document.getElementById('myDiv');
    myDiv.style.animation = `${keyframesName} 2s ease-in-out`;
  </script>
</body>
</html>
3. 编写技巧
  • 在编写keyframes规则时,我比较推荐在在style标签中将动画规则写好了在复制到JavaScript逻辑代码中,因为如果动画规则编写有问题,那么在insertRule插入样式的时候,可能会导致样式表识别不了
  • 查看是否添加成功,可以在控制台打印出来样式表,寻找我们添加的规则,如下图

    可以看到第一个样式表中的第一个样式是我们添加的keyframes样式,并且识别成功了会有CSSKeyframesRule的属性,里面就是我们定义的每一帧的动画样式
相关推荐
晗夜未央32 分钟前
任务队列反复失败,先分清重试、阻塞和结果待核对
开发语言·javascript
jktantan1 小时前
每个节点 41 字节:把一棵百万节点树拆进 14 个 typed array
前端·javascript·vue.js·算法·typescript
我命由我123452 小时前
访客系统形式(有用户概念、无用户概念)
java·开发语言·前端·javascript·python·产品运营·产品经理
程序员大阳3 小时前
副队长JavaScript教程(65)-详解JSON:轻量级数据交换格式
javascript·json·序列化·反序列化·stringify·parse
paopaokaka_luck4 小时前
基于springboot+vue的益暖微光公益服务平台(DeepSeek公益助手、善款信息追溯、志愿服务积分闭环、ECharts运营分析、活动状态自动流转)
java·前端·javascript·spring boot·mysql·架构·echarts
栀椩4 小时前
Electron 内嵌页面跨域问题(CORS/PNA)解决全记录
前端·javascript·electron
SEO_juper5 小时前
Chrome 扩展一键查看当前页面 SEO 信息:不用切页面,点一下全出来
前端·javascript·chrome
Highcharts.js5 小时前
CSUN 2026|Highcharts无障碍数据与AI分享
javascript·人工智能·数据分析·highcharts·图表开发
系统集成-鹰翔5 小时前
ERP推单数据库怎么备份:SQLite WAL模式下只复制db文件为什么可能漏任务
javascript·数据库·经验分享·后端
小大宇6 小时前
Vue知识点-ElementPlus-05 输入框
前端·javascript·vue.js