渐入渐出特效的灵活运用

1,891 阅读2分钟

(1)背景:

需要为TAB切换实现一个图片渐入渐出的效果。

(2)无特效时的实现方案:

div

<img class="product-service-img" :src="activeItem.img" />

(3)方案一:background-image + transition(animation)

div:

<div
  class="product-service-img"
  :style="{backgroundImage: `url(${activeItem.img})`, height: activeItem.height}">
</div>

style:

.product-service-img {
      transition: all .5s ease;
      background-size: contain;
      background-repeat: no-repeat;
      background-position-y: center;
      box-sizing: border-box;
      position: absolute;
      border-radius: 8px;
      left: 540px;
      width: 660px;
      top: 50%;
      transform: translateY(-50%);
}

出现的问题:不兼容(火狐、IE等不支持)

原因:W3C标准中明确background-image属性是不支持动画的

(4)方案二:animation + setTimeOut

遇到的问题:

1、如何在只改变src的情况下完成渐入渐出?

2、一个页面多次引用该组件时如何避免误操作即如何使各组件相互独立?(document.getElement···)

解决方案:

1、通过setTimeout+class给当前元素先删除再添加class,结合opacity的改变触发animation

2、采用${_uid}(全局唯一标识)标记组件

div:

<img class="product-service-img" :src="activeItem.img" :id="`${_uid}-img`" />

css:

@keyframes fade-in 
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1
  }
}
.fade-in {
    animation: fade-in 1s ease-in-out backwards;
}

js:

watch: {
    active() {
      const img = document.getElementById(`${this._uid}-img`);
      if (!img) return;
      this.hideElement(img);
      setTimeout(() => {
        this.showElement(img);
      }, 0);
    },
},
hideElement(dom) {
      if (!dom) return;
      dom.classList.remove('fade-in');
      dom.style.opacity = 0;
},

showElement(dom) {
      if (!dom) return;
      dom.classList.add('fade-in');
      dom.style.opacity = 1;
},

出现了问题:切换时闪烁

找寻原因:缺少背景色(图片与背景色相近时,闪烁不明显;但背景色相差较大时,闪烁极其明显)

思考:如何解决?为图片添加一个背景色?

结论:不可行,如果图片颜色各不一致,无法取有效背景色。

思考:其他人是怎么解决的?

高德:忽略兼容性,采用background-image + transition的方法

京东:忽略闪烁,采用transition

其他官网:忽略闪烁,采用transition

思考:background-image + transition(animation)的原理是什么?

缺陷:当背景大小不一致时,会出现伸缩效果

结论:在改变的一瞬间,存在渐入和渐出两种效果,一张图无法实现

(5)方案三(最终方案):transition

思路:

多张图片重叠在一起,只有激活状态的图片opacity为1,其他的图片opacity为0

当切换图片时,渐出的图片慢一些,作为渐出图片的背景色

渐入的图片快一些,覆盖之前存在的图片

同时利用判断动态处理class,因为组件自带作用域,所以在不使用document的时候,不会引起冲突

div

<img
        v-for="(item, index) in list"
        :key="index"
        :src="item.img"
        class="product-service-img"
        :class="{'fade-out': active === index, 'fade-in':active !== index}"
/>

style

.fade-in {
    opacity: 0;
    transition: all .6s ease-in-out;
  }
  .fade-out {
    opacity: 1;
    z-index: 1;
    transition: all .2s ease-in-out;
  }

(6)总结:

方案一 background-image + transition(animation)方案二 animation + setTimeOut方案三 transition
方案一 background-image + transition(animation)方案二 animation + setTimeOut方案三 transition
兼容性较差较好较好
流畅程度较好较差较好
组件冲突
性能消耗首次加载只加载一张图片,每次切换都会重新请求一次图片首次加载只加载一张图片,每次切换都会重新请求一次图片首次加载需加载多张图片,切换TAB时无需再加载图片