美文网首页
banner上的利益点碎片化切换动效

banner上的利益点碎片化切换动效

作者: 羽晞yose | 来源:发表于2019-11-28 17:30 被阅读0次

因为活动期间内切换的利益点太多(图片是运营自行配置的),一个是设计的工作量太大,另一方面是帧动画体积太大,即使我制作完压缩后,一次往返动画也有接近2兆,因为运维的限制,图片超过200K不予上传,所以,自行写一个动效来实现这个帧动画

切换动效最后呈现结果

从设计稿视觉可以得到几个信息点:

  1. 图片被切分为多个碎片,成为10*10
  2. 图片轮换以列为单位,列动画执行存在延时,视觉上最多有两列在发生翻转
  3. 每列10个碎片均以x轴进行翻转

实现思路:

  1. 填充容器,每个碎片都有3D翻转视觉,因此每个小碎片都有正反两面
  2. 将碎片容器进行定位,按照列行循环的方式进行定位
  3. 按列数进行延时动画触发(比如setTimeout,不过我用了tweenMax,所以是用的自带方法)
    额外说明:入参里并没有对图片数量进行限制,但实现只拿第一第二张图,因为项目时间而且动效复用可能性极低,所以不会过多的完善与拓展,有需要的同学自行拓展

实现代码如下:

<template>
    <div ref="container" class="v-container">
        <div ref="panel" class="v-panel"></div>
    </div>
</template>

<script>
import Tool from '@/mod/util/tool/1.0/tool.js';
import { TweenMax } from 'gsap'; // gsap动画库

export default {
    name: 'v-effect',
    props: {
        // 接收图片路径,只能是两个图片,这里没做限制,原因上面说了
        imgList: {
            type: Array,
            default: () => []
        }
    },
    data () {
        return {
            imgNum: 0,
            rows: 10,
            colums: 10,
            container: null,
            panel: null
        };
    },
    methods: {
        // 图片碎片化,填充容器,暂时只支持两张图片互相切换,不可多张轮换
        _generatePanels () {
            let vDom = '';
            let count = this.rows * this.colums;
            let [x, y] = [0, 0];
            let {clientWidth: cw, clientHeight: ch} = this.container; // containerWidth, containerHeight: 容器宽高
            let [fw, fh] = [~~(cw / this.colums), ~~(ch / this.rows)]; // fragmentWidth, fragmengHeight: 碎片宽高,必须取整,否则小数点能让效果出现间距

            for (let i = 0; i < count; i++) {
                vDom += `
                <div id="item_${i}" class="panelItem trans3d" style="left: ${x * fw}px; top: ${y * fh}px; width: ${fw}px; height: ${fh}px;">
                    <div class="front" style="background: url(${Tool.addDomain(this.imgList[this.imgNum])}) -${x * fw}px -${y * fh}px no-repeat / ${cw}px ${ch}px;"></div>
                    <div class="back" style="background: url(${Tool.addDomain(this.imgList[this.imgNum + 1])}) -${x * fw}px -${y * fh}px no-repeat / ${cw}px ${ch}px;;"></div>
                </div>`;

                y++;

                if (y === this.rows) {
                    y = 0;
                    x++;
                }
            }

            this.panel.innerHTML = vDom;
        },
        // 碎片动效
        _effect () {
            this._generatePanels();

            let panelsRows = this.panel.querySelectorAll('.panelItem');
            let arrPanelsRows = Array.prototype.slice.call(panelsRows);

            for (let i = 0; i < this.colums; i++) {
                TweenMax.delayedCall(0.2 * i, () => {
                    let groupPanel = arrPanelsRows.slice(i * this.rows, this.rows * (i + 1));
                    TweenMax.staggerTo(groupPanel, 0.3, {rotationX: 180, yoyo: true, repeat: -1, repeatDelay: 5});
                });
            }
        },
        init () {
            this.container = this.$refs.container;
            this.panel = this.$refs.panel;
            this._effect();
        }
    },
    mounted () {
        this.init();
    }
};
</script>

<style lang="less">
/* 底层有pxToRem,自行webpack引入插件 */

.v-container {
    position:absolute;
    top: 548px;
    left: 125px;
    width: 500px;
    height: 170px;
    perspective: 600px;
}

.v-panel {
    position:absolute;
    width: 100%;
    height: 100%;
    transform-style: preserve-3d;
}

.panelItem {
    position: absolute;
    transform-style: preserve-3d;
}

.front,
.back {
    position: absolute;
    top: 0;
    left: 0;
    .size(100%);
    backface-visibility: hidden;
}

.back {
    transform: rotateX(180deg);
}
</style>

这里有几个要点需要说明:

  1. 图片的容器必须取整,因为移动端转为rem单位的原因,我们js中获取容器大小是会出现小数点的。小数点必须处理掉,否则后续的图片定位会有出现间隙
  2. 行数与列数的分割刚好设计稿为10 * 10,假设结果带小数点的,碎片的衔接大概率会出现间距。这也是为什么上面说必须取整,因此碎片定位的时候都是整数,不会出现衔接间隙

相关文章

网友评论

      本文标题:banner上的利益点碎片化切换动效

      本文链接:https://www.haomeiwen.com/subject/ejsywctx.html