为什么CSS关键帧动画在具有范围样式的Vue组件中被破坏?

时间:2017-11-14 10:59:38

标签: javascript css vue.js vuejs2 css-animations

我正在尝试在Vue中实现CSS输入指示器。没有Vue,它看起来像这样:

.typing-indicator {
  background-color: #E6E7ED;
  width: auto;
  border-radius: 50px;
  padding: 20px;
  display: table;
  margin: 0 auto;
  position: relative;
  -webkit-animation: 2s bulge infinite ease-out;
          animation: 2s bulge infinite ease-out;
}
.typing-indicator:before, .typing-indicator:after {
  content: '';
  position: absolute;
  bottom: -2px;
  left: -2px;
  height: 20px;
  width: 20px;
  border-radius: 50%;
  background-color: #E6E7ED;
}
.typing-indicator:after {
  height: 10px;
  width: 10px;
  left: -10px;
  bottom: -10px;
}
.typing-indicator span {
  height: 15px;
  width: 15px;
  float: left;
  margin: 0 1px;
  background-color: #9E9EA1;
  display: block;
  border-radius: 50%;
  opacity: 0.4;
}
.typing-indicator span:nth-of-type(1) {
  -webkit-animation: 1s blink infinite 0.3333s;
          animation: 1s blink infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
  -webkit-animation: 1s blink infinite 0.6666s;
          animation: 1s blink infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
  -webkit-animation: 1s blink infinite 0.9999s;
          animation: 1s blink infinite 0.9999s;
}

@-webkit-keyframes blink {
  50% {
    opacity: 1;
  }
}

@keyframes blink {
  50% {
    opacity: 1;
  }
}
@-webkit-keyframes bulge {
  50% {
    -webkit-transform: scale(1.05);
            transform: scale(1.05);
  }
}
@keyframes bulge {
  50% {
    -webkit-transform: scale(1.05);
            transform: scale(1.05);
  }
}
html {
  display: table;
  height: 100%;
  width: 100%;
}

body {
  display: table-cell;
  vertical-align: middle;
}
<div class="typing-indicator">
  <span></span>
  <span></span>
  <span></span>
</div>

- 来源:http://jsfiddle.net/Arlina/gtttgo93/

问题是,在将scoped属性添加到组件的样式定义(<style lang="scss" scoped>)时,动画不起作用。我认为它可能与应该全局声明的关键帧有关。

.typing-indicator元素位于具有范围样式的组件模板中。

有没有人知道如何在使关键帧动画有效的同时让我的组件具有范围样式?

2 个答案:

答案 0 :(得分:4)

问题

问题在于,在向范围选择器和其他标识符添加ID时,Vue的Webpack加载器(vue-loader)如何错误地解析动画名称。这很重要,因为vue-loader的CSS作用域使用添加到元素的唯一属性来复制CSS作用域的行为。当您的关键帧名称附加ID时,对范围样式的动画规则中的关键帧的引用不会。

你的CSS:

@-webkit-keyframes blink {
  50% {
    opacity: 1;
  }
}

@keyframes blink {
  50% {
    opacity: 1;
  }
}
@-webkit-keyframes bulge {
  50% {
    -webkit-transform: scale(1.05);
            transform: scale(1.05);
  }
}
@keyframes bulge {
  50% {
    -webkit-transform: scale(1.05);
            transform: scale(1.05);
  }
}

.typing-indicator {
  ...
  -webkit-animation: 2s bulge infinite ease-out;
          animation: 2s bulge infinite ease-out;
}

.typing-indicator span:nth-of-type(1) {
  -webkit-animation: 1s blink infinite 0.3333s;
          animation: 1s blink infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
  -webkit-animation: 1s blink infinite 0.6666s;
          animation: 1s blink infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
  -webkit-animation: 1s blink infinite 0.9999s;
          animation: 1s blink infinite 0.9999s;
}

应该转变为:

@-webkit-keyframes blink-data-v-xxxxxxxx {
  50% {
    opacity: 1;
  }
}

@keyframes blink-data-v-xxxxxxxx {
  50% {
    opacity: 1;
  }
}
@-webkit-keyframes bulge-data-v-xxxxxxxx {
  50% {
    -webkit-transform: scale(1.05);
            transform: scale(1.05);
  }
}
@keyframes bulge-data-v-xxxxxxxx {
  50% {
    -webkit-transform: scale(1.05);
            transform: scale(1.05);
  }
}

.typing-indicator {
  ...
  -webkit-animation: 2s bulge-data-v-xxxxxxxx infinite ease-out;
          animation: 2s bulge-data-v-xxxxxxxx infinite ease-out;
}

.typing-indicator span:nth-of-type(1) {
  -webkit-animation: 1s blink-data-v-xxxxxxxx infinite 0.3333s;
          animation: 1s blink-data-v-xxxxxxxx infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
  -webkit-animation: 1s blink-data-v-xxxxxxxx infinite 0.6666s;
          animation: 1s blink-data-v-xxxxxxxx infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
  -webkit-animation: 1s blink-data-v-xxxxxxxx infinite 0.9999s;
          animation: 1s blink-data-v-xxxxxxxx infinite 0.9999s;
}

然而它只会转变为:

@-webkit-keyframes blink-data-v-xxxxxxxx {
  50% {
    opacity: 1;
  }
}

@keyframes blink-data-v-xxxxxxxx {
  50% {
    opacity: 1;
  }
}
@-webkit-keyframes bulge-data-v-xxxxxxxx {
  50% {
    -webkit-transform: scale(1.05);
            transform: scale(1.05);
  }
}
@keyframes bulge-data-v-xxxxxxxx {
  50% {
    -webkit-transform: scale(1.05);
            transform: scale(1.05);
  }
}

.typing-indicator {
  ...
  -webkit-animation: 2s bulge infinite ease-out;
          animation: 2s bulge infinite ease-out;
}

.typing-indicator span:nth-of-type(1) {
  -webkit-animation: 1s blink infinite 0.3333s;
          animation: 1s blink infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
  -webkit-animation: 1s blink infinite 0.6666s;
          animation: 1s blink infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
  -webkit-animation: 1s blink infinite 0.9999s;
          animation: 1s blink infinite 0.9999s;
}
  

需要注意的事项:在实际转换中,动画规则中关键帧名称的引用最后都缺少-data-v-xxxxxxxx。这就是错误。

当前(从47c3317开始)通过获取通过任何空白字符 [1] 分割动画规则的第一个值来识别速记动画规则声明中的动画名称。 。但是,动画属性的正式定义表明动画名称​​可以出现在规则定义中的任何位置。

  

<single-animation> = <time> || <single-timing-function> || <time> || <single-animation-iteration-count> || <single-animation-direction> || <single-animation-fill-mode> || <single-animation-play-state> || [ none | <keyframes-name> ]

- animation形式语法 [2]

因此,当您的动画声明有效时,vue-loader无法解析它。

解决方法

目前的解决方法是将动画名称移动到动画规则声明的开头。您的关键帧声明不需要更改,它们保留在作用域样式表中。您的动画声明现在应如下所示:

.typing-indicator {
  ...
  -webkit-animation: bulge 2s infinite ease-out;
          animation: bulge 2s infinite ease-out;
}
.typing-indicator span:nth-of-type(1) {
  -webkit-animation: blink 1s infinite 0.3333s;
          animation: blink 1s infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
  -webkit-animation: blink 1s infinite 0.6666s;
          animation: blink 1s infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
  -webkit-animation: blink 1s infinite 0.9999s;
          animation: blink 1s infinite 0.9999s;
}

参考

答案 1 :(得分:0)

我遇到了同样的问题,第一个答案确实告诉我为什么它不起作用,但解决方法部分并没有完全解决我的问题......这是我的代码:

/* Animations */
@keyframes moveOut1 {
    from {
        transform: translateY(0) scale(0);
    }
    3% {
        transform: translateY(0.2em) scale(1);
    }
    97% {
        transform: translateY(7.3em) scale(1);
    }
    to {
        transform: translateY(7.5em) scale(0);
    }
}
@keyframes moveOut2 {
    from {
        transform: rotate(60deg) translateY(0) scale(0);
    }
    3% {
        transform: rotate(60deg) translateY(0.2em) scale(1);
    }
    97% {
        transform: rotate(60deg) translateY(7.3em) scale(1);
    }
    to {
        transform: rotate(60deg) translateY(7.5em) scale(0);
    }
}
@keyframes moveOut3 {
    from {
        transform: rotate(120deg) translateY(0) scale(0);
    }
    3% {
        transform: rotate(120deg) translateY(0.2em) scale(1);
    }
    97% {
        transform: rotate(120deg) translateY(7.3em) scale(1);
    }
    to {
        transform: rotate(120deg) translateY(7.5em) scale(0);
    }
}
@keyframes moveOut4 {
    from {
        transform: rotate(180deg) translateY(0) scale(0);
    }
    3% {
        transform: rotate(180deg) translateY(0.2em) scale(1);
    }
    97% {
        transform: rotate(180deg) translateY(7.3em) scale(1);
    }
    to {
        transform: rotate(180deg) translateY(7.5em) scale(0);
    }
}
@keyframes moveOut5 {
    from {
        transform: rotate(240deg) translateY(0) scale(0);
    }
    3% {
        transform: rotate(240deg) translateY(0.2em) scale(1);
    }
    97% {
        transform: rotate(240deg) translateY(7.3em) scale(1);
    }
    to {
        transform: rotate(240deg) translateY(7.5em) scale(0);
    }
}
@keyframes moveOut6 {
    from {
        transform: rotate(300deg) translateY(0) scale(0);
    }
    3% {
        transform: rotate(300deg) translateY(0.2em) scale(1);
    }
    97% {
        transform: rotate(300deg) translateY(7.3em) scale(1);
    }
    to {
        transform: rotate(300deg) translateY(7.5em) scale(0);
    }
}
@keyframes ripple {
    from,
    to {
        width: 0.2em;
    }
    33% {
        width: 2.4em;
    }
}

所以我问了一个朋友,他给我的解决方案就是把css代码放在外面,然后通过

导入到vue组件中
<style>
@import url(./{css_file_name}.css);
</style>

但我不明白这背后的机制......但对我来说,只要它有效就可以了。