lucky-wheel-component
Version:
A lucky wheel component for Vue 3 and React
186 lines (173 loc) • 7.92 kB
JavaScript
'use strict';
var vue = require('vue');
var script = vue.defineComponent({
name: 'LuckyWheel',
props: {
// 奖品配置
prizes: {
type: Array,
required: true,
default: () => []
},
// 抽奖次数
initialDrawCount: {
type: Number,
default: 3
},
// 转盘颜色配置
colors: {
type: Array,
default: () => ["#f31f49", "#fff7d7", "#a71d77"]
},
// 文字颜色配置
textColors: {
type: Array,
default: () => ["#f3f1f1", "#a8213c", "#f3f1f1"]
},
// 额外旋转圈数
additionalTurns: {
type: Number,
default: 10
},
// 提示文字配置
messages: {
type: Object,
default: () => ({
noChance: '您没有抽奖机会了'
})
}
},
data() {
return {
currentRotation: 0,
isRotating: false,
drawCount: this.initialDrawCount,
lastClickTime: 0,
lastRotation: 0
};
},
methods: {
getPrizeStyle(index) {
const perAngle = 360 / this.prizes.length;
return {
transform: `rotateZ(${perAngle / 2 - 90 + perAngle * index}deg)`,
clipPath: this.getClipPath(perAngle)
};
},
getClipPath(perAngle) {
const p = perAngle / 2;
const d = Math.tan(p * Math.PI / 180) * 100;
const x = (100 - d) / 2;
return `polygon(0% 50%, 100% ${x}%, 100% ${100 - x}%)`;
},
startRotation() {
// 防抖和状态检查
const now = Date.now();
if (now - this.lastClickTime < 1000 || this.isRotating || this.drawCount <= 0) {
return;
}
this.lastClickTime = now;
if (this.drawCount <= 0) {
return;
}
this.isRotating = true;
// 随机选择奖品
const prizeIndex = Math.floor(Math.random() * this.prizes.length);
const targetAngle = this.getPrizeAngle(prizeIndex);
// 计算旋转角度
const additionalRotation = 360 * this.additionalTurns; // 额外旋转10圈
const totalRotation = this.currentRotation - additionalRotation - targetAngle + this.lastRotation;
// 应用旋转动画
const wheelElement = this.$refs.wheelRef;
if (wheelElement) {
wheelElement.style.transform = `rotate(${totalRotation}deg)`;
}
// 动画结束后处理
setTimeout(() => {
this.isRotating = false;
this.drawCount--;
this.currentRotation = totalRotation;
this.lastRotation = targetAngle;
this.showResult(prizeIndex);
}, 5000);
// 触发事件
this.$emit('on-start', { prizeIndex, drawCount: this.drawCount });
},
getPrizeAngle(index) {
const perAngle = 360 / this.prizes.length;
return index * perAngle + perAngle / 2;
},
showResult(prizeIndex) {
const prize = this.prizes[prizeIndex];
this.$emit('on-complete', {
index: prizeIndex,
prize: prize
});
}
}
});
const _hoisted_1 = { class: "lucky-wheel" };
const _hoisted_2 = { class: "wheel-box" };
const _hoisted_3 = {
id: "wheel",
ref: "wheelRef"
};
const _hoisted_4 = { class: "wheel-inner" };
function render(_ctx, _cache, $props, $setup, $data, $options) {
return (vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
vue.createElementVNode("div", _hoisted_2, [
vue.createElementVNode("div", _hoisted_3, [
vue.createElementVNode("div", _hoisted_4, [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(_ctx.prizes, (prize, index) => {
return (vue.openBlock(), vue.createElementBlock("div", {
key: index,
class: "prize-part",
style: vue.normalizeStyle(_ctx.getPrizeStyle(index))
}, [
vue.createElementVNode("div", {
class: "prize-bg",
style: vue.normalizeStyle({ background: _ctx.colors[index % _ctx.colors.length] })
}, null, 4 /* STYLE */),
vue.createElementVNode("div", {
class: "prize-text",
style: vue.normalizeStyle({ color: _ctx.textColors[index % _ctx.textColors.length] })
}, vue.toDisplayString(prize.prize), 5 /* TEXT, STYLE */)
], 4 /* STYLE */))
}), 128 /* KEYED_FRAGMENT */))
])
], 512 /* NEED_PATCH */),
vue.createElementVNode("div", {
class: vue.normalizeClass(["pointer", { 'disabled': _ctx.drawCount === 0 }]),
onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.startRotation && _ctx.startRotation(...args)))
}, null, 2 /* CLASS */)
])
]))
}
function styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;
if (typeof document === 'undefined') { return; }
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var css_248z = "\r\n/* 复制原来的 CSS 样式并做适当调整 */\n.lucky-wheel[data-v-4f76abb5] {\r\n width: 100%;\r\n max-width: 600px;\r\n margin: 0 auto;\n}\n.wheel-box[data-v-4f76abb5] {\r\n width: 100%;\r\n padding-bottom: 100%;\r\n position: relative;\n}\n#wheel[data-v-4f76abb5] {\r\n position: absolute;\r\n width: 100%;\r\n height: 100%;\r\n border-radius: 50%;\r\n overflow: hidden;\r\n background: url('./assets/wheel-bg.png') center center no-repeat;\r\n background-size: 100% 100%;\r\n transform-origin: center center;\r\n transition: transform 5s cubic-bezier(0.46, 0.03, 0, 0.96);\n}\r\n\r\n/* 转盘内部样式 */\n.wheel-inner[data-v-4f76abb5] {\r\n position: absolute;\r\n width: 83%;\r\n height: 83%;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n border-radius: 50%;\r\n overflow: hidden;\n}\n.prize-part[data-v-4f76abb5] {\r\n height: 100%;\r\n width: 50%;\r\n position: absolute;\r\n top: 0;\r\n left: 50%;\r\n transform-origin: left center;\r\n box-sizing: border-box;\n}\n.prize-bg[data-v-4f76abb5] {\r\n width: 100%;\r\n height: 100%;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\n}\n.prize-text[data-v-4f76abb5] {\r\n transform: translate(0, -50%) rotate(90deg);\r\n width: 100%;\r\n text-align: center;\r\n position: absolute;\r\n top: 50%;\r\n left: 20%;\r\n font-size: 1rem;\r\n padding-top: 0.3rem;\r\n box-sizing: border-box;\r\n white-space: nowrap;\r\n z-index: 1;\n}\n.pointer[data-v-4f76abb5] {\r\n position: absolute;\r\n left: 50%;\r\n top: 50%;\r\n transform: translate(-50%, -50%);\r\n width: 120px;\r\n height: 120px;\r\n background: url('./assets/game-arrow.png') center center no-repeat;\r\n background-size: contain;\r\n cursor: pointer;\r\n z-index: 2;\n}\n.pointer.disabled[data-v-4f76abb5] {\r\n cursor: not-allowed;\r\n opacity: 0.6;\n}\r\n";
styleInject(css_248z);
script.render = render;
script.__scopeId = "data-v-4f76abb5";
script.__file = "src/vue/LuckyWheel.vue";
module.exports = script;