想要開發一個,可進行配置獎品的大轉盤抽獎活動:如下圖:
要求: 轉盤底圖可配置,相對應的獎品也能夠配置
開發思路:
- 可以把轉盤開發成一個組件,所有參數皆是可配置的,做成組件具有公用型
- 通過 transform的rotate旋轉 以及 transition過渡來實現動畫
- 確定旋轉實現的原理,不想能像表盤那樣指針轉,應該是指針不動,表盤旋轉,用戶體驗性更好
具體實現步驟:
1.dom加載完成后,在mounted鈎子中寫一個transition平移動畫
//渲染完了 mounted() { this.oTurntable = document.querySelector('#turnUl'); // 過度中屬性用時5s this.oTurntable.style.webkitTransition = 'transform ' + this.time / 1000 + 's ease'; },
2.先根據獎品列表數量來計算每個獎品對應的角度,指針一般是定位到該中獎獎品的中心位置,這個要考慮到
autoRotate(arr) { if (arr.length) { let len = arr.length; let base = 360 / len; arr.forEach((item, index) => { // 指的是某個獎品區域的中間 : base/2 item.angle = 360 - (base / 2 + index * base); }); } return arr; },
3.點擊按鈕時請求接口,拿到中獎獎品進行旋轉到之前計算好的該獎品的角度,可以寫在定時器當中,完成后即清除定時器
// 點擊開始,請求接口抽獎 startPlay(){ const a = { prize: "50元和包券", id: 4 } this.startBtn(a) }, // 開始轉動,通過獎項級別進行匹配:id startBtn(val) { const self = this self.activeObj.prizeData.forEach((i,d)=>{ if(i.id == val.id){ self.pIndex = d } }) // 拿到相應的角度調旋轉接口 self.startrotate(self.activeObj.prizeData[self.pIndex].angle, () => { self.fulfillHandle(self.activeObj.prizeData[self.pIndex].prize); }); }, //開始旋轉 angle角度 complete回調成功函數 startrotate(angle, complete) { // 相應的角度 + 滿圈 只是在原角度多轉了幾圈 360 * 6 let rotate = 2160 * (this.rotNum + 1) + angle; this.oTurntable.style.webkitTransform = 'rotate(' + rotate + 'deg)'; clearTimeout(this.timer); // 設置5秒后停止旋轉,處理接口返回的數據 this.timer = setTimeout(() => { complete(); this.rotNum++; }, this.time); }, //得獎后的處理 fulfillHandle(prizeName) { this.$emit('result',prizeName) },
4.抽獎旋轉結束后再去處理后續操作,寫在startrotate 這個函數中,通過吧結束處理的函數當做參數進行回調
下面是完整代碼:
html:
<template> <div id="turnBox"> <ul id="turnUl" :style="{ backgroundImage : 'url(' + activeObj.turntableBgc + ')'}"> <li v-for="(item,index) in activeObj.prizeData" :key="index" :style="{webkitTransform: 'rotate(' + -item.angle + 'deg)'}" > </li> </ul> <img :src="activeObj.turntablebtn" alt="" @click="startPlay" class="turnBtn"> </div> </template>
js:
<script> export default { props: { activeObj: { type: Object, default: null }, }, data(){ return { pIndex: 0, // 中獎物品的下標 rotNum: 0, // 旋轉圈數基數 time: 5000, // 旋轉時間 timer: null, // 定時器 oTurntable: '', // 旋轉圓盤背景圖 type: 0, // 0 圖片 1 漢字 } }, created() { this.activeObj.prizeData = this.autoRotate(this.activeObj.prizeData) console.log(this.activeObj.prizeData); }, //渲染完了 mounted() { this.oTurntable = document.querySelector('#turnUl'); // 過度中屬性用時5s this.oTurntable.style.webkitTransition = 'transform ' + this.time / 1000 + 's ease'; }, methods:{ //自動生成角度添加到數組上 autoRotate(arr) { if (arr.length) { let len = arr.length; let base = 360 / len; arr.forEach((item, index) => { // 指的是某個獎品區域的中間 : base/2 item.angle = 360 - (base / 2 + index * base); }); } return arr; }, // 點擊開始,請求接口抽獎 async startPlay(){ const a = { prize: "50元和包券", id: 4 } this.startBtn(a) }, // 開始轉動,通過獎項級別進行匹配:id async startBtn(val) { const self = this self.activeObj.prizeData.forEach((i,d)=>{ if(i.id == val.id){ self.pIndex = d } }) // 拿到相應的角度調旋轉接口 self.startrotate(self.activeObj.prizeData[self.pIndex].angle, () => { self.fulfillHandle(self.activeObj.prizeData[self.pIndex].prize); }); }, //開始旋轉 angle角度 complete回調成功函數 startrotate(angle, complete) { // 相應的角度 + 滿圈 只是在原角度多轉了幾圈 360 * 6 let rotate = 2160 * (this.rotNum + 1) + angle; this.oTurntable.style.webkitTransform = 'rotate(' + rotate + 'deg)'; clearTimeout(this.timer); // 設置5秒后停止旋轉,處理接口返回的數據 this.timer = setTimeout(() => { complete(); this.rotNum++; }, this.time); }, //得獎后的處理 fulfillHandle(prizeName) { this.$emit('result',prizeName) }, //自動換行 autoWrap(str) { if (str.length > 5 && str.length <= 10) { str = str.substring(0, 5) + '<br/>' + str.substring(5, str.length); } else if (str.length > 10) { str = str.substring(0, 5) + '<br/>' + str.substring(5, 9) + '...'; } return str; } } } </script>
css:
<style lang="less" scoped> #turnBox { width: 545px; height: 544px; position: relative; overflow: hidden; margin: 0px auto; margin-top: 30px; background-position: center center; .turnBtn { position: absolute; width: 1.3rem; left: 50%; top: 50%; transform: translateX(-50%) translateY(-59%); overflow: hidden; background-repeat: no-repeat; background-size: 100% auto; z-index: 3; } ul { position: absolute; width: 100%; height: 100%; z-index: 1; background-repeat: no-repeat; background-size: 100% auto; li { position: absolute; box-sizing: border-box; // padding-top: 0.5rem; color: #7e250d; font-size: 0.3rem; top: 0pc; left: 0px; width: 100%; height: 100%; line-height: 20px; transform-origin: 50% 50%; img { position: absolute; top: 0.3rem; left: 50%; transform: translateX(-50%); width: 20%; } } } } </style>