动画动效之红包雨

思路

  在页面顶部之上,放置固定数量的红包,每秒随机降落5-10个,降落时给每个红包添加各自的动画,红包降落到页面底部时消失,降落固定时间。

 

效果图

 

 

H5

1.生成红包

  ViewModel.packetNum

  是红包总数量,这里我是一共200个红包,每秒随机降落5-10个,一共20秒。

  srcList

  放置红包显示图片,可以多个,生成红包数据时,会随机从srcList中获取

  packet.top

  红包是定位在页面顶部之上的,所以下方packet.top是-80(样式布局中红包高度80,可以根据实际情况替换)。

  packet.left

  为了保证红包随机降落的位置不一样,所以定位时packet.left也是随机生成的,但是要保证在页面显示范围之内.

  speed

  生成随机掉落时间,保证每个掉落时间保持在3秒到5.5秒之间,时间可以根据实际需求进行修改。掉落时间不一样,但是掉落高度是一样的,这样就会让红包一快一慢,看着更加真实。

initList: function(callback) {
        var that = window;
        var ViewModel = that.activeRedData.ViewModel;

        //建立临时红包列表
        var packetList = [];
        //建立临时红包图片数组
        var srcList = [ViewModel.imgurl, ViewModel.imgurl];
        //生成初始化红包
        for (var i = 0; i < ViewModel.packetNum; i++) {
            // 生成随机位置(水平位置)
            var left = Math.random() *  document.body.clientWidth - 20;
            // 优化位置,防止红包越界现象,保证每个红包都在屏幕之内
            if (left < 0) {
                left += 20;
            } else if (left >  document.body.clientWidth) {
                left -= 20;
            }
            // 建立临时单个红包
            var packet = {
                src: srcList[Math.ceil(Math.random() * 2) - 1],
                top: -80,
                left: left,
                speed: Math.random() * 2500 + 1000 //生成随机掉落时间,保证每个掉落时间保持在3秒到5.5秒之间
            }
            // 将单个红包装入临时红包列表
            packetList.push(packet);
        }
        // 将生成的临时红包列表更新至页面数据,页面内进行渲染
        ViewModel.packetList = packetList;
        activeRedMethods.renderList(callback);
    },

2.渲染红包

  上面生成了红包数据packetList,然后在把packetList数据渲染到页面,这里就不贴代码了。(最后页面底部会放置所有代码)

3.设置计时器,控制每秒红包下落

  showInter

  20秒计时器,

  showNum

  当前掉落红包的个数

  startAnimation

  红包掉落动画方法,

setInter: function(callback){
        var that = window;
        var ViewModel = that.activeRedData.ViewModel;
        var packetList = ViewModel.packetList;
        // 初始化动画执行当前索引
        var tempIndex = 0;
        var time  = 0;
        // 开始定时器,每隔1秒掉落一次红包
        that.activeRedData.ViewModel.showInter = setInterval(function() {
            // 生成当前掉落红包的个数,5-10个
            var showNum = Math.ceil(Math.random() * 10);
            if(showNum<5){
                showNum = 5;
            }
            // 防止数组越界
            if (time>=20) {
                // 20秒之后,清除定时器
                clearInterval(that.activeRedData.ViewModel.showInter);
                if(callback){
                    callback();
                }
            } else {
                for (var i = 0; i < showNum; i++) {
                    var idx = tempIndex + i;
                    activeRedMethods.startAnimation(idx);
                }
                tempIndex += showNum;
            }
            time += 1;
        }, 1000)
    },

4.设置红包下落动效

  这里的布局是,每个红包都是一个div内有一个红包img。

  所以这里红包下落动效就是外层div添加divanimation,从顶部平移到底部,
  内存图片通过rotate旋转,通过speed下落时间控制旋转度数,每秒旋转360度。

startAnimation: function(idx){
        var that = window;
        var ViewModel = that.activeRedData.ViewModel;
        var packetList = ViewModel.packetList;
        var cla = ".view" + idx;
        var anTime = parseInt(packetList[idx].speed) / 1000;
        var str = "divtranslate "+anTime+"s linear 1";
        var cla1 = ".red-packet" + idx;
        var rotateNum = anTime * 360;
        var strNum = "rotate("+rotateNum+"deg)";
        var strTime = anTime + "s linear"
        $(cla1).css("transform",strNum).css("transition",strTime);
        $(cla).css("animation",str);
    },
.divanimation {
    animation: divtranslate 3s linear 1;
}
@keyframes divtranslate {
    0% {
        transform: translateY(0);
    }

    100% {
        transform: translateY(100vh);
    }
}

至此,红包雨开发完成。

5.代码

<!-- 红包雨 -->
<div class="redpacketmaskview"></div>
<div class="redpacketview"></div>
/* 红包雨 */
.redpacketmaskview {
    width: 100%;
    height: 100%;
    position: fixed;
    left: 0;
    top: 0;
    background-color: rgba(0, 0, 0, 1);
    z-index: 999;
    display: none;
}

.redpacketview {
    box-sizing: border-box;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000;
    overflow: hidden;
    display: none;
}

.redview {
    width: 1.01rem;
    height: 1.21rem;
}

.red-packet {
    width: 1.01rem;
    height: 1.21rem;
}

.divanimation {
    animation: divtranslate 3s linear 1;
}

@keyframes divtranslate {
    0% {
        transform: translateY(0);
    }

    100% {
        transform: translateY(100vh);
    }
}
var activeRedData = {
    ViewModel: {
        imgurl: "images/popup/redpacket.png",
        windowWidth: "", //窗口宽度
        windowHeigh: "750", //窗口高度
        packetList: [{}], //红包队列
        packetNum: 200, //总共红包的数量
        showInter: '' // 循环动画定时器
    }
}

var activeRedMethods = {
    initList: function(callback) {
        var that = window;
        var ViewModel = that.activeRedData.ViewModel;

        //建立临时红包列表
        var packetList = [];
        //建立临时红包图片数组
        var srcList = [ViewModel.imgurl, ViewModel.imgurl];
        //生成初始化红包
        for (var i = 0; i < ViewModel.packetNum; i++) {
            // 生成随机位置(水平位置)
            var left = Math.random() *  document.body.clientWidth - 20;
            // 优化位置,防止红包越界现象,保证每个红包都在屏幕之内
            if (left < 0) {
                left += 20;
            } else if (left >  document.body.clientWidth) {
                left -= 20;
            }
            // 建立临时单个红包
            var packet = {
                src: srcList[Math.ceil(Math.random() * 2) - 1],
                top: -80,
                left: left,
                speed: Math.random() * 2500 + 1000 //生成随机掉落时间,保证每个掉落时间保持在3秒到5.5秒之间
            }
            // 将单个红包装入临时红包列表
            packetList.push(packet);
        }
        // 将生成的临时红包列表更新至页面数据,页面内进行渲染
        ViewModel.packetList = packetList;
        activeRedMethods.renderList(callback);
    },
    renderList: function(callback){
        var that = window;
        var ViewModel = that.activeRedData.ViewModel;
        var packetList = ViewModel.packetList;
        var html = '';
        for (var i = 0; i < packetList.length; i++) {
            var cla = "view" + i;
            var cla1 = "red-packet" + i;
            html += '<div class="redview '+cla+'" style="position:fixed;top:'+packetList[i].top+'px;left:'+packetList[i].left+'px;" onclick="activeRedMethods.onClickRedPacketBtn()">';
            html += '<img class="red-packet '+cla1+'" src="'+packetList[i].src+'"/>';
            html += '</div>';
        }
        $(".redpacketview").html(html);
        activeRedMethods.setInter(callback);
    },
    //计时器,设置动画
    setInter: function(callback){
        var that = window;
        var ViewModel = that.activeRedData.ViewModel;
        var packetList = ViewModel.packetList;
        // 初始化动画执行当前索引
        var tempIndex = 0;
        var time  = 0;
        // 开始定时器,每隔1秒掉落一次红包
        that.activeRedData.ViewModel.showInter = setInterval(function() {
            // 生成当前掉落红包的个数,1-3个
            var showNum = Math.ceil(Math.random() * 10);
            if(showNum<5){
                showNum = 5;
            }
            // 防止数组越界
            if (time>=20) {
                // 20秒之后,清除定时器
                clearInterval(that.activeRedData.ViewModel.showInter);
                if(callback){
                    callback();
                }
            } else {
                for (var i = 0; i < showNum; i++) {
                    var idx = tempIndex + i;
                    activeRedMethods.startAnimation(idx);
                }
                tempIndex += showNum;
            }
            time += 1;
        }, 1000)
    },
    startAnimation: function(idx){
        var that = window;
        var ViewModel = that.activeRedData.ViewModel;
        var packetList = ViewModel.packetList;
        var cla = ".view" + idx;
        var anTime = parseInt(packetList[idx].speed) / 1000;
        var str = "divtranslate "+anTime+"s linear 1";
        var cla1 = ".red-packet" + idx;
        var rotateNum = anTime * 360;
        var strNum = "rotate("+rotateNum+"deg)";
        var strTime = anTime + "s linear"
        $(cla1).css("transform",strNum).css("transition",strTime);
        $(cla).css("animation",str);
    },
    
    //红包点击
    onClickRedPacketBtn:function(){
        //这里是点击红包的事件,处理自己的逻辑。
    },
}

小程序

小程序这边整体思路和代码和H5基本一样,区别就是,小程序封装成组件,实现动画的方式通过小程序动画去实现的。

话不多说,直接上代码。

wxml

<view class="maskview"></view>
<view class="redpacketview">
    <block wx:for="{{packetList}}" wx:for-index="index" wx:for-item="items">
        <view class="redview view{{index}}" style="position:fixed;top:{{items.top}}px;left:{{items.left}}px;">
         <image class="red-packet red-packet{{index}}" src="{{items.src}}" >
         </image>
        </view>
    </block>
</view>

wxss

page{
    width: 100%;
    height: 100%;
}

.maskview {
    width: 100%;
    height: 100%;
    position: fixed;
    left: 0;
    top: 0;
    background-color: rgba(0, 0, 0, 0.5);
    z-index: 999;
}

.redpacketview{
    box-sizing: border-box;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000;
    overflow: hidden;
}

.redview{
    width: 96rpx;
    height: 131rpx;
}
.red-packet{
     width: 96rpx;
     height: 131rpx;
}

js

Component({
    /**
     * 组件的属性列表
     */
    properties: {},

    /**
     * 组件的初始数据
     */
    data: {
        imgurl: "https://www.jsdaima.com/Uploads/js/201811/1542602969/img/hb.png",
        windowWidth: "", //窗口宽度
        windowHeigh: "", //窗口高度
        packetList: [{}], //红包队列
        packetNum: 200, //总共红包的数量
        showInter: '' // 循环动画定时器
    },

    attached: function() {
        // 在组件实例进入页面节点树时执行
        this.initList();
    },

    /**
     * 组件的方法列表
     */
    methods: {
        
        //初始化红包列表
        initList: function() {
            var that = this;
            // 获取手机屏幕宽高
            wx.getSystemInfo({
                success: function(res) {
                    that.setData({
                        windowWidth: res.windowWidth,
                        windowHeigh: res.windowHeight,
                        top: res.windowHeight - 100 //设置红包初始位置
                    })
                }
            })

            //建立临时红包列表
            var packetList = [];
            //建立临时红包图片数组
            var srcList = [this.data.imgurl, this.data.imgurl];
            //生成初始化红包
            for (var i = 0; i < that.data.packetNum; i++) {
                // 生成随机位置(水平位置)
                var left = Math.random() * that.data.windowWidth - 20;
                // 优化位置,防止红包越界现象,保证每个红包都在屏幕之内
                if (left < 0) {
                    left += 20;
                } else if (left > that.data.windowWidth) {
                    left -= 20;
                }
                // 建立临时单个红包
                var packet = {
                    src: srcList[Math.ceil(Math.random() * 2) - 1],
                    top: -80,
                    left: left,
                    speed: Math.random() * 2500 + 1000 //生成随机掉落时间,保证每个掉落时间保持在3秒到5.5秒之间
                }
                // 将单个红包装入临时红包列表
                packetList.push(packet);
            }
            // 将生成的临时红包列表更新至页面数据,页面内进行渲染
            that.setData({
                packetList: packetList
            })
            that.setInter();    
        },
        //计时器,设置动画
        setInter: function(){
            var that = this;
            var packetList = that.data.packetList;
            // 初始化动画执行当前索引
            var tempIndex = 0;
            var time  = 0;
            // 开始定时器,每隔1秒掉落一次红包
            that.data.showInter = setInterval(function() {
                // 生成当前掉落红包的个数,1-3个
                var showNum = Math.ceil(Math.random() * 10);
                if(showNum<5){
                    showNum = 5;
                }
                // 防止数组越界
                if (time>=20) {
                    // 20秒之后,清除定时器
                    clearInterval(that.data.showInter);
                } else {
                    for (var i = 0; i < showNum; i++) {
                        var idx = tempIndex + i;
                        that.startAnimation(idx);
                    }
                    tempIndex += showNum;
                }
                time += 1;
            }, 1000)
        },
        //开始动画
        startAnimation: function(idx) {
            var that = this;
            var packetList = that.data.packetList;
            var cla = ".red-packet" + idx;
            var viewcla = ".view" + idx;
            var antime = parseInt(packetList[idx].speed);
            var list = [
                {
                    rotate: 0,
                },
                {
                    rotate: antime / 1000 * 360
                }
            ];
            this.animate(cla, list, antime, function() {
                this.clearAnimation(cla, {}, null)
            }.bind(this))
            this.animate(viewcla, [
                {
                    translateY:0
                },
                {
                    translateY: 800
                },
            ], antime, function() {
                this.clearAnimation(viewcla, {}, null)
            }.bind(this))
        },
    }

})
posted @ 2022-01-11 15:23  lvqs  阅读(881)  评论(0编辑  收藏  举报