aaa
doum
2026-06-04 08e9a67dd679f311e79a27b04cd0c53a30b4bccf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
let hoverAudio = null
let clickAudio = null
let unlocked = false
let unlockListenerAdded = false
 
function getHoverAudio() {
  if (!hoverAudio) {
    hoverAudio = uni.createInnerAudioContext()
    hoverAudio.src = '/static/sounds/hover.mp3'
  }
  return hoverAudio
}
 
function getClickAudio() {
  if (!clickAudio) {
    clickAudio = uni.createInnerAudioContext()
    clickAudio.src = '/static/sounds/click.mp3'
  }
  return clickAudio
}
 
/** 安全播放,吞掉 autoplay 策略导致的 Promise  rejection */
function safePlay(audio) {
  try {
    audio.stop()
    const ret = audio.play()
    if (ret && typeof ret.then === 'function') {
      ret.catch(() => {})
    }
  } catch (e) {}
}
 
/** 首次用户点击/触摸后解锁音频(hover 不算用户手势) */
function primeAudio() {
  ;[getHoverAudio(), getClickAudio()].forEach(audio => {
    try {
      audio.volume = 0
      const ret = audio.play()
      const finish = () => {
        audio.stop()
        audio.volume = 1
      }
      if (ret && typeof ret.then === 'function') {
        ret.then(finish).catch(() => { audio.volume = 1 })
      } else {
        setTimeout(finish, 30)
      }
    } catch (e) {
      audio.volume = 1
    }
  })
}
 
export function setupSoundUnlock() {
  if (unlockListenerAdded || typeof document === 'undefined') return
  unlockListenerAdded = true
  const onUnlock = () => {
    if (unlocked) return
    unlocked = true
    primeAudio()
    document.removeEventListener('click', onUnlock, true)
    document.removeEventListener('touchstart', onUnlock, true)
    document.removeEventListener('keydown', onUnlock, true)
  }
  document.addEventListener('click', onUnlock, true)
  document.addEventListener('touchstart', onUnlock, true)
  document.addEventListener('keydown', onUnlock, true)
}
 
function ensureUnlocked() {
  if (!unlocked) {
    unlocked = true
    primeAudio()
  }
}
 
export function playHoverSound() {
  if (!unlocked) return
  safePlay(getHoverAudio())
}
 
export function playClickSound() {
  ensureUnlocked()
  safePlay(getClickAudio())
}
 
setupSoundUnlock()