@ -0,0 +1,87 @@ |
|||
<template> |
|||
<view class="music-control" @click="toggleMusic"> |
|||
<text class="music-text" :class="{ 'rotating': isPlaying }"> |
|||
{{ isPlaying ? '🎵' : '🔇' }} |
|||
</text> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'MusicControl', |
|||
data() { |
|||
return { |
|||
isPlaying: false |
|||
} |
|||
}, |
|||
mounted() { |
|||
// 组件挂载时同步音乐状态 |
|||
this.syncMusicState(); |
|||
|
|||
// 添加定时器,每秒同步一次状态 |
|||
this.timer = setInterval(() => { |
|||
this.syncMusicState(); |
|||
}, 1000); |
|||
}, |
|||
beforeUnmount() { |
|||
// 组件卸载前清除定时器 |
|||
if (this.timer) { |
|||
clearInterval(this.timer); |
|||
} |
|||
}, |
|||
methods: { |
|||
syncMusicState() { |
|||
const app = getApp(); |
|||
if (app && app.globalData) { |
|||
this.isPlaying = app.globalData.isMusicPlaying; |
|||
} |
|||
}, |
|||
|
|||
toggleMusic() { |
|||
const app = getApp(); |
|||
if (!app || !app.globalData || !app.globalData.bgMusic) { |
|||
console.error('背景音乐未初始化'); |
|||
return; |
|||
} |
|||
|
|||
const bgMusic = app.globalData.bgMusic; |
|||
|
|||
// 直接基于当前组件的状态切换 |
|||
if (this.isPlaying) { |
|||
bgMusic.pause(); |
|||
} else { |
|||
bgMusic.play(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.music-control { |
|||
position: fixed; |
|||
right: 30rpx; |
|||
bottom: 30rpx; |
|||
width: 80rpx; |
|||
height: 80rpx; |
|||
border-radius: 50%; |
|||
background-color: rgba(0, 0, 0, 0.3); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
z-index: 999; |
|||
} |
|||
|
|||
.music-text { |
|||
font-size: 40rpx; |
|||
} |
|||
|
|||
.rotating { |
|||
animation: rotate 3s linear infinite; |
|||
} |
|||
|
|||
@keyframes rotate { |
|||
from { transform: rotate(0deg); } |
|||
to { transform: rotate(360deg); } |
|||
} |
|||
</style> |
@ -0,0 +1,97 @@ |
|||
<template> |
|||
<view v-if="visible" class="share-guide-mask" @click="closeGuide"> |
|||
<view class="guide-content"> |
|||
<image class="guide-arrow" :src="arrowImage" mode=""></image> |
|||
<view v-for="(text, index) in textArray" :key="index" class="guide-text"> |
|||
{{ text }} |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
value: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
text: { |
|||
type: [String, Array], |
|||
default: '点击右上角"..."选择"分享到朋友圈"' |
|||
}, |
|||
arrowImage: { |
|||
type: String, |
|||
default: '/static/share-arrow.png' |
|||
} |
|||
}, |
|||
computed: { |
|||
visible: { |
|||
get() { |
|||
return this.value; |
|||
}, |
|||
set(val) { |
|||
this.$emit('input', val); |
|||
} |
|||
}, |
|||
textArray() { |
|||
if (Array.isArray(this.text)) { |
|||
return this.text; |
|||
} |
|||
return [this.text]; |
|||
} |
|||
}, |
|||
methods: { |
|||
closeGuide() { |
|||
this.visible = false; |
|||
this.$emit('close'); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.share-guide-mask { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background-color: rgba(0, 0, 0, 0.7); |
|||
z-index: 9999; |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
align-items: flex-start; |
|||
} |
|||
|
|||
.guide-content { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
padding-top: 100rpx; |
|||
padding-right: 60rpx; |
|||
} |
|||
|
|||
.guide-arrow { |
|||
width: 100rpx; |
|||
height: 160rpx; |
|||
animation: arrow-up 1s infinite alternate; |
|||
} |
|||
|
|||
.guide-text { |
|||
font-size: 32rpx; |
|||
color: #FFFFFF; |
|||
font-weight: bold; |
|||
margin-bottom: 10rpx; |
|||
text-align: center; |
|||
} |
|||
|
|||
@keyframes arrow-up { |
|||
from { |
|||
transform: translateY(0); |
|||
} |
|||
to { |
|||
transform: translateY(-15rpx); |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,68 @@ |
|||
<template> |
|||
<image v-if="selectedItem" :src="selectedItem.image" class="random-image" mode="" /> |
|||
<view v-if="selectedItem" class="random-image-name"> |
|||
{{selectedItem.name}} |
|||
</view> |
|||
<view v-if="selectedItem" class="random-image-desc"> |
|||
{{selectedItem.desc}} |
|||
</view> |
|||
<MusicControl /> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
|
|||
const props = defineProps({ |
|||
images: { |
|||
type: Array, |
|||
required: true |
|||
} |
|||
}) |
|||
const selectedItem = ref(null) |
|||
|
|||
// 随机选择一项 |
|||
const selectRandomImage = () => { |
|||
if (props.images && props.images.length > 0) { |
|||
const randomIndex = Math.floor(Math.random() * props.images.length) |
|||
selectedItem.value = props.images[randomIndex] |
|||
} |
|||
} |
|||
onMounted(() => { |
|||
selectRandomImage() |
|||
}) |
|||
defineExpose({ |
|||
selectRandomImage, |
|||
selectedItem |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.random-image { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.random-image-name { |
|||
position: absolute; |
|||
bottom: 30%; |
|||
left: 50%; |
|||
transform: translate(-50%, -50%); |
|||
color: #ffffff; |
|||
font-size: 52rpx; |
|||
} |
|||
|
|||
.random-image-desc { |
|||
white-space: nowrap; |
|||
position: absolute; |
|||
bottom: 25%; |
|||
left: 50%; |
|||
transform: translate(-50%, -50%); |
|||
color: #ffffff; |
|||
font-size: 24rpx; |
|||
font-weight: 300; |
|||
opacity: .8; |
|||
} |
|||
</style> |
After Width: | Height: | Size: 27 MiB |
After Width: | Height: | Size: 18 MiB |
After Width: | Height: | Size: 31 MiB |
After Width: | Height: | Size: 35 MiB |
After Width: | Height: | Size: 28 MiB |
After Width: | Height: | Size: 27 MiB |
After Width: | Height: | Size: 19 MiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 226 KiB |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 1.5 MiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 1.8 MiB |
After Width: | Height: | Size: 264 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 180 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 1.0 MiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 183 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 743 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 1.0 MiB |
After Width: | Height: | Size: 243 KiB |
After Width: | Height: | Size: 1.8 MiB |
After Width: | Height: | Size: 152 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 128 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 2.5 MiB |
After Width: | Height: | Size: 4.5 MiB |
After Width: | Height: | Size: 4.5 MiB |
After Width: | Height: | Size: 4.1 MiB |
After Width: | Height: | Size: 3.5 MiB |
After Width: | Height: | Size: 3.0 MiB |
After Width: | Height: | Size: 3.2 MiB |
After Width: | Height: | Size: 101 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 1.4 MiB |
After Width: | Height: | Size: 4.2 MiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 1.7 MiB |
After Width: | Height: | Size: 169 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 1.5 MiB |
After Width: | Height: | Size: 162 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 1.7 MiB |
After Width: | Height: | Size: 182 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 1.5 MiB |
After Width: | Height: | Size: 162 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 1.5 MiB |
After Width: | Height: | Size: 170 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 1.6 MiB |
After Width: | Height: | Size: 163 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 1.5 MiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 851 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 16 MiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 3.3 MiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 4.4 MiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 17 MiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 4.6 MiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 15 MiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 15 MiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 10 KiB |