<view class="page">
<view class="drum_bg">
<view v-if="myMoonCake" class="moon_cake">我的月饼:{{ myMoonCake }}</view>
<view class="drum_countdown" v-if="startDrum">
{{ drumTimer }}
</view>
<view class="drum_number" :class="{ animation: showAnimation }" v-if="drumCount > 0">连击 X{{ drumCount }}</view>
<view>
<image :src="`${elec_ossImgUrl}rabbit_left.png`" mode="widthFix" class="rabbit_left" />
<image :src="`${elec_ossImgUrl}rabbit_right.png`" mode="widthFix" class="rabbit_right" />
</view>
<view @click="changeMusic">
<view class="music_bg" v-if="music"></view>
<image :src="`${elec_ossImgUrl}drum_turnon.png`" mode="widthFix" v-if="music" class="music" :class="music ? 'rotate' : ''" />
<image :src="`${elec_ossImgUrl}drum_turnoff.png`" mode="widthFix" v-else class="music" />
</view>
<view>
<view class="drum_ready" :class="{ readyAnimation: showDrumReady }" v-if="startReady">{{ readyTime }}
</view>
<image :src="`${elec_ossImgUrl}drum_surface.png`" mode="widthFix" class="surface" @click="handleClick" />
<view class="ripple_container">
<view class="circle" :class="{ expand: showAnimation }"></view>
<view class="circle1" :class="{ expand: showAnimation }"></view>
<view class="circle2" :class="{ expand: showAnimation }"></view>
</view>
</view>
<view v-if="drumUses" class="button_container">
<view class="drum_times">
<view class="times_num">{{ drumUses }}</view>
<view class="times_text">剩余敲击机会</view>
</view>
<view class="drum_start button-top" @click="handleStart">
<view class="start_text">{{ startDrum || startReady ? `敲击鼓面` : `开始敲击` }}</view>
</view>
<view class="drum_obtain" @click="getDrumUses">
<slot name="getMoreChance"></slot>
<view class="obtain_text">获取机会</view>
</view>
</view>
<!-- 增加插槽 -->
<slot></slot>
</view>
</view>
</template>
<script>
const { ossImgUrl } = getApp().globalData; //实例化app.js中的变量和常量
export default {
props: {
// 敲鼓时间
drummingCountdown: {
type: String,
default: () => ''
},
// 敲鼓使用机会次数
drumUses: {
type: String,
default: () => ''
},
// 我的月饼
myMoonCake: {
type: String,
default: () => ''
},
bgMusic: {
type: String,
default: () => ''
}
},
inject: ['getIsActionDrum'],
data() {
return {
drumCount: 0,//打击次数
drumTimer: null,
readyTime: 3,//准备时间
showAnimation: false,
showDrumReady: false,
startDrum: false,
startReady: false,
elec_ossImgUrl: `${ossImgUrl}electricalMall/`,
music: true,
backgroundMusic: null, // 背景音乐实例
drumSound: null, // 鼓点音效实例
userAgent: '',
DrumRestrict: false,//重置打击音效时的限制
};
},
computed: {
isActionDrum() {
let flag = false;
if (this.getIsActionDrum) {
flag = this.getIsActionDrum(); // getter
} else {
flag = false;
}
return flag;
},
},
watch: {
drummingCountdown(newVal) {
if (newVal > 0 && !this.startDrum) {
this.drumTimer = newVal;
}
}
},
mounted() {
// this.audioConfig()
// this.drumTimer = this.drummingCountdown
const unWatch = this.$watch(() => this.bgMusic, (newVal) => {
if (newVal) {
this.audioConfig();
unWatch();
}
}, { immediate: true });
},
onHide() {
this.backgroundMusic.stop();
this.drumSound.stop();
this.music = false
},
beforeDestroy() {
this.backgroundMusic.stop();
this.drumSound.stop();
this.music = false
},
methods: {
audioConfig() {
// 创建背景音乐实例
用来创建并返回内部 audio 上下文 `innerAudioContext` 对象。APP、H5、微信小程序都支持此方法。
this.backgroundMusic = uni.createInnerAudioContext();
this.backgroundMusic.src = this.bgMusic; // 背景音乐路径
this.backgroundMusic.volume = 0.5; // 设置背景音乐循环音量
this.backgroundMusic.loop = true; // 设置背景音乐循环播放
// #ifdef H5
const userAgent = navigator.appVersion;
let website = ['Chrome', 'Firefox', 'Safari', 'Edge', 'Opera', 'Chromium']
let noPlay = false
for (let i = 0; i < website.length; i++) {
const element = website[i];
noPlay = userAgent.includes(element);
if (noPlay) {
break
}
}
if (noPlay) {
this.music = false
this.$forceUpdate()
} else {
this.backgroundMusic.play();
}
// #endif
// #ifndef H5
this.backgroundMusic.play();
// #endif
// 创建鼓点音效实例
this.drumSound = uni.createInnerAudioContext();
this.drumSound.src = `${this.elec_ossImgUrl}drum.mp3`; // 鼓点音效路径
this.drumSound.volume = 1;
},
changeMusic() {
this.music = !this.music;
if (this.music) {
this.backgroundMusic.play();
} else {
this.backgroundMusic.stop();
}
},
addDrumRate() {
let that = this
if (!that.DrumRestrict) {
that.drumSound.stop();
that.DrumRestrict = true
that.drumSound.seek(0);
that.drumSound.play();
setTimeout(() => {
that.DrumRestrict = false;
}, 200);
}
},
handleClick() {
let that = this
// 点击敲打开始鼓点动画和音效
that.showAnimation = true;
setTimeout(() => {
that.showAnimation = false;
}, 200);
that.addDrumRate()
// end
// 开始敲击之后开始计数
if (that.startDrum) {
that.drumCount++;
}
},
handleStart() {
if (this.startDrum || this.startReady) {
return;
}
this.$emit('drumStart');
if (this.drumUses > 0) {
if (!this.startDrum) {
if (this.drummingCountdown) { this.drumTimer = this.drummingCountdown; }
// 开始敲击
this.drumCount = 0
this.readyTime = 3
this.readyCountdown()
}
} else {
uni.showToast({ title: '次数已用完,快去完成任务获取更多机会吧!', icon: 'none' })
this.$emit('drumFail');
}
},
// 准备倒计时
readyCountdown() {
this.startReady = true
this.showDrumReady = true
setTimeout(() => {
this.showDrumReady = false;
}, 200);
let countdown = setInterval(() => {
this.showDrumReady = true
setTimeout(() => {
this.showDrumReady = false;
}, 200);
this.readyTime--;
if (this.readyTime <= 0) {
clearInterval(countdown);
this.startTiming()
}
}, 1000);
},
// 开始计数
startTiming() {
if (this.drumTimer > 0) {
this.startReady = false
this.startDrum = true;
this.startCountdown();
}
setTimeout(() => {
this.startDrum = false;
this.showDrumReady = false
}, this.drumTimer * 1000);
},
// 打击倒计时
startCountdown() {
let countdown = setInterval(() => {
this.drumTimer--;
if (this.drumTimer <= 0) {
this.startDrum = false;
this.$emit('drumCount', this.drumCount)
clearInterval(countdown);
}
}, 1000);
},
// 获取使用机会
getDrumUses() {
// 如果正在执行中
if (this.isActionDrum) return;
this.$emit('getDrumUses')
}
}
};
</script>
<style>
.page {
position: relative;
touch-action: manipulation;
}
img {
-webkit-touch-callout: none;
/* 禁止长按图片弹出菜单 */
-webkit-user-select: none;
/* 禁止选择图片 */
pointer-events: none;
/* 禁止图片点击事件 */
}
.drum_bg {
width: 750rpx;
height: 1080rpx;
background-image: url('https://tineco-gngw.oss-accelerate.aliyuncs.com/electricalMall/mid-autumn_bg.png');
background-size: 100%;
position: relative;
}
.moon_cake {
width: 200rpx;
height: 40rpx;
font-size: 28rpx;
font-family: SourceHanSansSC-Medium, SourceHanSansSC;
font-weight: 600;
color: #df3d2c;
line-height: 40rpx;
margin: 730rpx 0 0 280rpx;
text-align: center;
position: absolute;
}
.music {
width: 50rpx;
height: 50rpx;
margin: 30rpx 26rpx;
z-index: 8;
position: absolute;
}
.music_bg {
width: 50rpx;
height: 50rpx;
margin: 30rpx 26rpx;
background-color: #be7fce;
border: 5rpx solid #be7fce;
border-radius: 50%;
animation: musicRotate 2s linear infinite;
position: absolute;
z-index: 1;
}
@keyframes musicRotate {
0% {
transform: scale(1.2);
opacity: 0.8;
}
50% {
transform: scale(1.5);
opacity: 0.5;
}
100% {
transform: scale(1.8);
opacity: 0.2;
}
}
.rotate {
animation: rotate 3s linear infinite;
}
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.surface {
width: 380rpx;
height: 370rpx;
margin: 294rpx 0 0 164rpx;
pointer-events: auto;
}
.drum_ready {
width: 200rpx;
font-size: 100rpx;
font-family: SourceHanSansSC-Medium, SourceHanSansSC;
font-weight: normal;
color: #f84b31;
text-shadow: 0px 4px 8px #cc9a06;
z-index: 2;
position: absolute;
margin: 400rpx 0 0 260rpx;
text-align: center;
opacity: 1;
transform: scale(1);
transition: all 0.3s;
}
.drum_ready.readyAnimation {
opacity: 1;
transform: scale(2);
}
.button_container {
display: flex;
justify-content: center;
align-items: top;
position: absolute;
bottom: 50rpx;
left: 34rpx;
}
.button-top {
margin: 16rpx 20rpx;
}
.drum_times {
width: 164rpx;
height: 122rpx;
background-image: url('https://tineco-gngw.oss-accelerate.aliyuncs.com/electricalMall/drum_times.png');
background-size: 100%;
position: relative;
}
.times_num {
font-size: 36rpx;
font-family: SourceHanSansSC-Medium, SourceHanSansSC;
font-weight: 500;
color: #df3d2c;
line-height: 54rpx;
margin-top: 22rpx;
text-align: center;
}
.times_num:after {
content: '次';
font-size: 28rpx;
font-family: SourceHanSansSC-Regular, SourceHanSansSC;
font-weight: 500;
}
.times_text {
width: 164rpx;
font-size: 24rpx;
font-family: SourceHanSansSC-Medium, SourceHanSansSC;
font-weight: 500;
color: #feeeca;
line-height: 36rpx;
margin-top: 6rpx;
margin-left: 12rpx;
position: absolute;
}
.drum_start {
width: 316rpx;
height: 92rpx;
background-image: url('https://tineco-gngw.oss-accelerate.aliyuncs.com/electricalMall/drum_start.png');
background-size: 100%;
}
.start_text {
width: 316rpx;
height: 92rpx;
font-size: 43rpx;
font-family: SourceHanSansSC-Bold, SourceHanSansSC;
font-weight: bold;
color: #feeeca;
line-height: 92rpx;
text-align: center;
}
.drum_obtain {
width: 156rpx;
height: 156rpx;
background-image: url('https://tineco-gngw.oss-accelerate.aliyuncs.com/electricalMall/drum_obtain.png');
background-size: 100%;
position: relative;
}
.obtain_text {
width: 56rpx;
font-size: 28rpx;
font-family: SourceHanSansSC-Medium, SourceHanSansSC;
font-weight: 500;
color: #feeeca;
margin-left: 52rpx;
line-height: 32rpx;
margin-top: 32rpx;
}
.rabbit_left {
width: 257rpx;
height: 290rpx;
position: absolute;
margin: 462rpx 0 0 56rpx;
z-index: 2;
pointer-events: none;
}
.rabbit_right {
width: 287rpx;
height: 355rpx;
position: absolute;
margin: 450rpx 0 0 436rpx;
z-index: 2;
pointer-events: none;
}
.drum_countdown {
width: 90rpx;
height: 91rpx;
background-image: url('https://tineco-gngw.oss-accelerate.aliyuncs.com/electricalMall/drum_countdown.png');
background-size: 100%;
margin: 244rpx 0 0 16rpx;
position: absolute;
font-size: 36rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #fffaa5;
line-height: 90rpx;
text-align: center;
}
.drum_countdown:after {
content: 's';
}
.drum_number {
width: 750rpx;
font-size: 48rpx;
font-family: SourceHanSansSC-Bold, SourceHanSansSC;
font-weight: bold;
color: #fffaa5;
line-height: 57rpx;
text-shadow: 0px 4px 8px #b353cf;
position: absolute;
margin: 220rpx 0;
text-align: center;
opacity: 1;
transform: scale(1);
transition: all 0.2s;
}
//次数跳动效果
.drum_number.animation {
opacity: 1;
transform: scale(1.5);
}
.ripple_container {
position: absolute;
z-index: 1;
top: 470rpx;
left: 360rpx;
pointer-events: none;
}
.circle {
width: 10rpx;
height: 10rpx;
background-color: #ffe496;
border: 5rpx solid #ffeed7;
border-radius: 50%;
overflow: hidden;
transition: all 0.2s;
position: absolute;
z-index: 1;
}
.circle1 {
width: 10rpx;
height: 10rpx;
background-color: #ffe496;
border: 5rpx solid #ffe496;
border-radius: 50%;
overflow: hidden;
transition: all 0.2s;
position: absolute;
}
.circle2 {
width: 10rpx;
height: 10rpx;
background-color: #ffe496;
border: 5rpx solid #ffe496;
border-radius: 50%;
overflow: hidden;
transition: all 0.2s;
position: absolute;
}
//波纹效果 根据缩放实现
.circle.expand {
transform: scale(20);
opacity: 0;
}
.circle1.expand {
transform: scale(40);
opacity: 0;
}
.circle2.expand {
transform: scale(60);
opacity: 0;
}
</style>
动效演示地址
hepengwei.cn/#/canvas/pa…
源码地址
github.com/hepengwei/v…