This commit is contained in:
2026-01-05 12:47:14 +08:00
commit 1fc846fae3
1614 changed files with 162035 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
import type { ExtractPropTypes } from 'vue'
import { CLICK_EVENT } from '../_constants'
import { commonProps, makeArrayProp, makeNumberProp } from '../_utils'
export const dollmachineProps = {
...commonProps,
/**
* @description 初始化爪子的图片链接
*/
defaultClaw: {
type: String,
default:
'https://img14.360buyimg.com/imagetools/jfs/t1/146467/34/22553/4178/61b088afE198f676e/21952e7018d1d141.png',
},
/**
* @description 爪子抓到奖品的图片链接
*/
activeClaw: {
type: String,
default:
'https://img13.360buyimg.com/imagetools/jfs/t1/218082/28/7092/15914/61b088afEf9c253f7/8392e2b14bd8f43a.png',
},
/**
* @description 速度
*/
speed: makeNumberProp(20),
/**
* @description 奖品列表
*/
prizeList: makeArrayProp<any>([]),
/**
* @description 中奖奖品在列表的索引位置
*/
prizeIndex: makeNumberProp(-1),
}
export type DollMachineProps = ExtractPropTypes<typeof dollmachineProps>
export const dollmachineEmits = {
[CLICK_EVENT]: () => true,
startTurns: () => true,
endTurns: () => true,
}
export type DollMachineEmits = typeof dollmachineEmits

View File

@@ -0,0 +1,255 @@
<script setup lang="ts">
import type { ComponentInternalInstance } from 'vue'
import { computed, defineComponent, getCurrentInstance, onMounted, reactive, ref } from 'vue'
import { PREFIX } from '../_constants'
import { getMainClass } from '../_utils'
import { dollmachineEmits, dollmachineProps } from './dollmachine'
const props = defineProps(dollmachineProps)
const emit = defineEmits(dollmachineEmits)
const instance = getCurrentInstance() as ComponentInternalInstance
const giftPrize = ref()
const machineBoxDom = ref()
const machineToolsDom = ref()
const classes = computed(() => {
return getMainClass(props, componentName)
})
const toolsStyle = reactive({
left: '50%',
marginLeft: '0',
})
function leftCenter() {
toolsStyle.left = '50%'
const toolDomW = machineToolsDom.value.width
toolsStyle.marginLeft = `-${toolDomW / 2}px`
}
function leftRightMove(flag: string) {
const query = uni.createSelectorQuery().in(instance)
query.select('.machine-box').boundingClientRect()
query.select('.machine-tools').boundingClientRect()
query.exec((res) => {
machineBoxDom.value = res[0]
machineToolsDom.value = res[1]
setTimeout(() => {
const toolDomLeft = machineToolsDom.value.left
const boxDomW = machineBoxDom.value.width
const toolDomW = machineToolsDom.value.width
const max = boxDomW - toolDomW
if (
(flag === 'left' && toolDomLeft === 0)
|| (flag === 'right' && toolDomLeft === max)
) {
return false
}
const distance = flag === 'left' ? -30 : 30
const left: number = toolDomLeft + distance
if (flag === 'left')
toolsStyle.left = `${left < 0 ? 0 : left}px`
else
toolsStyle.left = `${left > max ? max : left}px`
}, 200)
})
}
// const topBottomMove = (flag: string) => {
// if (flag == "top") {
// } else {
// }
// };
function moveTools(flag: string) {
// toolsStyle.transform = "none";
toolsStyle.marginLeft = '0'
if (flag === 'left' || flag === 'right') {
leftRightMove(flag)
}
else {
// topBottomMove(flag);
}
}
const clawStyle = ref({
'background-image': `url(${props.defaultClaw})`,
'background-size': '100% 100%',
'background-position': 'center',
'background-repeat': 'no-repeat',
})
const machineRopeDom = ref()
const machineClawDom = ref()
const machineOperateDom = ref()
const machineLock = ref(false)
const initLock = ref(false)
const ropeDomHeight = ref({
height: '20px',
})
function startGame() {
emit('startTurns')
giftPrize.value = ''
machineLock.value = true
initLock.value = true
clawStyle.value['background-image'] = `url(${props.activeClaw})`
const heightBox = machineBoxDom.value.height
const heightTools = machineToolsDom.value.height
const heightOpe = machineOperateDom.value.height
ropeDomHeight.value.height = `${heightBox - heightOpe - heightTools - 20}px`
}
function initGame() {
ropeDomHeight.value.height = '20px'
}
function ropeHeightEnd() {
const query = uni.createSelectorQuery().in(instance)
query.select('.machine-rope').boundingClientRect()
query.exec((res) => {
machineRopeDom.value = res[0]
initLock.value = false
if (machineRopeDom.value.height === 20) {
machineLock.value = false
emit('endTurns')
}
clawStyle.value['background-image'] = `url(${props.defaultClaw})`
giftPrize.value = props.prizeList[props.prizeIndex].imagePath
setTimeout(() => {
initGame()
}, 200)
})
}
const giftEle: any = reactive([])
function setGiftEle() {
const left = Math.floor(Math.random() * 325)
const top = Math.floor(Math.random() * (150 - 70) + 70)
const angle = Math.floor(Math.random() * 90)
giftEle.push({
left: `${left}px`,
top: `${top}px`,
transform: `rotate(${angle}deg)`,
})
}
function init() {
giftPrize.value = ''
leftCenter()
initGame()
}
onMounted(() => {
uni.$once('dollMachineMounted', () => {
const query = uni.createSelectorQuery().in(instance)
query.select('.machine-box').boundingClientRect()
query.select('.machine-tools').boundingClientRect()
query.select('.machine-operate').boundingClientRect()
query.select('.machine-rope').boundingClientRect()
query.exec((res) => {
machineBoxDom.value = res[0]
machineToolsDom.value = res[1]
machineOperateDom.value = res[2]
machineRopeDom.value = res[3]
setTimeout(() => {
leftCenter()
// ropeHeightEnd()
}, 300)
})
})
uni.$emit('dollMachineMounted')
})
</script>
<script lang="ts">
const componentName = `${PREFIX}-doll-machine`
export default defineComponent({
name: componentName,
options: {
virtualHost: true,
addGlobalClass: true,
styleIsolation: 'shared',
},
})
</script>
<template>
<div :class="classes" :style="customClass">
<div class="machine-box">
<div class="machine-tools" :style="toolsStyle">
<div
id="machine-rope"
class="machine-rope"
:style="ropeDomHeight"
@transitionend="ropeHeightEnd"
@webkitTransitionEnd="ropeHeightEnd"
/>
<div ref="machineClawDom" class="machine-claw" :style="clawStyle">
<image
v-if="giftPrize"
:src="giftPrize"
alt="加载失败"
class="gift-prize"
/>
</div>
</div>
<div class="machine-gift-box">
<div class="box-glass">
<image
v-for="(item, index) of prizeList"
:id="`gift${index}`"
:key="index"
:ref="setGiftEle"
:src="item.imagePath"
class="gift-img"
:style="giftEle[index]"
@load="setGiftEle"
/>
</div>
<div class="machine-operate">
<div
class="machine-direction"
:class="[machineLock ? 'disabledClick' : '']"
>
<!-- <span
class="direction-block direction-block-top"
@click="moveTools('top')"
></span> -->
<span
class="direction-block direction-block-left"
@click="moveTools('left')"
/>
<span
class="direction-block direction-block-right"
@click="moveTools('right')"
/>
<!-- <span
class="direction-block direction-block-bottom"
@click="moveTools('bottom')"
></span> -->
</div>
<div
class="machine-btn"
:class="[
machineLock ? 'machine-disabled disabledClick' : 'machine-start',
]"
@click="startGame"
/>
<div
class="machine-reset-btn"
:class="[initLock ? 'disabledClick' : '']"
@click="init"
>
重置
</div>
</div>
</div>
</div>
</div>
</template>
<style lang="scss">
@import './index';
</style>

View File

@@ -0,0 +1,166 @@
.nut-doll-machine {
.machine-box {
position: relative;
width: 100%;
height: 690px;
background: url("https://img12.360buyimg.com/imagetools/jfs/t1/145351/6/24350/800170/61c95470E416c27bb/a3f62a18af70684e.png")
no-repeat center;
background-size: cover;
}
.machine-tools {
position: absolute;
top: 0;
// left: 50%;
// transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: all linear 0.3s;
}
.machine-rope {
top: 50px;
width: 10px;
height: 20px;
background: linear-gradient(to bottom right, #ff9800, #ffeb3b);
transition: all linear 2s;
}
.machine-claw {
width: 80px;
height: 70px;
// background: url("https://img14.360buyimg.com/imagetools/jfs/t1/146467/34/22553/4178/61b088afE198f676e/21952e7018d1d141.png")
// no-repeat center;
// background-size: 100% 100%;
text-align: center;
.gift-prize {
width: 60px;
height: 60px;
margin-top: 30px;
}
}
.machine-gift-box {
position: absolute;
bottom: 0;
display: flex;
flex-direction: column;
width: 100%;
// height: 100%;
.box-glass {
position: relative;
width: 100%;
height: 200px;
background-color: #f1d90556;
.gift-img {
position: absolute;
width: 50px;
height: 50px;
}
}
}
.machine-operate {
display: flex;
align-items: center;
justify-content: space-around;
width: 90%;
padding: 5px 20px;
margin: 0 auto;
// position: absolute;
// bottom: 0;
// left: 50%;
// transform: translateX(-50%);
.machine-direction {
position: relative;
width: 50px;
height: 50px;
background: url("https://img14.360buyimg.com/imagetools/jfs/t1/3283/2/18965/1403/62c28eb5E0cfb824b/9b90cde1898d18af.png")
no-repeat center;
background-size: 100% 100%;
.direction-block {
position: absolute;
top: 50%;
display: block;
width: 15px;
height: 15px;
// background-color: #ff9800;
&:nth-child(1) {
left: 0;
transform: translateY(-50%);
}
&:nth-child(2) {
right: 0;
transform: translateY(-50%);
}
// &:nth-child(1),
// &:nth-child(4) {
// display: block;
// }
// &:nth-child(1) {
// top: 0;
// left: 50%;
// transform: translateX(-50%);
// }
// &:nth-child(2) {
// top: 50%;
// left: 0;
// transform: translateY(-50%);
// }
// &:nth-child(3) {
// top: 50%;
// right: 0;
// transform: translateY(-50%);
// }
// &:nth-child(4) {
// bottom: 0;
// left: 50%;
// transform: translateX(-50%);
// }
}
}
.machine-btn {
width: 50px;
height: 60px;
}
.machine-start {
background: url("https://img13.360buyimg.com/imagetools/jfs/t1/205479/17/4245/32041/61309346E02bd3b6b/b41be60bedbb1e69.png")
no-repeat center;
background-size: contain;
}
.machine-disabled {
background: url("https://img10.360buyimg.com/imagetools/jfs/t1/193040/14/21217/16320/61309346E6569e270/36e45126a5f1fc9c.png")
no-repeat center;
background-size: contain;
}
.machine-reset-btn {
display: flex;
align-items: center;
justify-content: center;
color: #ff9800;
}
}
}
// stylelint-disable selector-class-pattern
.disabledClick {
pointer-events: none !important;
cursor: not-allowed !important;
}

View File

@@ -0,0 +1 @@
export type * from './dollmachine'