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,133 @@
.nut-marquee {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 300px;
height: 300px;
margin: 0 auto;
border-radius: 8px;
// stylelint-disable selector-class-pattern
.bgContent {
position: absolute;
width: 100%;
height: 100%;
}
.marqueeBg {
position: absolute;
width: 100%;
height: 100%;
background: url("https://img10.360buyimg.com/imagetools/jfs/t1/189406/15/21216/26045/61309346E9aa7922b/5dc34e22d3a7bb0e.png")no-repeat center;
background-size: 100% 100%;
}
.start {
position: relative;
top: -5px;
left: -2px;
width: 75px;
height: 75px;
background: url("https://img13.360buyimg.com/imagetools/jfs/t1/205479/17/4245/32041/61309346E02bd3b6b/b41be60bedbb1e69.png") no-repeat center;
background-size: 100% 100%;
}
.disabledDraw {
background: url("https://img10.360buyimg.com/imagetools/jfs/t1/193040/14/21217/16320/61309346E6569e270/36e45126a5f1fc9c.png") no-repeat center;
background-size: 100% 100%;
}
.gift-list {
padding: 0;
margin: 0;
.gift-item {
position: absolute;
width: 75px;
height: 75px;
list-style: none;
background: url("https://img10.360buyimg.com/imagetools/jfs/t1/187454/31/21425/27854/61309346E7c791c2c/a12649fbffb63a34.png") no-repeat center;
background-size: 100% 100%;
.gift-img {
width: 35px;
height: 35px;
margin: 8px auto;
image {
width: 100%;
height: 100%;
}
}
.desc {
display: block;
max-width: 70px;
margin: 0 auto;
overflow: hidden;
font-size: 12px;
font-weight: 500;
color:#fff;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
}
}
// 上面3个奖品
.gift-1,.gift-2,.gift-3 {
top: 25px;
}
.gift-1 {
left: 15px;
}
.gift-2 {
left: 110px;
}
.gift-3 {
left: 205px;
}
// 中间2个奖品
.gift-4,.gift-8 {
top: 110px;
}
.gift-4 {
left: 205px;
}
.gift-8 {
left: 15px;
}
// 下面3个奖品
.gift-5,.gift-6,.gift-7 {
top: 190px;
}
.gift-5 {
left: 205px;
}
.gift-6 {
left: 110px;
}
.gift-7 {
left: 15px;
}
// 中奖
.active {
background: url("https://img10.360buyimg.com/imagetools/jfs/t1/189406/15/21216/26045/61309346E9aa7922b/5dc34e22d3a7bb0e.png") no-repeat center;
background-size: 100% 100%;
}
}
}

View File

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

View File

@@ -0,0 +1,61 @@
import type { ExtractPropTypes } from 'vue'
import { commonProps, makeNumericProp } from '../_utils'
export const marqueeProps = {
...commonProps,
/**
* @description 抽奖样式
*/
styleOpt: {
type: Object,
default: () => {
return {
itemStyle: {},
startStyle: {},
bgStyle: {
background: 'rgb(255, 231, 149)',
},
}
},
},
/**
* @description 奖品列表
*/
prizeList: {
type: Array<any>,
required: true,
},
/**
* @description 是否禁用开始抽奖点击
*/
disabled: Boolean,
/**
* @description 中奖奖品的index
*/
prizeIndex: makeNumericProp(-1),
/**
* @description 初始转动速度
*/
speed: makeNumericProp(150),
/**
* @description 预抽奖,转动多少次进入抽奖环节
*/
circle: makeNumericProp(30),
}
export type MarqueeProps = ExtractPropTypes<typeof marqueeProps>
export const marqueeEmits = {
click: () => true,
/**
* @description 开始跑动的回调函数,此时将接口中的中奖索引,赋值到 prize-index
*/
startTurns: () => true,
/**
* @description 停止跑动后的回调函数
*/
endTurns: () => true,
}
export type MarqueeEmits = typeof marqueeEmits

View File

@@ -0,0 +1,138 @@
<script setup lang="ts">
import { computed, defineComponent, onMounted, reactive, ref, watch } from 'vue'
import { PREFIX } from '../_constants'
import { getMainClass } from '../_utils'
import { marqueeEmits, marqueeProps } from './marquee'
const props = defineProps(marqueeProps)
const emit = defineEmits(marqueeEmits)
let { prizeList, styleOpt } = reactive(props)
const classes = computed(() => {
return getMainClass(props, componentName)
})
onMounted(() => {
// init();
})
watch(
() => props.prizeList,
(list, prevList) => {
prizeList = list
},
)
const marqueeDom: any = ref(null)
// 上锁
const lock = ref(false)
// 转动到的商品的index
const index = ref(0)
// 转动跑格子次数
const cellNumber = ref(0)
// 初始速度
const velocity = ref(+props.speed)
// 至少需要转动多少次再进入抽奖环节
const cycle = ref(props.circle)
// 转动定时器
const timer = ref<any>(null)
const bgContentStyle = styleOpt.bgStyle
const bgItemStyle = styleOpt.itemStyle
const cursorStyle = styleOpt.startStyle
// 每次转动
function rollMarquee() {
cellNumber.value += 1
let idx = index.value // 当前转动到哪个位置
const count = 8 // 总共有多少个位置
idx += 1
if (idx > count - 1)
idx = 0
index.value = idx
getPrize()
}
function getPrize() {
// 当前转动次数符合条件 && 转动到中奖位置
if (cellNumber.value > +cycle.value && props.prizeIndex === index.value) {
clearTimeout(timer.value) // 清除转动定时器
// 恢复默认值和初始值
timer.value = 0
cellNumber.value = 0
velocity.value = +props.speed
cycle.value = props.circle
setTimeout(() => {
index.value = +props.prizeIndex
emit('endTurns')
lock.value = false
}, 500)
}
else {
if (cellNumber.value < +cycle.value)
velocity.value -= 4
else
velocity.value += 20
// 开始转动抽奖
timer.value = setTimeout(rollMarquee, velocity.value)
}
}
function startDraw() {
emit('click')
if (props.disabled)
return
if (!lock.value) {
lock.value = true
emit('startTurns')
rollMarquee()
}
}
</script>
<script lang="ts">
const componentName = `${PREFIX}-marquee`
export default defineComponent({
name: componentName,
options: {
virtualHost: true,
addGlobalClass: true,
styleIsolation: 'shared',
},
})
</script>
<template>
<view ref="marqueeDom" :class="classes" :style="customStyle">
<view class="bgContent" />
<view class="marqueeBg" :style="bgContentStyle" />
<view
class="start"
:class="[{ disabledDraw: lock || props.disabled }]"
:style="cursorStyle"
@click="startDraw"
/>
<ul class="gift-list">
<li
v-for="(item, i) in prizeList"
:key="`luckmarquee${i}`"
class="gift-item"
:class="[`gift-${i + 1}`, { active: index === i }]"
:style="bgItemStyle"
>
<div class="gift-img">
<image :src="item.prizeImg" />
</div>
<span class="desc" v-html="item.prizeName" />
</li>
</ul>
</view>
</template>
<style lang="scss">
@import './index';
</style>