• 签到抽奖功能——js常见前端抽奖需求


    网站开发 ,经常需要用到登录注册,签到抽奖等模块,虽然每次都要写,但是把这个记录下来会很方便下次再用。。。

    这边刚写了一个签到抽奖,放到这边来分享记录一下。 项目地址我的博客

    首先根据设计图 需要这样的样式与效果

    这样的抽奖页面无非就是样式当前类切换的效果, 那基本逻辑就是点击抽奖后,需要做一个跑马灯的效果,并且一开始加速然后减速到出中奖结果, 这边会用到定时器

    每切换一下调用定时器,直到出来结果后清除定时器。。。展示中奖

    那面贴上代码

    // 调用是这样的 
    
    // 声明这个函数 用来传入后台请求获取中奖结果id的
    function getId() {
        return Math.ceil(Math.random(1,8)*10) + 7; // 线下测试 随机数结果
        // return  '   '  // 这里是如果用户没有权限抽奖 返回的字符串  
    };
    
    const lettery = new Lottery(getId);   //创建实例 ,传入获取中奖id的函数,前面还可以传入一个对象,里面是控制抽奖转的最低圈数与速度
    
    //模拟后台奖品数据
    const prize = [{"id":9,"title":"10个积分","type":1},{"id":10,"title":"5元优惠券","type":2}, ....] 共七组奖品
    
    lettery.init(prize); // 初始化 , 传入奖品数据 prize
    
    

    上面是如何调用这个功能 ,下面h+c实现样式,但并未做注释,样式可以自己根据需要去写,也是简单的东西,最后是js逻辑代码,有我的理解与注释

    // 这边是html 字符串,放在js中,初始化的时候处理并加入页面
    
    let lotteryHtml = `
            <div id="lottery">
            <div class="lottery-box">
                <div class="lottery-head">
                    <h1><img src="../images/sign/sign-box.png" width="40" height="40">签到抽奖</h1>
                    <div class="prize-close">X</div>
                </div>
                <div class="lottery-content">
                    <div class="left-light sider-light">
                        <i></i><i></i><i></i><i></i><i></i><i></i><i></i>
                    </div>
                    <div class="top-light sider-light">
                        <i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
                    </div>
                    <div class="right-light sider-light">
                        <i></i><i></i><i></i><i></i><i></i><i></i><i></i>
                    </div>
                    <div class="bottom-light sider-light">
                        <i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
                    </div>
                    <div class="prize-content">
                        <ul class="clearfix">
                            <li class="lottery-0" data-id="{ id }" data-index="0">
                                <img src="{ src }" alt="">
                                <p>{ title }</p>
                            </li>
                            <li class="lottery-1" data-id="{ id }" data-index="1">
                                <img src="{ src }" alt="">
                                <p>{ title }</p>
                            </li>
                            <li class="lottery-2" data-id="{ id }" data-index="2">
                                <img src="{ src }" alt="">
                                <p>{ title }</p>
                            </li>
                            <li class="lottery-7" data-index="7">
                                <p class="thank">谢谢参与</p>
                            </li>
                            <li class="lottery">
                                <p class="title">开始抽奖</p>
                                <span>免费次数:<em>1</em>次</span>
                            </li>
                            <li class="lottery-3" data-id="{ id }" data-index="3">
                                <img src="{ src }" alt="">
                                <p>{ title }</p>
                            </li>
                            <li class="lottery-6" data-id="{ id }" data-index="6">
                                <img src="{ src }" alt="">
                                <p>{ title }</p>
                            </li>
                            <li class="lottery-5" data-id="{ id }" data-index="5">
                                <img src="{ src }" alt="">
                                <p>{ title }</p>
                            </li>
                            <li class="lottery-4" data-id="{ id }" data-index="4">
                                <img src="{ src }" alt="">
                                <p>{ title }</p>
                            </li>
                        </ul>
                        <div class="prize-reason">
                            <div>
                                <span class="close-res">X</span>
                                <p class="res-title"></p>
                                <img src="">
                                <p class="res-con"></p>
                                <span class="res-btn">再抽一次</span>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="prize-bottom">
                    <div>
                        <h4>抽奖说明:</h4>
                        <p>1、 每个用户每天签到一次可获得一次抽奖机会( 抽奖机会当天有效 )</p>
                        <p>2、 10积分抽奖一次</p>
                    </div>
                </div>
            </div>
        </div>
        `; 
    
    // css 可根据自己的需求修改 我这边是stylus 语法
    
    // 抽奖
    #lottery
    	position fixed 
    	left 0px
    	top 0px
    	right 0px
    	bottom 0px
    	background-color rgba(0,0,0,.6)
    	z-index 999
    	display none
    	.lottery-box
    		width 440px
    		height 620px
    		position absolute
    		left 0px
    		top 0px
    		right 0px
    		bottom 0px
    		margin auto 
    	.lottery-head
    		width 250px
    		height 40px
    		line-height 40px
    		border-radius 20px
    		background-color #353535
    		text-align center
    		margin 0 auto 
    		h1 
    			font-size 24px
    			margin 0
    			color #E97424
    			height 40px
    			line-height 40px
    			img 
    				vertical-align middle
    				margin-right 10px
    				margin-top -20px
    	.prize-close
    		position absolute
    		right -60px
    		top -20px
    		width 40px
    		height 40px
    		background-color #3F3F3F
    		line-height 40px
    		border-radius 50%
    		text-align center
    		color #fff 
    		font-size 20px
    		cursor pointer
    	.lottery-content
    		position relative 
    		width 100%
    		height 388px 
    		margin-top 20px
    		border-radius 20px 
    		overflow hidden
    		background-color #222
    		.sider-light
    			position absolute
    			background-color #353535
    			font-size 0
    			i 
    				display inline-block
    				width 10px
    				height 10px 
    				border-radius 50%
    				box-shadow 0 0 20px rgba(204,255,255,.8)
    				vertical-align middle
    				animation light 1s alternate infinite;
    				&:nth-child(2n)
    					animation light 1s linear 1s alternate infinite;
    		.left-light,.right-light
    			width 24px 
    			top 24px 
    			height 332px
    			left 0px
    			text-align center
    			i 
    				display block
    				background-color #E97424
    				margin 0 auto 38px
    				&:first-child
    					margin-top 17px
    				&:last-child
    					margin-bottom 0
    				&:nth-child(2n)
    					background-color #FDBD40
    		.right-light
    			left auto 
    			right 0px
    		.top-light,.bottom-light
    			left 0px
    			top 0px
    			height 24px 
    			line-height 24px
    			width 100%
    			i 
    				margin-right 38px 
    				background-color #FDBD40
    				&:first-child
    					margin-left 23px
    				&:last-child
    					margin-right 0
    				&:nth-child(2n)
    						background-color #E97424
    		.top-light
    			border-radius 20px 20px 0 0
    		.bottom-light 
    			top auto 
    			bottom 8px
    			border-radius 0 0 20px 20px
    		
    	.prize-content
    		padding 34px
    		li 
    			float left
    			width 120px 
    			height 100px 
    			border-radius 10px 
    			margin-right 6px 
    			margin-top 6px 
    			background-color #FFF2DA
    			border 2px solid transparent
    			box-sizing border-box
    			cursor default
    			text-align center
    			&.active 
    				border-color #E97424
    			&:nth-child(-n+3)
    				margin-top 0
    			&:nth-child(3n)
    				margin-right 0
    			&:nth-child(5)
    				background-color #E97424
    				cursor pointer
    				user-select none
    				.title
    					font-size 23px 
    					color #fff 
    					margin-top 20px
    				span 
    					color #FFCC00
    			img 
    				width 50px
    				margin-top 10px
    			p 
    				color #E97424
    			.thank
    				line-height 100px
    		.prize-reason
    			position absolute 
    			width 300px
    			height 300px
    			left 0px
    			top 0px
    			right 0px
    			bottom 0px
    			margin auto 
    			border-radius 20px 
    			background-color #353535
    			overflow hidden
    			color #fff 
    			text-align center
    			display none
    			&>div 
    				position relative 
    				z-index 2
    			&:before 
    				content ""
    				position absolute
    				width 200%
    				height 200%
    				border-radius 50%
    				left 50%
    				margin-left -100%
    				top -160%
    				background-color #222222
    			.close-res
    				position absolute
    				right 5px
    				top 5px 
    				width 30px 
    				height 30px 
    				border-radius 50%
    				color #fff 
    				text-align center
    				line-height 30px 
    				background-color rgba(0,0,0,.8)
    				cursor pointer
    			.res-title
    				font-size 24px 
    				line-height 60px 
    			img 
    				margin-top 20px 
    			.res-con
    				line-height 50px 
    				height 50px 
    				font-size 22px 
    				font-weight bold
    				&.no 
    					font-size 16px 
    					font-weight normal 
    			.res-btn 
    				display block
    				margin 25px auto 0
    				width 120px 
    				height 34px 
    				line-height 34px 
    				font-size 16px 
    				color #fff
    				background-color #FECC32
    				border-radius 5px 
    				cursor pointer
    				user-select none
    	.prize-bottom
    		margin-top 24px 
    		background-color #222222
    		width 100%
    		height 148px
    		border-radius 20px 
    		position relative
    		&::after,&::before 
    			content ""
    			position absolute
    			width 10px 
    			height 24px 
    			background-color #353535
    			top -24px 
    			left 130px 
    		&::after 
    			left auto 
    			right 130px
    		div 
    			width 100%
    			height 140px 
    			border-radius 20px
    			background-color #353535
    			box-sizing border-box
    			padding 10px 20px 
    			color #ddd 
    			line-height 2
    			h4 
    				font-size 16px 
    				color #E97424
    		
    @keyframes light 
    	0% 
    		box-shadow 0 0 5px rgba(204,255,255,.8)
    	100
    		box-shadow 0 0 20px rgba(204,255,255,.8)
    		
    
    
    

    上面两段是样式效果, 下面是逻辑代码了。

    ;(function(win, $) {
    
        //这边是用到的三张图片地址  变量没有大写。。
        const pointImgSrc = '../images/sign/point.png';
        const couponImgSrc = '../images/sign/coupon.png';
        const thanksImgSrc = '../images/sign/thanks.png';
    
        /**
            opts => object 
            * speed 转动速度  数值越小速度越快
            * cycle 最少转圈数
            
            fn => function 
            * return id (Number)
        */ 
        
        
        class Lottery {
            constructor(fn = 0, opts = {}) { 
                this.opts = opts;
                this.callbackId = fn;
            }
    
            //初始化
            init(data = []) {  // 传入奖品数据数组对象 数组长度为7  奖品id, 奖品title, 奖品类型 1,2
                this.options = Object.assign({}, {
                    speed: 40,
                    cycle: 5,
                }, this.opts);  // 合并默认参数
    
                // 初始一些变量
                this._index = 0; // 当前转动位置
                this._timer = null; // 计时器
                this._count = 8; // 抽奖转动的长度
                this._prize = -1; // 中奖的位置 
                this._times = 0; // 转动的次数
                this._curId = 0; // 中奖的id 后台提供
                this._speed = this.options.speed;
                this._cycle = this.options.cycle * 8;
                this._isClick = false; 
                this._prizeType = 0; // 中奖类型
                this._prizeTitle;
    
                this.data = data; // 奖品数据  后台提供
    
                this._render(); // 渲染抽奖模块
    
                this._initEvent(); //初始事件
            }
    
            _render() {
                let html = '',
                    i = 0,
                    j = 0,
                    k = 0; // 数组赋值索引参数
                
                html += lotteryHtml
                    .replace(/{ src }/g, (v)=>{
                        return prize[i++].type == 1? pointImgSrc: couponImgSrc;
                    })
                    .replace(/{ title }/g, (v)=>{
                        return prize[j++].title;
                    })
                     .replace(/{ id }/g, (v)=>{
                        return prize[k++].id;
                    })
    
                $('body').append(html);
                this.lotteryDom = $('#lottery'); //声明dom对象
            }
    
            _initEvent() { 
                this.lotteryDom
                    .on('click', '.prize-close', ()=> {
                        this.lotteryDom.hide();
                    })
                    .on('click', '.close-res', ()=> {
                        this.lotteryDom.find('.prize-reason').fadeOut();
                    })
                    .on('click', '.lottery, .res-btn', this.startGame.bind(this))
            }
    
            startGame() {
                this.lotteryDom.find('.prize-reason').fadeOut(); // 开始时候隐藏上次中奖结果弹出层
                // 后台请求中奖id   简单处理非id 直接警告
                if (typeof(this.callbackId()) == 'number') {
                    this._curId = this.callbackId(); 
                } else {
                    alert(this.callbackId());
                    return;
                };
    
                // if(this.lotteryDom.find('.lottery em').text() == 1) {   // 免费抽奖次数清零。  
                //       this.lotteryDom.find('.lottery em').text(0)
                // }
    
                if(!this._isClick) {  //  抽奖动画没结束 不能再次触发
                    this._roll();
                }
            }
    
            _getPrizeIndex() {
                // 这里过滤获取当前中奖结果索引
                let dom = this.lotteryDom.find('li').filter((i,v)=>{
                    return $(v).data('id') == this._curId;
                })
                   
    
                this._prizeType = dom.find('p').text().indexOf('积分') > 0? 1: dom.find('p').text().indexOf('优惠券') > 0? 2: 0;
                if(this._prizeType) {
                    this._prizeTitle = dom.find('p').text();
                };
    
                if(!dom.length) return 7; // 全都不符合返回谢谢惠顾的索引
    
                return dom.data('index')/1; 
            }
    
            _roll() {
                this._isClick = true; // 控制暴力点击
    
                this.lotteryDom.find('.lottery-'+ this._index).removeClass('active');  //每次调用 去除当前选中 
                this._index++;
    
                if(this._index > this._count - 1) {  // 循环添加
                    this._index = 0;
                }
    
                this.lotteryDom.find('.lottery-'+ this._index).addClass('active');  // 下一个添加选中
    
                this._times ++;
                if(this._times > this._cycle + 10 && this._prize == this._index) {  // 转动圈数超过基数+10 并且当前位置等于中奖结果位置
                    
                    clearTimeout(this._timer); // 清除定时器
                    this._showPrize(); // 展示中奖结果
                } else {
    
                    if(this._times < this._cycle) { // 圈数小于设置的基数 速度边快
                        this._speed -= 10;
    
                    } else if(this._times == this._cycle) {
                        this._prize = this._getPrizeIndex(); // 转动到达基数时候 获取中奖结果的索引
    
                    } else {
                        if (this._times > this._cycle + 10 && (this._prize == 0 && this._index == 7 || this._prize == this._index + 1)) {   // 这里是当  当前转动到的索引是中奖的前一个位置的时候 立刻 减速的判断条件
                            this._speed += 110;
                        } else {
                            this._speed += 20;
                        }
                    }
    
                    if (this._speed < 40) {  // 设置最快速度
                        this._speed = 40
                    }
    
                    this._timer = setTimeout(()=>{  // 重复执行
                        this._roll();
                    }, this._speed)
                }
            }
    
            _showPrize() { //展示中奖结果
                // 直接dom操作 展示结果文案了
                let reizeDon = this.lotteryDom.find('.prize-reason');
                reizeDon.fadeIn();
                if(this._prizeType) {
                    reizeDon.find('img').attr('src', this._prizeType == 1? pointImgSrc: couponImgSrc);
                    reizeDon.find('.res-title').text('恭喜获得');
                    reizeDon.find('.res-con').text(this._prizeTitle).removeClass('no');
                } else {
                    reizeDon.find('.res-title').text('谢谢参与');
                    reizeDon.find('.res-con').text('哎呀,没抽中, 换个姿势,再来一次吧~').addClass('no');
                    reizeDon.find('img').attr('src', thanksImgSrc);
                }
                
    
                // 初始点击与动画
                this._isClick = false; 
                this._prize = -1;
                this._times = 0;
                this._speed = this.options.speed;
            }
        }
    
    
        win.Lottery = Lottery;
    
    })(window, jQuery);
    
    

    最后抽奖就是这个结果啦,项目地址在个人博客,效果可以自己在网站中看到哦~

    上面展示了如何完成一个抽奖功能, 如果有更好的,希望指出

    前进道路长,学习不可怠
  • 相关阅读:
    Java Web总结十Jsp
    当前结果
    QFontMetrics的一个问题
    设想的用户交互流程
    多视图工作
    改进函数、变量的表示
    接口测试Session/Cookie笔记(二)
    接口测试笔记(一)
    创业公司心力交瘁
    禅道BUG管理工具使用链接存储
  • 原文地址:https://www.cnblogs.com/mrzll/p/10283272.html
Copyright © 2020-2023  润新知