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