js修改元素的keyframes样式

demo效果:

通过js修改元素的keyframes样式的使用场景非常少, 一般用于元素的动画末节点不固定且动画复杂(比如分为多段不同效果的动画);

记录一下方法, 权当保存一种思路.

demo调用:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<style>
		#block { width: 20px; height: 20px; background: lightblue; position: absolute; left: 20px; top: 20px; }
		.ani { animation: myFrame .5s forwards; }
		.btn { position: absolute; left: 20px; top: 220px; }

		@keyframes myFrame {
			from { width: 20px; height: 20px; left: 20px; top: 20px; }
			to { width: 99px; height: 99px; left: 99px; top: 99px; }
		}
	</style>
</head>
<body>
	<div id="block" class="ani"></div>
	<button id="btn" class="btn">随机生成animation动效</button>
</body>
<script src="./editKeyframes.js"></script>
<script>
const frame_edit = _editKeyframes('myFrame')

// 记录最后操作的目标点
let from_str = 'width: 99px; height: 99px; left: 99px; top: 99px;'

const getRandom = () => { // 随机生成大于等于20且小于100的整数
	return Math.floor(Math.random() * 80 + 20)
}

btn.onclick = () => {
	/*
	注* 如果在dom的className没有改变的情况下直接修改keyframes样式将无法实现动效 
	所以修改流程为: 去除dom的className -> 修改keyframes -> 重新给dom设置className(须异步修改)
	*/
	block.style = from_str // 在清除dom的className之前把dom的样式固定在动画的末端
	block.className = '' // 修改目标元素的className

	const customStr = `width: ${getRandom()}px; height: ${getRandom()}px; left: ${getRandom()}px; top: ${getRandom()}px;`

	const keyframes_str = `
		{
			from { ${from_str}; }
			to { ${customStr} }
		}
	`
	from_str = customStr

	frame_edit(keyframes_str)

	setTimeout(() => { // 异步目标修改元素的className
		block.className = 'ani'
	})
}
</script>
</html>

功能代码实现(editKeyframes.js):

/**
 * 修改名为keyframesName的keyframes样式 
 * 
 * @param {String} keyframesName keyframes名称 
 * 
 * @returns {Function} 柯里化后的最终处理方法函数 
 * 
 * @example 
 * const edit = _editKeyframes(KEYFRAMESNAME) 
 * edit('from {...} to {...}')
 * 
 * 注* 如果在dom的className没有改变的情况下直接修改keyframes样式将无法实现动效 
 *     所以修改流程为: 去除dom的className -> 修改keyframes -> 重新给dom设置className
 */
export const _editKeyframes = (keyframesName) => {
  let sheetObj = null
  let ss = Array.from(document.styleSheets).filter(styleSheet => {
    return !styleSheet.href || styleSheet.href.startsWith(window.location.origin)
  })
  if (!!ss.length) {
    for (let i = 0; i < ss.length; ++i) {
      for (let j = 0; j < ss[i].cssRules.length; ++j) {
        if (ss[i].cssRules[j].type === window.CSSRule.KEYFRAMES_RULE && ss[i].cssRules[j].name === keyframesName) {
          sheetObj = {
            has: true,
            value: ss[i],
          }
          break
        }
      }
      if (sheetObj === null) {
        sheetObj = {
          has: false,
          value: ss[0],
        }
      }
    }
  } else {
    document.head.appendChild(document.createElement('style'))
    ss = Array.from(document.styleSheets).filter(styleSheet => {
      return !styleSheet.href || styleSheet.href.startsWith(window.location.origin)
    })
    sheetObj = {
      has: false,
      value: ss[0],
    }
  }

  return function (cssStr) {
    if (sheetObj.has) {
      const index = [...sheetObj.value.cssRules].findIndex(val => {
        return val.name === keyframesName
      })
      sheetObj.value.deleteRule(index)
      sheetObj.value.insertRule(`@keyframes ${keyframesName} ${cssStr}`)
    } else {
      sheetObj.value.insertRule(`@keyframes ${keyframesName} ${cssStr}`)
      sheetObj.has = true
    }
  }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值