vue 简单实现 营销 转盘抽奖

请叫我海龟先生 等级 1022 0 1

1.0 思路整理

转盘抽奖很常见,之前也没写过,现在有空来写写,分析如下:

1.1 转盘旋转 ? ----- 可以用 transform 的 rotate 来解决 1.2 旋转动画 ? ----- transition 过渡来处理 1.3 停留目标位置及中奖提示 ? ------ 通过控制旋转角度控制停留位置,中奖提示,考虑添加回调

1.1 开始行动

上面的思考,我们知道了大概要实现的步骤,首先我们搞张图片 vue 简单实现  营销 转盘抽奖 这个圆盘有 10 份,每一份 360/10 = 36deg,假设要停留在第二个---->20金币,顺时针(含初始位置并计为1),即 共需要旋转 (2 - 1)* 36 = 36,这样,我们可以得出,停留位置需要旋转的角度 = (target - 1)*36

1.2 中奖回调

上面的步骤,我们知道了如何控制到目标位置,那接下来就是事件通知,起初想的是,固定转动时间,然后开启定时器计时,很显然不靠谱,有没有什么可以在动画结束后就通知呢?transitionend,我找到了这个事件,可以监听元素动画结束事件,只不过有些兼容 这个好办

/**
动画结束事件兼容
**/
whichTransitionEvent(){
    let el = document.createElement('span'),
    transitions = {
        'transition':'transitionend',
        'OTransition':'oTransitionEnd',
        'MozTransition':'transitionend',
        'WebkitTransition':'webkitTransitionEnd'
    };
    for(let t in transitions){
        if( el.style[t] !== undefined ){
            return transitions[t];
        }
    }
    el = null;
}

2.0 完整示例

控制转动位置和事件通知都找到方法了,接下来开干! 栗子: vue 简单实现  营销 转盘抽奖

完整代码

<template>
  <div>
      <h3>转盘抽奖</h3>
      <div class="round_box" >
          <img class="img_rotate"  ref="rotImg" src="../assets/zhuan.png" alt="">
          <div class="center">
              <div class="pointer" ></div>
          </div>
      </div>
      <button @click="toDraw" >点击抽奖</button>
  </div>
</template>

<script>
export default {
    name:'rotaryDraw',
    data() {
        return {
            rotate: 0,
            resetRotate: 0,
            hitId: 1,// 1-10
            drawStatus: false
        }
    },
    async mounted() {
        await this.$nextTick();
        let evenTransition = this.whichTransitionEvent();
        let img = this.$refs.rotImg;
        let that = this;
        const hitAre = [ '30M流量包','20金币','20M流量包','10M流量包','5金币',
                         '谢谢参与','10金币','50M流量包','2金币','100M流量包'
                        ];
        // 监听 动画结束 
        img.addEventListener(evenTransition,tranHand,false);

        function tranHand() {
            // 复位
            that.resetRotate = that.rotate > 360 ? that.rotate % 360 : 0;
            img.style.transition = "none 0s ease 0s";
            img.style.transform = `rotate(${that.resetRotate}deg)`; 
            alert(`抽奖结果【 ${hitAre[that.hitId - 1]} 】`);
            that.drawStatus = false
        }
    },
    methods: {
        start() {
            this.$refs.rotImg.style.transition = "all 3s ease 0s";
            this.$refs.rotImg.style.transform = `rotate(${this.rotate}deg)`;
        },
        toDraw() {
            if(this.drawStatus){
                console.log('正在抽奖中');
                return
            }
            // 标记状态
            this.drawStatus = true
            /**
             * 圆盘共 10 份 每份 36度, 停位置(id)度数 (id - 1)*36 
             * 基数 3圈 360*4
             * this.rotate 当前角度
             * **/  
            let reset = 360 * 4;
            let idx = this.getRandomInt(1,11);
            // 设置命中
            this.hitId = idx;
            // 需要多转角度
            let addRotate = this.resetRotate > 0 ? 360 - this.resetRotate : 0;
            // 总共角度
            let allRotate = this.rotate + (idx - 1) * 36 + reset + addRotate;
            // 角度限制
            this.rotate = this.setRotate(allRotate);

            this.start()
        },
        // 递归计算角度 不超过 360*6
        setRotate(deg) {
            let rest = deg - 360;
            return  rest > 360*6 ? this.setRotate(rest) : deg;
        },
        getRandomInt(min, max) {
            // 向上收
            min = Math.ceil(min);
            // 向下收
            max = Math.floor(max);
            return Math.floor(Math.random() * (max - min)) + min; //不含最大值,含最小值
        },
        // 动画兼容
        whichTransitionEvent(){
            let el = document.createElement('span'),
            transitions = {
                'transition':'transitionend',
                'OTransition':'oTransitionEnd',
                'MozTransition':'transitionend',
                'WebkitTransition':'webkitTransitionEnd'
            };
            for(let t in transitions){
                if( el.style[t] !== undefined ){
                    return transitions[t];
                }
            }
            el = null;
        }
    }

}
</script>

<style lang="scss" >
.img_rotate{
    transform: rotate(0deg);
}
.round_box{
    width: 100%;
    max-width: 375px;
    position: relative;
    overflow: hidden;
    img{
        width: 100%;
    }
    .center{
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%,-50%);
        .pointer{
            width: 5px;
            height: 90px;
            background-color: #f40;
            position: absolute;
            top: -90px;
        }
        .pointer::before{
            content:'';
            width: 0;
            height: 0;
            border-top: 15px solid transparent;
            border-right: 15px solid transparent;
            border-bottom: 15px solid #f40;
            border-left: 15px solid transparent;
            position: absolute;
            top: -20px;
            left: 50%;
            transform: translateX(-50%);
        }
    }
}

</style>

3.0 tips

总体来说有几个点需要注意 1、动画开始前上锁 2、动画结束后通知,状态复位

/**
比如:
基数3圈 reset 360*3
停留位置 第二个 (2 - 1)* 36 = 36
总共角度 360*3 + 36
动画停止后,因为还要继续旋转,所以不可能把角度一直增加,因此需要复位 
360*3 + 36 其实可以考虑 就转了 36度,然后再增加需要转的角度
**/

3、继续旋转,因为我们计算是以 30M流量 为初始值的,所以在此旋转 仍然需要以 30M为起点,此时假设 现在停留位置是 300度,也就是说 再转 60度,也就回到了初始位置,本人也是按照这个思路进行复位的。

收藏
评论区

相关推荐

基于Vue实现一个有点意思的拼拼乐小游戏
笔者去年曾写过一个类似的拼拼乐小游戏,技术栈采用自己的Xuery框架和原生javascript实现的,脚手架采用gulp来实现,为了满足对vue的需求,笔者再次使用vue生态将其重构,脚手架采用比较火的vuecli。 前言 为了加深大家对vue的了解和vue项目实战,笔者采用vue生态来重构此项目,方便大家学习和探索。技术栈如下: vuecli4
前端培训-Vue专题之Vue基础
简介特点:MVVM框架,双向绑定,数据驱动,单页面,组件化。 区别Vue 和 jQuery 的区别:不直接操作DOM,而是操作数据。案例:Hello World 你好,世界HTML代码:xml<h1msg</h1jQuery实现javascript$("h1").text("你好,世界");Vue 实现javascriptthis.msg '你好,世界'
vscode的eslint插件不起作用
最近在用vue进行开发,但是vsCode中的eslint插件装上之后不起作用 1.vsCode打开“设置”,选择"settings.json" ![](https://img2018.cnblogs.com/blog/921637/201905/921637-20190516165707540-1304630667.png) 2.输入一段脚本
Angular React Vue我应该选择什么?
2017 年比较 Angular、React、Vue 三剑客 ============================== 为 web 应用选择 JavaScript 开发框架是一件很费脑筋的事。现如今 [Angular](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Flink.juej
Authing 新版登录表单组件上线啦
同时支持 **React** 、 **Vue** 、 **Angular** 及 **原生 JavaScript** 命令式调用的 Authing 新版登录表单(即 [Guard2.0](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fdocs.authing.cn%2Fsdk%2F
CodeMirror 在线代码编辑器
像百度编辑器插件部分、菜鸟教程示例等高德地图都在使用,这里也记录一下: CodeMirror是一个用于编辑器文本框textarea代码高亮javascript插件......vue 中使用 参见:https://www.npmjs.com/package/vue-codemirrorhttps://blog.csdn.net/oumaharuki/
JavaScript 核心原理精讲【朋友圈已刷屏】
作为一名前端工程师,JavaScript 你一定每天都在用。但是,即便工作 5 年以上的前端也不一定用得非常熟,甚至很多前端对 JavaScript 的掌握程度仅仅停留在会用的层面。 而且 Vue/React 等框架的便利,更是让前端人无需苦学 JavaScript 原生,就可以快速构建一个网页。它解决了开发者短期的痛点,却为依赖框架开发的程序员埋下长期隐
React与Vue的相同与不同点
我们知道JavaScript是世界上最流行的语言之一,React和Vue是JS最流行的两个框架。所以要想前端的开发那么必须掌握好这两个框架。 那么这两个框架有什么不同呢? **React 和 Vue 相同之处,它们都有:** * 使用 Virtual DOM * 提供了响应式 (Reactive) 和组件化 (Composable) 的视图组件
React面试必问Fiber和Hooks,一次搞定
国内的前端领域,Vue 和 React 是最火的两个框架,要说岗位数量,Vue可能会更多一点。 但如果把公司范围缩小到大厂,或者把范围扩展到全球,那React无疑独占鳌头。 ![](https://oscimg.oschina.net/oscnet/ba57134c-6a7d-47d8-a317-7ad3976a1a77.jpg "2019年
Vue 全家桶
vue全家桶。 使用过vue的程序员一般这样评价它,“vue.js兼具angular.js和react.js的优点”。Vue.js 是一个JavaScript MVVM(Model-View-ViewModel)库,用于渐近式构建用户界面。它以数据驱动和组件化思想构建,采用自底向上增量开发的设计思想。相比Angular.js,Vue.js API更加简洁;
Vue 全家桶、原理及优化简议
不少互联网公司都在使用vue技术栈,或称为vue全家桶。 使用过vue的程序员一般这样评价它,“vue.js兼具angular.js和react.js的优点”。Vue.js 是一个JavaScript MVVM(Model-View-ViewModel)库,用于渐近式构建用户界面。它以数据驱动和组件化思想构建,采用自底向上增量开发的设计
vue 路由 懒加载
原文链接: [vue 路由 懒加载](https://my.oschina.net/ahaoboy/blog/1618024) 路由懒加载 ===== 当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。 结合 Vue 的[异步组
vue 路由懒加载
原文链接: [vue 路由懒加载](https://my.oschina.net/ahaoboy/blog/1796979) 路由懒加载 ===== 当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。 结合 Vue 的[异步组件
阿里巴巴前端练习生学习笔记
字符串引擎和Javascript引擎的区别:是否对于DOM进行全部改变? 相关资料链接• Wiki MVC • Wiki MVVM • Mustach • Handlebars • React • Angular • Vue • Bootstrap • Ant Design • Fusion Des