new_app/uni_modules/lime-dialer/components/l-dialer/l-dialer.uvue

260 lines
7.6 KiB
Plaintext

<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>