大家好!先上图看看本次案例的整体效果。
实现思路:
Vue component实现大转盘组件,可以嵌套到任意要使用的页面。
css3 transform控制大转盘抽奖过程的动画效果。
抽奖组件内使用钩子函数watch监听抽奖结果的返回情况播放大转盘动画并给用户弹出中奖提示。
中奖结果弹窗,为抽奖组件服务。
实现步骤如下:
构建api奖品配置信息和抽奖接口,vuex全局存放奖品配置和中奖结果数据信息。
api:
export default { getPrizeList () { let prizeList = [ { id: 1, name: '小米8', img: 'https://i1.mifile.cn/f/i/g/2015/cn-index/m8-140.png' }, { id: 2, name: '小米电视', img: 'https://i1.mifile.cn/f/i/g/2015/TV4A-43QC.png' }, { id: 3, name: '小米平衡车', img: 'https://i1.mifile.cn/f/i/g/2015/cn-index/scooter-140!140x140.jpg' }, { id: 4, name: '小米耳机', img: 'https://c1.mifile.cn/f/i/g/2015/video/pinpai140!140x140.jpg' } ] return prizeList }, lottery () { return { id: 4, name: '小米耳机', img: 'https://c1.mifile.cn/f/i/g/2015/video/pinpai140!140x140.jpg' } } }
store:
import lotteryApi from '../../api/lottery.api.js' const state = { prizeList: [], lotteryResult: {} } const getters = { prizeList: state => state.prizeList, lotteryResult: state => state.lotteryResult } const mutations = { SetPrizeList (state, { prizeList }) { state.prizeList = prizeList }, SetLotteryResult (state, { lotteryResult }) { state.lotteryResult = lotteryResult } } const actions = { getPrizeList ({ commit }) { let result = lotteryApi.getPrizeList() commit('SetPrizeList', { prizeList: result }) }, lottery ({ commit }) { let result = lotteryApi.lottery() commit('SetLotteryResult', { lotteryResult: result }) } } export default { state, getters, mutations, actions, namespaced: true }
编写抽奖组件,为保证通用性,组件只负责播放抽奖结果。接收两个数据和一个方法,如下:
数据一:预置的奖品列表数据(轮播奖品需要)
数据二:抽奖结果,播放抽奖动画和弹出中奖结果需要
方法:抽奖动作,返回的抽奖结果数据即为数据二,响应式传递给组件
大概代码思路如下(仅供参考,不可运行)
<template> <section> <div> <img src="https://www.cnblogs.com/images/cnblogs_com/codeon/878827/o_backImage.jpg" alt> <div> <img src="https://www.cnblogs.com/images/cnblogs_com/codeon/878827/o_circle.jpg" alt> <ul :style="wheelStyle" :class="transition"> <li v-for="(prize,index) in slotPrizes" :style="{transform: 'rotate('+index*45+'deg)'}" v-bind:key="index"> <div></div> <div> <h3>{{prize.name}}</h3> </div> </li> </ul> <div @click="$emit('lottery')"> <a> <img src="https://images.cnblogs.com/cnblogs_com/codeon/878827/o_go.jpg" alt> </a> </div> </div> <prize-pop :prize="lotteryResult" v-if="showPrize" @closeLotteryPop="showPrize=false" /> </div> </section> </template> <script> import PrizePop from './common/prize-pop.vue' export default { name: 'BigTurntable', data () { return { isStart: false, showPrize: false, wheelStyle: { 'transform': 'rotate(0deg)' }, transition: 'transitionclear', playTurns: 5 // 默认先旋转5圈 } }, components: { PrizePop }, props: { prizes: { type: Array, required: false }, lotteryResult: { type: Object, default: () => { } } }, computed: { slotPrizes () { var self = this console.log(self.prizes) let prizeList = [] prizeList.push({ ...self.prizes[0], slotIndex: 1 }) prizeList.push({ name: '谢谢参与', slotIndex: 2 }) prizeList.push({ ...self.prizes[1], slotIndex: 3 }) prizeList.push({ name: '谢谢参与', slotIndex: 4 }) prizeList.push({ ...self.prizes[2], slotIndex: 5 }) prizeList.push({ name: '谢谢参与', slotIndex: 6 }) prizeList.push({ ...self.prizes[3], slotIndex: 7 }) prizeList.push({ name: '谢谢参与', slotIndex: 8 }) console.log(prizeList) return prizeList } }, methods: { /** * 执行抽奖动画 */ playWheel (index) { }, /** * 获取中奖结果所在奖品列表中的索引,以确定抽奖动画最终落在哪个奖品 */ getPrizeIndex (prizeId) { } }, watch: { /** * 监听抽奖结果,一旦有中奖信息就开始执行抽奖动画 */ lotteryResult (newVal, oldVal) { var self = this if (newVal.id && newVal.id > 0) { let index = self.getPrizeIndex(newVal.id) self.playWheel(index) } } } } </script>
弹出中奖结果组件,依附于抽奖组件,在上一步的执行抽奖结果动画结束后执行。