抽奖
This commit is contained in:
260
uni_modules/lime-dialer/components/l-dialer/l-dialer.uvue
Normal file
260
uni_modules/lime-dialer/components/l-dialer/l-dialer.uvue
Normal file
@@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<view class="l-dialer" :style="rootStyles">
|
||||
<view class="l-dialer__inner" :style="innerStyle">
|
||||
<view class="l-dialer__inner-border" v-if="$slots['border'] != null">
|
||||
<slot name="border" />
|
||||
</view>
|
||||
<view class="l-dialer__inner-wrap" ref="drawbleRef" :style="wrapStyle">
|
||||
<view class="l-dialer__inner-item" v-for="(item, index) in prizeList" :key="index"
|
||||
:style="itemStyle(index)">
|
||||
<view class="l-dialer__inner-content" :style="contentStyle(index)">
|
||||
<slot v-if="$slots['prize'] != null" name="prize" :item="item" :even="index % 2"></slot>
|
||||
<template v-else>
|
||||
<text class="l-dialer__inner-name" :style="nameStyle">{{ item['name'] }}</text>
|
||||
<image class="l-dialer__inner-img" :src="item['img']"></image>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="l-dialer__pointer" :style="pointerStyle">
|
||||
<slot v-if="$slots['pointer'] != null" name="pointer" />
|
||||
<image v-else :class="!isTurnIng ? 'heart' : ''" src="/uni_modules/lime-dialer/static/turnable_btn.png"
|
||||
style="width: 100%" mode="widthFix" @tap="$emit('click')" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="uts" setup>
|
||||
const emits = defineEmits(['click', 'done'])
|
||||
const slots = defineSlots<{
|
||||
prize : {
|
||||
item : UTSJSONObject,
|
||||
even : number
|
||||
}
|
||||
}>()
|
||||
const props = defineProps({
|
||||
size: {
|
||||
// #ifdef APP-ANDROID
|
||||
type: Object,
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
type: [String, Number],
|
||||
// #endif
|
||||
default: 300
|
||||
},
|
||||
prizeList: {
|
||||
type: Array as PropType<UTSJSONObject[]>,
|
||||
default: () : UTSJSONObject[] => []
|
||||
},
|
||||
turns: {
|
||||
type: Number,
|
||||
default: 10
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
default: 3
|
||||
},
|
||||
styleOpt: {
|
||||
type: Object as PropType<UTSJSONObject>,
|
||||
default: () : UTSJSONObject => ({
|
||||
// 每一块扇形的背景色,默认值,可通过父组件来改变
|
||||
prizeBgColors: ['#fff0a3', '#fffce6'],
|
||||
// 每一块扇形的外边框颜色,默认值,可通过父组件来改变
|
||||
borderColor: '#ffd752',
|
||||
} as UTSJSONObject)
|
||||
},
|
||||
customStyle: {
|
||||
type: String,
|
||||
},
|
||||
dialStyle: {
|
||||
type: String,
|
||||
},
|
||||
pointerStyle: {
|
||||
type: String,
|
||||
default: `width: 30%`
|
||||
}
|
||||
})
|
||||
|
||||
const drawbleRef = ref<UniElement | null>(null)
|
||||
const startRotateDegree = ref(0)
|
||||
const rotateAngle = ref('rotate(0deg)')
|
||||
const rotateTransition = ref('')
|
||||
const isTurnIng = ref(false)
|
||||
|
||||
|
||||
const getStyleOpt = computed(() : UTSJSONObject => {
|
||||
const style = {
|
||||
// 每一块扇形的背景色,默认值,可通过父组件来改变
|
||||
prizeBgColors: ['#fff0a3', '#fffce6'],
|
||||
// 每一块扇形的外边框颜色,默认值,可通过父组件来改变
|
||||
borderColor: '#ffd752',
|
||||
}
|
||||
return UTSJSONObject.assign(style, props.styleOpt)
|
||||
})
|
||||
const rootStyles = computed(() : string => {
|
||||
const size = /\d$/.test(`${props.size}`) ? `${props.size}px` : props.size;
|
||||
return `width: ${size}; height: ${size}; ${props.customStyle}`
|
||||
})
|
||||
|
||||
const innerStyle = computed(() : string => {
|
||||
// const style = new Map<string, string>()
|
||||
let style = ''
|
||||
const padding = getStyleOpt.value['padding'] ?? 0
|
||||
|
||||
style += `padding: ${padding};`
|
||||
style += `transform: ${rotateAngle.value};`
|
||||
style += `${rotateTransition.value};`//`transition: ${rotateTransition.value};`
|
||||
style += `${props.dialStyle};`
|
||||
|
||||
return style
|
||||
})
|
||||
|
||||
const wrapStyle = computed(() : string => {
|
||||
const borderColor = getStyleOpt.value['borderColor']
|
||||
if (borderColor != null) {
|
||||
return `border: 1rpx solid ${borderColor}`
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
const itemStyle = computed(() : ((index : number) => Map<string, any>) => {
|
||||
return (index : number) : Map<string, any> => {
|
||||
const length = props.prizeList.length;
|
||||
const prizeBgColors : string[] = (getStyleOpt.value['prizeBgColors'] ?? [] as string[]) as string[]
|
||||
const prizeBgColorsLength = prizeBgColors.length;
|
||||
const borderColor = getStyleOpt.value['borderColor']
|
||||
const style = new Map<string, any>();
|
||||
// #ifndef APP
|
||||
if (length == 2) {
|
||||
// style['transform'] = index == 0 ? 0 : `rotate(270deg)`
|
||||
style.set('transform', index == 0 ? `rotate(0deg)` : `rotate(270deg)`)
|
||||
style.set('top', 0)
|
||||
} else {
|
||||
style.set('transform', `rotate(${(360 / length) * index}deg) skewX(0deg) skewY(${360 / length - 90}deg)`);
|
||||
}
|
||||
if (prizeBgColorsLength > 0) {
|
||||
style.set('backgroundColor', `${prizeBgColors[index % prizeBgColorsLength]}`)
|
||||
}
|
||||
if (borderColor != null) {
|
||||
style.set('border', `1rpx solid ${borderColor}`)
|
||||
}
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
if (length == 2) {
|
||||
style.set('backgroundColor', `${prizeBgColors[index % prizeBgColorsLength]}`)
|
||||
style.set('transform', index == 0 ? `rotate(0deg)` : `rotate(270deg)`);
|
||||
style.set('top', 0)
|
||||
if (borderColor != null) {
|
||||
style.set('border', `1rpx solid ${borderColor}`)
|
||||
}
|
||||
} else {
|
||||
style.set('transform', `rotate(${(360 / length) * index}deg)`);
|
||||
}
|
||||
|
||||
// #endif
|
||||
return style
|
||||
}
|
||||
})
|
||||
|
||||
const contentStyle = computed(() : ((index : number) => string) => {
|
||||
return (index : number) : string => {
|
||||
// #ifndef APP
|
||||
if (props.prizeList.length != 2) {
|
||||
return `transform: skewY(${90 - 360 / props.prizeList.length}deg) skewX(0deg) rotate(${180 / props.prizeList.length}deg)`
|
||||
} else {
|
||||
return index == 0
|
||||
? `transform: rotate(90deg); bottom: 0`
|
||||
: `transform: rotate(0deg); bottom: -50%; left: 0`
|
||||
}
|
||||
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
if (props.prizeList.length != 2) {
|
||||
return `transform: rotate(${180 / props.prizeList.length}deg)`
|
||||
} else {
|
||||
return index == 0
|
||||
? `transform: rotate(90deg); bottom: 0`
|
||||
: `transform: rotate(0deg); bottom: -50%; left: 0`
|
||||
}
|
||||
|
||||
// #endif
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
const nameStyle = computed(() : Map<string, any> => {
|
||||
const fontSize = getStyleOpt.value['fontSize']
|
||||
const color = getStyleOpt.value['color']
|
||||
const style = new Map<string, any>()
|
||||
|
||||
if (fontSize != null) {
|
||||
style.set('fontSize', fontSize)
|
||||
}
|
||||
if (color != null) {
|
||||
style.set('color', color)
|
||||
}
|
||||
return style
|
||||
})
|
||||
|
||||
|
||||
const run = (index : number) => {
|
||||
if (isTurnIng.value) return
|
||||
const duration = props.duration;
|
||||
const length = props.prizeList.length;
|
||||
|
||||
const _rotateAngle = startRotateDegree.value + props.turns * 360 + 360 - (180 / length + (360 / length) * index) - (startRotateDegree.value % 360);
|
||||
startRotateDegree.value = _rotateAngle;
|
||||
rotateAngle.value = `rotate(${_rotateAngle}deg)`;
|
||||
rotateTransition.value = `transition-duration: ${duration}s`;
|
||||
isTurnIng.value = true
|
||||
setTimeout(() => {
|
||||
emits('done', index);
|
||||
isTurnIng.value = false
|
||||
}, duration * 1000 + 500);
|
||||
}
|
||||
// #ifdef APP
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
if (drawbleRef.value == null) return;
|
||||
const ctx = drawbleRef.value!.getDrawableContext()!;
|
||||
const size = drawbleRef.value!.offsetWidth;
|
||||
watch(props.prizeList, () => {
|
||||
ctx.reset()
|
||||
const length = props.prizeList.length;
|
||||
if (length == 2) return
|
||||
const prizeBgColors : string[] = (getStyleOpt.value['prizeBgColors'] ?? [] as string[]) as string[]
|
||||
const prizeBgColorsLength = prizeBgColors.length;
|
||||
const borderColor = getStyleOpt.value['borderColor'] as string | null
|
||||
|
||||
const centerX = size / 2;
|
||||
const centerY = size / 2;
|
||||
const radius = size / 2;
|
||||
|
||||
const angle = (2 * Math.PI) / length;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(centerX, centerY);
|
||||
ctx.arc(centerX, centerY, radius, i * angle, (i + 1) * angle);
|
||||
ctx.lineTo(centerX, centerY);
|
||||
ctx.closePath();
|
||||
ctx.fillStyle = prizeBgColors[i % prizeBgColorsLength];
|
||||
if (borderColor != null) {
|
||||
ctx.lineWidth = 2
|
||||
ctx.strokeStyle = borderColor;
|
||||
ctx.stroke()
|
||||
}
|
||||
ctx.fill();
|
||||
}
|
||||
ctx.update()
|
||||
}, { immediate: true })
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
defineExpose({
|
||||
run
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './index';
|
||||
</style>
|
||||
Reference in New Issue
Block a user