init
This commit is contained in:
88
uni_modules/nutui-uni/components/turntable/index.scss
Normal file
88
uni_modules/nutui-uni/components/turntable/index.scss
Normal file
@@ -0,0 +1,88 @@
|
||||
.nut-turntable {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
// transform: translateZ(0);
|
||||
.pointer {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
|
||||
// left: calc(50% - 35px);
|
||||
// top: calc(50% - 40px);
|
||||
left: 50%;
|
||||
z-index: 99;
|
||||
transform: translate(-43.75%, -50%);
|
||||
}
|
||||
// stylelint-disable selector-class-pattern
|
||||
|
||||
.drawTable-name {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 10px;
|
||||
width: calc(100% - 20px);
|
||||
font-size: 12px;
|
||||
color: #ff5722;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.drawTable-img {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
|
||||
/* 要居中就要50% - 宽度 / 2 */
|
||||
left: calc(50% - 30px / 2);
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
|
||||
image {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.turntable {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
|
||||
// stylelint-disable selector-id-pattern
|
||||
#canvasWx {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.mlcanvas {
|
||||
height: 50% !important;
|
||||
margin-top: 25%;
|
||||
|
||||
canvas {
|
||||
transform: scale(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.prize {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 25%;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
|
||||
.item {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform-origin: center bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
uni_modules/nutui-uni/components/turntable/index.ts
Normal file
2
uni_modules/nutui-uni/components/turntable/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export type * from './turntable'
|
||||
export type * from './type'
|
||||
95
uni_modules/nutui-uni/components/turntable/turntable.ts
Normal file
95
uni_modules/nutui-uni/components/turntable/turntable.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import type { ExtractPropTypes } from 'vue'
|
||||
import { CLICK_EVENT } from '../_constants'
|
||||
import { commonProps, makeNumberProp } from '../_utils'
|
||||
|
||||
export const turntableProps = {
|
||||
...commonProps,
|
||||
/**
|
||||
* @description 转盘的宽度
|
||||
*/
|
||||
width: {
|
||||
required: true,
|
||||
default: '300px',
|
||||
},
|
||||
/**
|
||||
* @description 转盘的高度
|
||||
*/
|
||||
height: {
|
||||
required: true,
|
||||
default: '300px',
|
||||
},
|
||||
/**
|
||||
* 奖品列表
|
||||
*/
|
||||
prizeList: {
|
||||
type: Array<any>,
|
||||
required: true,
|
||||
default: () => [],
|
||||
},
|
||||
/**
|
||||
* 中奖奖品在列表的索引位置
|
||||
*/
|
||||
prizeIndex: makeNumberProp(-1),
|
||||
/**
|
||||
* @description 从开始转动到结束所用时间,单位秒
|
||||
*/
|
||||
turnsNumber: makeNumberProp(5),
|
||||
/**
|
||||
* @description 转盘中的样式,包括每个扇区的背景颜色(在每条数据中页可单独设置 prizeColor),扇区的边框颜色
|
||||
*/
|
||||
styleOpt: {
|
||||
default: () => {
|
||||
return {
|
||||
// 每一块扇形的背景色,默认值,可通过父组件来改变
|
||||
prizeBgColors: [
|
||||
'rgb(255, 231, 149)',
|
||||
'rgb(255, 247, 223)',
|
||||
'rgb(255, 231, 149)',
|
||||
'rgb(255, 247, 223)',
|
||||
'rgb(255, 231, 149)',
|
||||
'rgb(255, 247, 223)',
|
||||
],
|
||||
// 每一块扇形的外边框颜色,默认值,可通过父组件来改变
|
||||
borderColor: '#ff9800',
|
||||
}
|
||||
},
|
||||
},
|
||||
/**
|
||||
* @description 转动需要持续的时间(秒)
|
||||
*/
|
||||
turnsTime: makeNumberProp(5),
|
||||
/**
|
||||
* @description 抽奖间隔(秒)
|
||||
*/
|
||||
lockTime: makeNumberProp(0),
|
||||
/**
|
||||
* @description 转盘中指针的样式,包括背景图片、大小等
|
||||
*/
|
||||
pointerStyle: {
|
||||
default: () => {
|
||||
return {
|
||||
width: '80px',
|
||||
height: '80px',
|
||||
backgroundImage:
|
||||
'url("https://img11.360buyimg.com/imagetools/jfs/t1/89512/11/15244/137408/5e6f15edEf57fa3ff/cb57747119b3bf89.png")',
|
||||
backgroundSize: 'contain',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export type TurnTableProps = ExtractPropTypes<typeof turntableProps>
|
||||
|
||||
export const turntableEmits = {
|
||||
[CLICK_EVENT]: () => true,
|
||||
startTurns: () => true,
|
||||
endTurns: () => true,
|
||||
lockTurns: () => true,
|
||||
}
|
||||
|
||||
export type TurnTableEmits = typeof turntableEmits
|
||||
|
||||
export interface TurnTableInst {
|
||||
rotateTurn: () => void
|
||||
}
|
||||
249
uni_modules/nutui-uni/components/turntable/turntable.vue
Normal file
249
uni_modules/nutui-uni/components/turntable/turntable.vue
Normal file
@@ -0,0 +1,249 @@
|
||||
<script setup lang="ts">
|
||||
import type { ComponentInternalInstance } from 'vue'
|
||||
import { computed, defineComponent, getCurrentInstance, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { PREFIX } from '../_constants'
|
||||
import { getMainClass, getMainStyle, isH5, isMpWeixin } from '../_utils'
|
||||
import { turntableEmits, turntableProps } from './turntable'
|
||||
import type { TPrizeItem } from './type'
|
||||
|
||||
const props = defineProps(turntableProps)
|
||||
|
||||
const emit = defineEmits(turntableEmits)
|
||||
const instance = getCurrentInstance() as ComponentInternalInstance
|
||||
defineExpose({ rotateTurn })
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
turnsNumber,
|
||||
styleOpt,
|
||||
turnsTime,
|
||||
pointerStyle,
|
||||
lockTime,
|
||||
} = reactive(props)
|
||||
|
||||
let prizeList: TPrizeItem[] = reactive(props?.prizeList)
|
||||
|
||||
const classes = computed(() => {
|
||||
return getMainClass(props, componentName)
|
||||
})
|
||||
|
||||
const styles = computed(() => {
|
||||
return getMainStyle(props, { width, height })
|
||||
})
|
||||
|
||||
// const getRandomColor = function () {
|
||||
// const r = Math.floor(Math.random() * 256);
|
||||
// const g = Math.floor(Math.random() * 256);
|
||||
// const b = Math.floor(Math.random() * 256);
|
||||
// return "rgb(" + r + "," + g + "," + b + ")";
|
||||
// };
|
||||
|
||||
// 用来锁定转盘,避免同时多次点击转动
|
||||
const lock = ref(false)
|
||||
// 是否正在转动
|
||||
const rorating = ref(false)
|
||||
// 剩余抽奖次数
|
||||
// const num = ref(5);
|
||||
// 开始转动的角度
|
||||
const startRotateDegree = ref(0)
|
||||
// 设置指针默认指向的位置,现在是默认指向2个扇形之间的边线上
|
||||
const rotateAngle = ref<string>('0')
|
||||
const rotateTransition = ref('')
|
||||
|
||||
const turntableDom = ref(null)
|
||||
const canvasDom = ref(null)
|
||||
const canvasDomEle = ref()
|
||||
const _rorateDeg = ref(360 / prizeList.length)
|
||||
|
||||
// 根据index计算每一格要旋转的角度的样式
|
||||
function getRotateAngle(index: number, flag?: string) {
|
||||
const angle = (360 / prizeList.length) * index + 180 / prizeList.length
|
||||
return {
|
||||
transform: `rotate(${angle}deg)${flag === 'canvas' && isH5 ? ' scale(2)' : ''}`,
|
||||
}
|
||||
}
|
||||
// 初始化圆形转盘canvas
|
||||
function init() {
|
||||
const data = styleOpt
|
||||
const prizeNum = prizeList.length
|
||||
const { prizeBgColors } = data
|
||||
// 开始绘画
|
||||
// const canvas = canvasDom.value;
|
||||
// const luckdraw = turntableDom.value;
|
||||
// const ctx = canvas.getContext('2d');
|
||||
const ctx = uni.createCanvasContext('canvasWx', instance.proxy)
|
||||
|
||||
// const canvasW = Number(width.replace(/px/g, "")); // 画板的高度
|
||||
// const canvasH =
|
||||
// Number(height.replace(/px/g, "")) / (envApp.value == "WEAPP" ? 1 : 2); // 画板的宽度
|
||||
const canvasW = Number.parseFloat(width) // 画板的高度
|
||||
const radis = isMpWeixin ? 1 : 2
|
||||
const canvasH = Number.parseFloat(height) / radis
|
||||
|
||||
if (isMpWeixin) {
|
||||
// translate方法重新映射画布上的 (0,0) 位置
|
||||
ctx.translate(0, canvasH)
|
||||
// rotate方法旋转当前的绘图,因为文字是和当前扇形中心线垂直的
|
||||
ctx.rotate((-90 * Math.PI) / 180)
|
||||
}
|
||||
// 圆环的外圆的半径,可用来调整圆盘大小来适应外部盒子的大小
|
||||
// const outRadius = canvasW / 2 - 1;
|
||||
// 圆环的内圆的半径
|
||||
// const innerRadius = 0;
|
||||
const baseAngle = (Math.PI * 2) / prizeNum // 每个奖项所占角度数
|
||||
// ctx.clearRect(0, 0, canvasW, canvasH); //去掉背景默认色
|
||||
// ctx.strokeStyle = borderColor; // 设置画图线的颜色
|
||||
for (let index = 0; index < prizeNum; index++) {
|
||||
const startAngle = index * baseAngle
|
||||
const endAngle = (index + 1) * baseAngle
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(canvasW / 2, canvasH / 2)
|
||||
ctx.arc(
|
||||
canvasW / 2,
|
||||
canvasH / 2,
|
||||
canvasH / 2,
|
||||
startAngle,
|
||||
endAngle,
|
||||
false,
|
||||
)
|
||||
/* 随机颜色 */
|
||||
if (prizeList[index].prizeColor)
|
||||
ctx.fillStyle = prizeList[index].prizeColor // 设置每个扇形区域的颜色,根据每条数据中单独设置的优先
|
||||
else
|
||||
ctx.fillStyle = prizeBgColors[index] // 设置每个扇形区域的颜色
|
||||
|
||||
ctx.fill()
|
||||
}
|
||||
ctx.draw()
|
||||
}
|
||||
|
||||
// 判断是否可以转动
|
||||
function canBeRotated() {
|
||||
// if (num.value <= 0) {
|
||||
// return false;
|
||||
// }
|
||||
if (lock.value) {
|
||||
if (!rorating.value)
|
||||
emit('lockTurns')
|
||||
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
function startTurns() {
|
||||
// 如果还不可以转动
|
||||
if (!canBeRotated())
|
||||
return false
|
||||
|
||||
emit('startTurns')
|
||||
}
|
||||
// 转动起来
|
||||
function changeLock() {
|
||||
setTimeout(() => {
|
||||
lock.value = false
|
||||
}, lockTime * 1000)
|
||||
}
|
||||
function rotate(index: number) {
|
||||
const turnsTimeNum = turnsTime
|
||||
const rotateAngleValue
|
||||
= startRotateDegree.value
|
||||
+ turnsNumber * 360
|
||||
+ 360
|
||||
- (180 / prizeList.length + (360 / prizeList.length) * index)
|
||||
- (startRotateDegree.value % 360)
|
||||
startRotateDegree.value = rotateAngleValue
|
||||
rotateAngle.value = `rotate(${rotateAngleValue}deg)`
|
||||
rotateTransition.value = `transform ${turnsTimeNum}s cubic-bezier(0.250, 0.460, 0.455, 0.995)`
|
||||
setTimeout(() => {
|
||||
emit('endTurns')
|
||||
rorating.value = false
|
||||
changeLock()
|
||||
}, turnsTimeNum * 1000 + 500)
|
||||
}
|
||||
|
||||
function rotateTurn() {
|
||||
// 开始转动
|
||||
// 先上锁
|
||||
lock.value = true
|
||||
rorating.value = true
|
||||
setTimeout(() => {
|
||||
rotate(props.prizeIndex)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.prizeList,
|
||||
(list) => {
|
||||
prizeList = list
|
||||
init()
|
||||
},
|
||||
)
|
||||
|
||||
// watch(
|
||||
// () => props.prizeIndex,
|
||||
// (nIndex) => {
|
||||
// rotate(nIndex);
|
||||
// }
|
||||
// );
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
// #ifdef H5
|
||||
const canvasDom: HTMLElement | null
|
||||
= document.getElementById('canvasWx')
|
||||
canvasDomEle.value = canvasDom
|
||||
// #endif
|
||||
init()
|
||||
}, 800)
|
||||
})
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
const componentName = `${PREFIX}-turntable`
|
||||
|
||||
export default defineComponent({
|
||||
name: componentName,
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
styleIsolation: 'shared',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view ref="turntableDom" :class="classes" :style="styles">
|
||||
<view class="turntable" :style="{ transform: rotateAngle, transition: rotateTransition }">
|
||||
<canvas
|
||||
id="canvasWx"
|
||||
ref="canvasDom"
|
||||
type="2d"
|
||||
:class="isMpWeixin ? '' : 'mlcanvas'"
|
||||
canvas-id="canvasWx"
|
||||
:style="isMpWeixin ? '' : getRotateAngle(0, 'canvas')"
|
||||
/>
|
||||
<!-- <canvas id="canvasWx" canvas-id="canvasWx" ref="canvasDom" type="2d" :style="getRotateAngle(0)">
|
||||
</canvas> -->
|
||||
<view v-if="prizeList.length > 0" class="prize">
|
||||
<view
|
||||
v-for="(item, index) of prizeList"
|
||||
:key="index"
|
||||
class="item"
|
||||
:style="getRotateAngle(index)"
|
||||
>
|
||||
<view class="drawTable-name">
|
||||
{{ item.prizeName }}
|
||||
</view>
|
||||
<view class="drawTable-img">
|
||||
<image :src="item.prizeImg" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pointer" :style="pointerStyle" @click="startTurns" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import './index';
|
||||
</style>
|
||||
6
uni_modules/nutui-uni/components/turntable/type.ts
Normal file
6
uni_modules/nutui-uni/components/turntable/type.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface TPrizeItem {
|
||||
id: string | number
|
||||
prizeName: string
|
||||
prizeColor: string
|
||||
prizeImg: string
|
||||
}
|
||||
Reference in New Issue
Block a user