js 动态修改css动画@keyframes (基于vue讲解 兼容ie)

21 篇文章 1 订阅
12 篇文章 0 订阅

先看效果

已有的css样式 动画效果是2s时间由透明变为不透明;
在这里插入图片描述
在这里插入图片描述
修改后的动画效果
在这里插入图片描述
在这里插入图片描述

styleSheets对象

Document.styleSheets 只读属性,
返回一个由 StyleSheet 对象组成的 StyleSheetList,
每个 StyleSheet 对象都是一个文档中链接或嵌入的样式表。

let styleSheetList = document.styleSheets;
它是一个 StyleSheet 对象的有序集合。
styleSheetList.item(index) 或 styleSheetList[index] 
根据它的索引(索引基于0)返回一个单独的样式表对象。

CSSRule 对象

cssRule接口表示一个CSS规则。规则存在若干种类型。

CSSStyleRule  //  CSSRule.STYLE_RULE ==1
 // CSSRule.CHARSET_RULE ==2
CSSImportRule //CSSRule.IMPORT_RULE ==3
CSSMediaRule  // @media 规则  CSSRule.MEDIA_RULE==4
CSSFontFaceRule //CSSRule.FONT_FACE_RULE ==5
CSSPageRule //CSSRule.PAGE_RULE==6
CSSKeyframesRule // CSSRule.KEYFRAMES_RULE ==7  对应于@keyframes at-rule的完整的关键帧
CSSKeyframeRule // CSSRule.KEYFRAME_RULE==8 对应于@keyframes at-rule的单个关键帧
CSSNamespaceRule //CSSRule.NAMESPACE_RULE==10
CSSCounterStyleRule
CSSDocumentRule
CSSSupportsRule //CSSRule.SUPPORTS_RULE ==12
CSSFontFeatureValuesRule
CSSViewportRule

其中 CSSKeyframesRule 规则 定义了 @keyframes 动画的完整的关键帧;

查找动画关键帧样式位置

通过遍历 找到 document.styleSheets下的cssRules获取属性表对象

//例如
document.styleSheets[0].cssRules
//返回 CSSRuleList

在这里插入图片描述
其中type代表cssRule规则类型的值,而type 等于7 代表完整的动画帧的规则CSSKeyframesRule
所以我们要修改动画样式 需要先找到 type==7的列表;

修改动画关键帧样式

方法
//样式表中插入一条规则。
appendRule(rule, index) //Chrome  IE9及以上 FireFox
insertRule(rule, index) // 暂未找到那个版本支持
addRule(selector, rules, [index])// IE 特有(以下,以上被删除了)
//样式表中插入删除条规则。
removeRule([index]) IE // IE 特有( ie9 以下,以上被删除了)
deleteRule(index) //Chrome  IE9及以上 FireFox

注意:修改时一定要找到所有的样式表修改;如下图存在两个同名的样式表,
在这里插入图片描述
两个同名的样式表都要修改,否则样式不生效;
如下图修改是只修改了最后一列样式表
f12查看样式修改成功!
但是会出现复用当前组件时,复用两次以上的动画不生效!

在这里插入图片描述
注意:由于vue需要打包,vue会把css生成的样式打包成link引入的方式,当使用link引入方式时无法通过cssRules进行查找

在这里插入图片描述
所以这里我们需要使用appendRule或者insertRule插入一条规则;
在这里插入图片描述

vue 代码参考 (细节请自行修改)

data
    animationName: "",
      sheetsIndex: "",
      keyframeIndex: "",
      // 动画总耗时 (毫秒)
      animationDuration: "350",
      // 动画关键帧数组
      animationArr: [],
methods
    // 改变窗口动画
    changeAnimation() {
      // 动画加载一定程度后再加载视图,否则性能差,出现掉帧情况
      this.viewShow = false;
      setTimeout(() => {
        this.viewShow = true;
      }, (this.animationDuration / 100) * 75);
      // 设置动画
      this.animationArr = [
        `0% {
          left: ${String(window.$clientX) ? window.$clientX + "px" : "0%"};
          top: ${String(window.$clientY) ? window.$clientY + "px" : "100%"};
          width: 0px;
          height: 0px;
          opacity: 0.5;
        }`,
        `100% {
           left: ${this.left};
           top: ${this.top};
           width: ${this.width};
           height: ${this.height};
           opacity: 1;
        }`,
      ];
      let selector = ".no_router_popup_animation";
      this.changeKeyframes(selector, "noRouterPopup", this.animationArr);
    },
    // 寻找 css不是link引入的
    findNoLinkSheet() {
      var styleSheets = document.styleSheets;
      console.log("进入了findNoLinkSheet",styleSheets);

      let ssLength = styleSheets.length;
      for (var i = 0; i < ssLength; i++) {
        try {
          // 谷歌、火狐浏览器空时返回错误; uc浏览器 空为null;
          styleSheets[i].cssRules || styleSheets[i].rules;
          if (!styleSheets[i].cssRules && !styleSheets[i].rules) {
            continue;
          }
        } catch {
          continue;
        }
        this.sheetsIndex = i;
        console.log("this.sheetsIndex", this.sheetsIndex);
        break;
      }
    },
    // 添加新动画
    addKeyframes(selector, animName, AnimationArr) {
      var styleSheets = document.styleSheets;
      let animationString = "";
      AnimationArr.forEach((item) => {
        // keyframesArr[k].insertRule(item);
        animationString += item;
      });
      let Keyframes = `@keyframes ${animName}{${animationString}}`;
      console.log("Keyframes");

      if (styleSheets[this.sheetsIndex].appendRule) {
        styleSheets[this.sheetsIndex].insertRule =
          styleSheets[this.sheetsIndex].appendRule;
      }
      styleSheets[this.sheetsIndex].insertRule(Keyframes);
      console.log(
        "styleSheets[this.sheetsIndex]",
        styleSheets[this.sheetsIndex]
      );

      this.animationName = animName;
      // 动画总耗时设置
      let selectorDom = document.querySelectorAll(selector);
      selectorDom[selectorDom.length - 1].style.animationDuration =
        this.animationDuration + "ms";
      // 重新指定动画名字使之生效
      selectorDom[
        selectorDom.length - 1
      ].style.animationName = this.animationName;
    },
    // 查找动画keyframe
    findKeyframesRule(animName) {
      var styleSheets = document.styleSheets;
      // console.log("styleSheets", styleSheets);

      let ssLength = styleSheets.length;
      for (var i = 0; i < ssLength; i++) {
        try {
          // 谷歌、火狐浏览器空时返回错误; uc浏览器 空为null;
          styleSheets[i].cssRules || styleSheets[i].rules;
          if (!styleSheets[i].cssRules && !styleSheets[i].rules) {
            continue;
          }
        } catch {
          continue;
        }
        var oRules = styleSheets[i].cssRules
          ? styleSheets[i].cssRules
          : styleSheets[i].rules;

        let oRulesLength = oRules.length;
        for (var x = 0; x < oRulesLength; x++) {
          // 跳过name为 undefined
          if (!oRules[x].name) {
            continue;
          }
          let rule = oRules[x];

          if (
            String(rule.name).indexOf(animName) != -1 &&
            (rule.type == CSSRule.KEYFRAMES_RULE ||
              rule.type == CSSRule.WEBKIT_KEYFRAMES_RULE)
          ) {
            // console.log("rule.name", rule.name);
            // console.log("oRules", oRules);

            // 递归查找keyframes
            return this.findKeyframesCallBack(oRules, animName, x);
          }
        }
      }
    },
    /**
     * @name: 递归查找keyframes
     * @test: test font
     * @msg:
     * @param {*} oRules document.styleSheets[i].cssRules||document.styleSheets[i].rules
     * @param {*} animName 修改的动画名称
     * @param {*} index  cssRules或rules数组下标
     * @param {*} ruleArr  保存具有与animName的keyframes数组
     * @return {*} ruleArr
     */
    findKeyframesCallBack(oRules, animName, index, ruleArr = []) {
      let ruleItem = oRules[index];
      if (
        String(ruleItem.name).indexOf(animName) != -1 &&
        (ruleItem.type == CSSRule.KEYFRAMES_RULE ||
          ruleItem.type == CSSRule.WEBKIT_KEYFRAMES_RULE)
      ) {
        this.animationName = ruleItem.name;
        this.keyframeIndex = index;
        ruleArr.push(ruleItem);
        return this.findKeyframesCallBack(oRules, animName, index + 1, ruleArr);
      } else {
        return ruleArr;
      }
    },
    // 改变已有动画
    changeKeyframes(selector, animName, AnimationArr) {
      var keyframesArr = [];
      try {
        keyframesArr = this.findKeyframesRule(animName);
      } catch {
        return;
      }
      // 如果找不到则添加一个动画
      if (!keyframesArr) {
        console.log("!keyframesArr", !keyframesArr);
        this.findNoLinkSheet();
        this.addKeyframes(selector, animName, AnimationArr);
        return;
      }
      const keyframesArrLength = keyframesArr.length;
      // 遍历修改所有的keyframes 不全部修改会出现动画不生效 或者只生效一次
      for (var k = 0; k < keyframesArrLength; k++) {
        // 兼容ie (暂未验证)
        if (!keyframesArr[k].deleteRule) {
          keyframesArr[k].deleteRule = keyframesArr[k].removeRule;
        }
        // 删除已经存在的开始和结束帧
        keyframesArr[k].deleteRule("0%");
        keyframesArr[k].deleteRule("100%");
        // 兼容谷歌与火狐
        if (keyframesArr[k].appendRule) {
          keyframesArr[k].insertRule = keyframesArr[k].appendRule;
        }
        // // 兼容ie (暂未验证)
        // else if (keyframesArr[k].addRule) {
        //   keyframesArr[k].insertRule = function (rule, index = 0) {
        //     let selector = rule.split("{")[0];
        //     let selectorLength = selector.length;
        //     let style = rule.slice(selectorLength);
        //     return keyframesArr[k].addRule(selector, style, index);
        //   };
        // }

        // 添加动画
        AnimationArr.forEach((item) => {
          keyframesArr[k].insertRule(item);
        });
      }

      var styleSheets = document.styleSheets;

      // this.animationName = animName;
      // 动画总耗时设置
      let selectorDom = document.querySelectorAll(selector);
      selectorDom[selectorDom.length - 1].style.animationDuration =
        this.animationDuration + "ms";
      // 重新指定动画名字使之生效
      selectorDom[
        selectorDom.length - 1
      ].style.animationName = this.animationName;
    },
  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值