Shopify主题背景音乐播放器 - 可配置Section完整开发指南
为Shopify主题开发一个功能强大的背景音乐播放器,不仅能营造品牌氛围,还能提供丰富的配置选项和用户交互功能。本指南将带你构建一个企业级的音乐播放器Section。
Section Schema 配置
首先创建完整的 Schema 配置,让用户可以在后台自定义播放器设置:
{
"name": "背景音乐播放器",
"tag": "section",
"class": "bg-music-section",
"settings": [
{
"type": "header",
"content": "播放器设置"
},
{
"type": "checkbox",
"id": "enable_music",
"label": "启用背景音乐",
"default": true
},
{
"type": "checkbox",
"id": "auto_play",
"label": "自动播放",
"default": false,
"info": "受浏览器政策限制,需要用户首次交互后才能播放"
},
{
"type": "select",
"id": "play_mode",
"label": "播放模式",
"default": "loop",
"options": [
{ "value": "loop", "label": "循环播放" },
{ "value": "random", "label": "随机播放" },
{ "value": "single", "label": "单曲循环" },
{ "value": "once", "label": "播放一次" }
]
},
{
"type": "range",
"id": "default_volume",
"label": "默认音量",
"min": 0,
"max": 100,
"step": 5,
"unit": "%",
"default": 50
},
{
"type": "header",
"content": "播放器外观"
},
{
"type": "select",
"id": "player_theme",
"label": "播放器主题",
"default": "dark",
"options": [
{ "value": "dark", "label": "深色主题" },
{ "value": "light", "label": "浅色主题" },
{ "value": "gradient", "label": "渐变主题" },
{ "value": "brand", "label": "品牌色主题" }
]
},
{
"type": "select",
"id": "player_position",
"label": "播放器位置",
"default": "bottom-left",
"options": [
{ "value": "bottom-left", "label": "左下角" },
{ "value": "bottom-right", "label": "右下角" },
{ "value": "top-left", "label": "左上角" },
{ "value": "top-right", "label": "右上角" }
]
},
{
"type": "select",
"id": "player_size",
"label": "播放器大小",
"default": "medium",
"options": [
{ "value": "small", "label": "小" },
{ "value": "medium", "label": "中" },
{ "value": "large", "label": "大" }
]
},
{
"type": "checkbox",
"id": "show_progress",
"label": "显示播放进度",
"default": true
},
{
"type": "checkbox",
"id": "show_volume_control",
"label": "显示音量控制",
"default": true
}
],
"blocks": [
{
"type": "music_track",
"name": "音乐曲目",
"settings": [
{
"type": "text",
"id": "track_name",
"label": "曲目名称",
"placeholder": "例如:品牌主题曲"
},
{
"type": "text",
"id": "artist_name",
"label": "艺术家",
"placeholder": "例如:XXXX"
},
{
"type": "url",
"id": "audio_url",
"label": "音频文件链接",
"info": "支持 MP3、OGG、AAC 格式,建议文件小于 5MB"
},
{
"type": "image_picker",
"id": "cover_image",
"label": "封面图片(可选)"
}
]
}
],
"presets": [
{
"name": "背景音乐播放器",
"blocks": [
{
"type": "music_track",
"settings": {
"track_name": "示例音乐",
"artist_name": "店铺音乐"
}
}
]
}
]
}
完整 Section 代码
Section 主体结构 (bg-music.liquid
)
{%- if section.settings.enable_music and section.blocks.size > 0 -%}
<section
id="bg-music-section"
class="bg-music-wrapper"
data-auto-play="{{ section.settings.auto_play }}"
data-play-mode="{{ section.settings.play_mode }}"
data-default-volume="{{ section.settings.default_volume }}"
data-theme="{{ section.settings.player_theme }}"
data-position="{{ section.settings.player_position }}"
data-size="{{ section.settings.player_size }}"
>
<!-- 音频播放器(隐藏的原生播放器) -->
<div class="audio-container">
{%- for block in section.blocks -%}
{%- case block.type -%}
{%- when 'music_track' -%}
<audio
class="bg-audio-track"
data-track-index="{{ forloop.index0 }}"
data-track-name="{{ block.settings.track_name | escape }}"
data-artist="{{ block.settings.artist_name | escape }}"
preload="metadata"
{{ block.shopify_attributes }}
>
<source src="{{ block.settings.audio_url }}" type="audio/mpeg">
<source src="{{ block.settings.audio_url }}" type="audio/ogg">
您的浏览器不支持音频播放功能
</audio>
{%- endcase -%}
{%- endfor -%}
</div>
<!-- 播放器控制界面 -->
<div class="music-player-widget {{ section.settings.player_theme }} {{ section.settings.player_position }} {{ section.settings.player_size }}">
<!-- 主控制按钮 -->
<button class="player-toggle-btn" aria-label="播放/暂停背景音乐" tabindex="0">
<svg class="play-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M8 5v14l11-7z"/>
</svg>
<svg class="pause-icon" viewBox="0 0 24 24" fill="currentColor" style="display: none">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
</svg>
</button>
<!-- 扩展控制面板 -->
<div class="player-controls" style="display: none">
<!-- 音乐信息 -->
<div class="track-info">
<div class="track-name">未选择音乐</div>
<div class="artist-name"></div>
</div>
{%- if section.settings.show_progress -%}
<!-- 播放进度 -->
<div class="progress-container">
<div class="progress-bar">
<div class="progress-fill"></div>
<div class="progress-handle"></div>
</div>
<div class="time-display">
<span class="current-time">0:00</span>
<span class="total-time">0:00</span>
</div>
</div>
{%- endif -%}
<!-- 控制按钮组 -->
<div class="control-buttons">
<button class="prev-btn" aria-label="上一首" title="上一首">⏮</button>
<button class="next-btn" aria-label="下一首" title="下一首">⏭</button>
<button class="mode-btn" aria-label="播放模式" title="播放模式">🔄</button>
{%- if section.settings.show_volume_control -%}
<!-- 音量控制 -->
<div class="volume-control">
<button class="volume-btn" aria-label="音量控制" title="音量">🔊</button>
<div class="volume-slider">
<input type="range" min="0" max="100" value="{{ section.settings.default_volume }}" class="volume-range">
</div>
</div>
{%- endif -%}
</div>
</div>
<!-- 展开/收起按钮 -->
<button class="expand-btn" aria-label="展开播放器" title="展开播放器">⚙️</button>
</div>
</section>
{%- endif -%}
### CSS 样式 (添加到主题样式文件或 Section 内)
```scss
/* 背景音乐播放器样式 */
.bg-music-wrapper {
.audio-container {
position: absolute;
opacity: 0;
pointer-events: none;
}
.music-player-widget {
position: fixed;
z-index: 9999;
display: flex;
align-items: center;
gap: 8px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
/* 位置设置 */
&.bottom-left { bottom: 20px; left: 20px; }
&.bottom-right { bottom: 20px; right: 20px; }
&.top-left { top: 20px; left: 20px; }
&.top-right { top: 20px; right: 20px; }
/* 尺寸设置 */
&.small .player-toggle-btn { width: 48px; height: 48px; font-size: 16px; }
&.medium .player-toggle-btn { width: 60px; height: 60px; font-size: 20px; }
&.large .player-toggle-btn { width: 72px; height: 72px; font-size: 24px; }
/* 主题样式 */
&.dark {
.player-toggle-btn {
background: rgba(0, 0, 0, 0.8);
color: white;
border: 2px solid rgba(255, 255, 255, 0.2);
}
.player-controls {
background: rgba(0, 0, 0, 0.9);
color: white;
border: 1px solid rgba(255, 255, 255, 0.1);
}
}
&.light {
.player-toggle-btn {
background: rgba(255, 255, 255, 0.9);
color: #333;
border: 2px solid rgba(0, 0, 0, 0.1);
}
.player-controls {
background: rgba(255, 255, 255, 0.95);
color: #333;
border: 1px solid rgba(0, 0, 0, 0.1);
}
}
&.gradient {
.player-toggle-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
}
.player-controls {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
}
/* 主控制按钮 */
.player-toggle-btn {
border-radius: 50%;
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(10px);
transition: all 0.3s ease;
svg {
width: 60%;
height: 60%;
transition: all 0.2s ease;
}
&:hover, &:focus {
transform: scale(1.05);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}
&.playing {
animation: pulse 2s infinite;
}
&:focus {
outline: 2px solid #007AFF;
outline-offset: 2px;
}
}
/* 扩展控制面板 */
.player-controls {
position: absolute;
bottom: 100%;
left: 0;
margin-bottom: 12px;
padding: 16px;
border-radius: 12px;
backdrop-filter: blur(20px);
min-width: 280px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
.track-info {
margin-bottom: 12px;
.track-name {
font-weight: 600;
font-size: 14px;
margin-bottom: 2px;
}
.artist-name {
font-size: 12px;
opacity: 0.7;
}
}
.progress-container {
margin-bottom: 12px;
.progress-bar {
position: relative;
height: 4px;
background: rgba(255, 255, 255, 0.2);
border-radius: 2px;
cursor: pointer;
margin-bottom: 8px;
.progress-fill {
height: 100%;
background: #007AFF;
border-radius: 2px;
width: 0%;
transition: width 0.1s linear;
}
.progress-handle {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 12px;
height: 12px;
background: #007AFF;
border-radius: 50%;
left: 0%;
cursor: grab;
opacity: 0;
transition: opacity 0.2s ease;
}
&:hover .progress-handle {
opacity: 1;
}
}
.time-display {
display: flex;
justify-content: space-between;
font-size: 11px;
opacity: 0.7;
}
}
.control-buttons {
display: flex;
align-items: center;
gap: 12px;
button {
background: rgba(255, 255, 255, 0.1);
border: none;
border-radius: 6px;
padding: 8px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s ease;
&:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-1px);
}
}
.volume-control {
display: flex;
align-items: center;
gap: 8px;
.volume-slider {
width: 60px;
.volume-range {
width: 100%;
height: 4px;
border-radius: 2px;
background: rgba(255, 255, 255, 0.2);
outline: none;
cursor: pointer;
&::-webkit-slider-thumb {
appearance: none;
width: 12px;
height: 12px;
border-radius: 50%;
background: #007AFF;
cursor: pointer;
}
}
}
}
}
}
.expand-btn {
background: rgba(255, 255, 255, 0.1);
border: none;
border-radius: 50%;
width: 32px;
height: 32px;
cursor: pointer;
font-size: 12px;
transition: all 0.2s ease;
&:hover {
background: rgba(255, 255, 255, 0.2);
transform: scale(1.1);
}
}
}
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(0, 123, 255, 0.5); }
70% { box-shadow: 0 0 0 15px rgba(0, 123, 255, 0); }
100% { box-shadow: 0 0 0 0 rgba(0, 123, 255, 0); }
}
/* 响应式设计 */
@media (max-width: 768px) {
.bg-music-wrapper .music-player-widget {
&.small .player-toggle-btn { width: 44px; height: 44px; }
&.medium .player-toggle-btn { width: 52px; height: 52px; }
&.large .player-toggle-btn { width: 60px; height: 60px; }
.player-controls {
min-width: 260px;
bottom: auto;
top: 100%;
margin-top: 12px;
margin-bottom: 0;
}
}
}
JavaScript 功能实现
class ShopifyMusicPlayer {
constructor(sectionElement) {
this.section = sectionElement
this.audioTracks = [...this.section.querySelectorAll('.bg-audio-track')]
this.currentTrackIndex = 0
this.currentAudio = null
this.isPlaying = false
this.isExpanded = false
this.playMode = this.section.dataset.playMode || 'loop'
this.autoPlay = this.section.dataset.autoPlay === 'true'
this.defaultVolume = parseInt(this.section.dataset.defaultVolume) / 100 || 0.5
this.initializeElements()
this.initializeEvents()
this.loadTrack(0)
this.updatePlayModeButton()
if (this.autoPlay) {
this.handleFirstInteraction()
}
}
initializeElements() {
this.widget = this.section.querySelector('.music-player-widget')
this.toggleBtn = this.section.querySelector('.player-toggle-btn')
this.expandBtn = this.section.querySelector('.expand-btn')
this.controls = this.section.querySelector('.player-controls')
this.trackName = this.section.querySelector('.track-name')
this.artistName = this.section.querySelector('.artist-name')
this.progressBar = this.section.querySelector('.progress-bar')
this.progressFill = this.section.querySelector('.progress-fill')
this.progressHandle = this.section.querySelector('.progress-handle')
this.currentTimeDisplay = this.section.querySelector('.current-time')
this.totalTimeDisplay = this.section.querySelector('.total-time')
this.prevBtn = this.section.querySelector('.prev-btn')
this.nextBtn = this.section.querySelector('.next-btn')
this.modeBtn = this.section.querySelector('.mode-btn')
this.volumeBtn = this.section.querySelector('.volume-btn')
this.volumeRange = this.section.querySelector('.volume-range')
this.playIcon = this.section.querySelector('.play-icon')
this.pauseIcon = this.section.querySelector('.pause-icon')
}
initializeEvents() {
// 主控制按钮
this.toggleBtn?.addEventListener('click', () => this.togglePlay())
this.toggleBtn?.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
this.togglePlay()
}
})
// 展开按钮
this.expandBtn?.addEventListener('click', () => this.toggleExpand())
// 控制按钮
this.prevBtn?.addEventListener('click', () => this.previousTrack())
this.nextBtn?.addEventListener('click', () => this.nextTrack())
this.modeBtn?.addEventListener('click', () => this.cyclePlayMode())
// 音量控制
this.volumeBtn?.addEventListener('click', () => this.toggleMute())
this.volumeRange?.addEventListener('input', (e) => this.setVolume(e.target.value / 100))
// 进度条控制
this.progressBar?.addEventListener('click', (e) => this.seekTo(e))
// 首次交互处理
document.addEventListener('click', () => this.handleFirstInteraction(), { once: true })
// 键盘快捷键
document.addEventListener('keydown', (e) => this.handleKeyboard(e))
}
loadTrack(index) {
if (index < 0 || index >= this.audioTracks.length) return
if (this.currentAudio) {
this.currentAudio.pause()
this.currentAudio.removeEventListener('loadedmetadata', this.onLoadedMetadata)
this.currentAudio.removeEventListener('timeupdate', this.onTimeUpdate)
this.currentAudio.removeEventListener('ended', this.onTrackEnded)
}
this.currentTrackIndex = index
this.currentAudio = this.audioTracks[index]
if (!this.currentAudio) return
// 更新音乐信息
const trackName = this.currentAudio.dataset.trackName || '未知音乐'
const artistName = this.currentAudio.dataset.artist || '未知艺术家'
if (this.trackName) this.trackName.textContent = trackName
if (this.artistName) this.artistName.textContent = artistName
// 设置音量
this.currentAudio.volume = this.defaultVolume
if (this.volumeRange) this.volumeRange.value = this.defaultVolume * 100
// 绑定事件
this.onLoadedMetadata = () => this.updateDuration()
this.onTimeUpdate = () => this.updateProgress()
this.onTrackEnded = () => this.handleTrackEnd()
this.currentAudio.addEventListener('loadedmetadata', this.onLoadedMetadata)
this.currentAudio.addEventListener('timeupdate', this.onTimeUpdate)
this.currentAudio.addEventListener('ended', this.onTrackEnded)
}
togglePlay() {
if (!this.currentAudio) return
if (this.isPlaying) {
this.pause()
} else {
this.play()
}
}
async play() {
if (!this.currentAudio) return
try {
await this.currentAudio.play()
this.isPlaying = true
this.updatePlayButton()
this.toggleBtn?.classList.add('playing')
} catch (error) {
console.error('播放失败:', error)
}
}
pause() {
if (!this.currentAudio) return
this.currentAudio.pause()
this.isPlaying = false
this.updatePlayButton()
this.toggleBtn?.classList.remove('playing')
}
updatePlayButton() {
if (this.playIcon && this.pauseIcon) {
this.playIcon.style.display = this.isPlaying ? 'none' : 'block'
this.pauseIcon.style.display = this.isPlaying ? 'block' : 'none'
}
}
previousTrack() {
let newIndex = this.currentTrackIndex - 1
if (newIndex < 0) {
newIndex = this.audioTracks.length - 1
}
this.loadTrack(newIndex)
if (this.isPlaying) this.play()
}
nextTrack() {
let newIndex
if (this.playMode === 'random') {
newIndex = Math.floor(Math.random() * this.audioTracks.length)
} else {
newIndex = this.currentTrackIndex + 1
if (newIndex >= this.audioTracks.length) {
newIndex = 0
}
}
this.loadTrack(newIndex)
if (this.isPlaying) this.play()
}
cyclePlayMode() {
const modes = ['loop', 'random', 'single', 'once']
const currentIndex = modes.indexOf(this.playMode)
this.playMode = modes[(currentIndex + 1) % modes.length]
this.updatePlayModeButton()
// 保存用户偏好
localStorage.setItem('musicPlayerMode', this.playMode)
}
updatePlayModeButton() {
if (!this.modeBtn) return
const modeIcons = {
loop: '🔄',
random: '🔀',
single: '🔂',
once: '➡️'
}
this.modeBtn.textContent = modeIcons[this.playMode] || '🔄'
this.modeBtn.title = `播放模式: ${this.playMode}`
}
handleTrackEnd() {
switch (this.playMode) {
case 'single':
this.currentAudio.currentTime = 0
this.play()
break
case 'once':
this.pause()
break
case 'loop':
case 'random':
default:
this.nextTrack()
break
}
}
setVolume(volume) {
if (this.currentAudio) {
this.currentAudio.volume = Math.max(0, Math.min(1, volume))
}
this.updateVolumeButton()
}
toggleMute() {
if (!this.currentAudio) return
if (this.currentAudio.volume > 0) {
this.previousVolume = this.currentAudio.volume
this.setVolume(0)
if (this.volumeRange) this.volumeRange.value = 0
} else {
const restoreVolume = this.previousVolume || this.defaultVolume
this.setVolume(restoreVolume)
if (this.volumeRange) this.volumeRange.value = restoreVolume * 100
}
}
updateVolumeButton() {
if (!this.volumeBtn || !this.currentAudio) return
const volume = this.currentAudio.volume
let icon = '🔊'
if (volume === 0) icon = '🔇'
else if (volume < 0.3) icon = '🔈'
else if (volume < 0.7) icon = '🔉'
this.volumeBtn.textContent = icon
}
updateProgress() {
if (!this.currentAudio || !this.progressFill) return
const progress = this.currentAudio.currentTime / this.currentAudio.duration
this.progressFill.style.width = `${progress * 100}%`
if (this.progressHandle) {
this.progressHandle.style.left = `${progress * 100}%`
}
if (this.currentTimeDisplay) {
this.currentTimeDisplay.textContent = this.formatTime(this.currentAudio.currentTime)
}
}
updateDuration() {
if (!this.currentAudio || !this.totalTimeDisplay) return
this.totalTimeDisplay.textContent = this.formatTime(this.currentAudio.duration)
}
seekTo(event) {
if (!this.currentAudio || !this.progressBar) return
const rect = this.progressBar.getBoundingClientRect()
const clickX = event.clientX - rect.left
const progress = clickX / rect.width
this.currentAudio.currentTime = progress * this.currentAudio.duration
}
formatTime(seconds) {
if (isNaN(seconds)) return '0:00'
const mins = Math.floor(seconds / 60)
const secs = Math.floor(seconds % 60)
return `${mins}:${secs.toString().padStart(2, '0')}`
}
toggleExpand() {
this.isExpanded = !this.isExpanded
if (this.controls) {
this.controls.style.display = this.isExpanded ? 'block' : 'none'
}
if (this.expandBtn) {
this.expandBtn.textContent = this.isExpanded ? '✕' : '⚙️'
this.expandBtn.setAttribute('aria-label', this.isExpanded ? '收起播放器' : '展开播放器')
}
}
handleFirstInteraction() {
if (this.autoPlay && !this.isPlaying) {
this.play()
}
}
handleKeyboard(event) {
// 只在非输入元素上响应快捷键
if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') return
switch (event.code) {
case 'Space':
if (event.ctrlKey) {
event.preventDefault()
this.togglePlay()
}
break
case 'ArrowLeft':
if (event.ctrlKey) {
event.preventDefault()
this.previousTrack()
}
break
case 'ArrowRight':
if (event.ctrlKey) {
event.preventDefault()
this.nextTrack()
}
break
}
}
}
// 初始化播放器
document.addEventListener('DOMContentLoaded', () => {
const musicSection = document.getElementById('bg-music-section')
if (musicSection) {
new ShopifyMusicPlayer(musicSection)
}
})
集成到Shopify主题的完整步骤
方法一:作为Section使用(推荐用于特定页面)
1. 创建Section文件
在主题的 sections/
目录下创建 bg-music.liquid
文件,将上述完整代码复制进去
2. 在主题中引用
在需要显示音乐播放器的模板中添加:
<!-- 在 theme.liquid 的 body 结束标签前 -->
{% section 'bg-music' %}
<!-- 或在特定页面模板中 -->
{% section 'bg-music' %}
3. 后台配置
- 进入主题定制器
- 添加”背景音乐播放器”Section
- 配置播放器设置(主题、位置、音量等)
- 添加音乐曲目Block,设置音乐信息和文件链接
方法二:集成到模板设置中(推荐用于全站)
如果你希望在整个网站中都能使用背景音乐播放器,可以将其直接集成到主题设置中。
1. 修改 settings_schema.json
在主题根目录的 config/settings_schema.json
文件中添加以下配置:
{
"name": "背景音乐设置",
"settings": [
{
"type": "header",
"content": "背景音乐播放器"
},
{
"type": "checkbox",
"id": "enable_background_music",
"label": "启用背景音乐",
"default": false,
"info": "在整个网站中启用背景音乐播放器"
},
{
"type": "checkbox",
"id": "music_auto_play",
"label": "自动播放",
"default": false,
"info": "受浏览器政策限制,需要用户首次交互后才能播放"
},
{
"type": "select",
"id": "music_play_mode",
"label": "播放模式",
"default": "loop",
"options": [
{ "value": "loop", "label": "循环播放" },
{ "value": "random", "label": "随机播放" },
{ "value": "single", "label": "单曲循环" },
{ "value": "once", "label": "播放一次" }
]
},
{
"type": "range",
"id": "music_default_volume",
"label": "默认音量",
"min": 0,
"max": 100,
"step": 5,
"unit": "%",
"default": 50
},
{
"type": "select",
"id": "music_player_theme",
"label": "播放器主题",
"default": "dark",
"options": [
{ "value": "dark", "label": "深色主题" },
{ "value": "light", "label": "浅色主题" },
{ "value": "gradient", "label": "渐变主题" },
{ "value": "brand", "label": "品牌色主题" }
]
},
{
"type": "select",
"id": "music_player_position",
"label": "播放器位置",
"default": "bottom-left",
"options": [
{ "value": "bottom-left", "label": "左下角" },
{ "value": "bottom-right", "label": "右下角" },
{ "value": "top-left", "label": "左上角" },
{ "value": "top-right", "label": "右上角" }
]
},
{
"type": "select",
"id": "music_player_size",
"label": "播放器大小",
"default": "medium",
"options": [
{ "value": "small", "label": "小" },
{ "value": "medium", "label": "中" },
{ "value": "large", "label": "大" }
]
},
{
"type": "checkbox",
"id": "music_show_progress",
"label": "显示播放进度",
"default": true
},
{
"type": "checkbox",
"id": "music_show_volume_control",
"label": "显示音量控制",
"default": true
},
{
"type": "header",
"content": "音乐列表"
},
{
"type": "text",
"id": "music_track_1_name",
"label": "音乐1 - 曲目名称",
"placeholder": "例如:品牌主题曲"
},
{
"type": "text",
"id": "music_track_1_artist",
"label": "音乐1 - 艺术家",
"placeholder": "例如:音乐制作人"
},
{
"type": "url",
"id": "music_track_1_url",
"label": "音乐1 - 文件链接",
"info": "支持 MP3、OGG、AAC 格式"
},
{
"type": "text",
"id": "music_track_2_name",
"label": "音乐2 - 曲目名称(可选)"
},
{
"type": "text",
"id": "music_track_2_artist",
"label": "音乐2 - 艺术家(可选)"
},
{
"type": "url",
"id": "music_track_2_url",
"label": "音乐2 - 文件链接(可选)"
},
{
"type": "text",
"id": "music_track_3_name",
"label": "音乐3 - 曲目名称(可选)"
},
{
"type": "text",
"id": "music_track_3_artist",
"label": "音乐3 - 艺术家(可选)"
},
{
"type": "url",
"id": "music_track_3_url",
"label": "音乐3 - 文件链接(可选)"
}
]
}
2. 在 theme.liquid 中集成播放器
在 layout/theme.liquid
文件的 </body>
标签前添加:
{%- if settings.enable_background_music -%}
{%- assign music_tracks = '' -%}
{%- if settings.music_track_1_url != blank -%}
{%- assign music_tracks = music_tracks | append: settings.music_track_1_url | append: '|' | append: settings.music_track_1_name | append: '|' | append: settings.music_track_1_artist | append: '||' -%}
{%- endif -%}
{%- if settings.music_track_2_url != blank -%}
{%- assign music_tracks = music_tracks | append: settings.music_track_2_url | append: '|' | append: settings.music_track_2_name | append: '|' | append: settings.music_track_2_artist | append: '||' -%}
{%- endif -%}
{%- if settings.music_track_3_url != blank -%}
{%- assign music_tracks = music_tracks | append: settings.music_track_3_url | append: '|' | append: settings.music_track_3_name | append: '|' | append: settings.music_track_3_artist | append: '||' -%}
{%- endif -%}
{%- if music_tracks != blank -%}
<section
id="bg-music-section"
class="bg-music-wrapper"
data-auto-play="{{ settings.music_auto_play }}"
data-play-mode="{{ settings.music_play_mode }}"
data-default-volume="{{ settings.music_default_volume }}"
data-theme="{{ settings.music_player_theme }}"
data-position="{{ settings.music_player_position }}"
data-size="{{ settings.music_player_size }}"
data-tracks="{{ music_tracks | remove: '||' | split: '||' | join: ',' }}"
>
<!-- 音频播放器(隐藏的原生播放器) -->
<div class="audio-container">
{%- assign tracks_array = music_tracks | remove: '||' | split: '||' -%}
{%- for track_data in tracks_array -%}
{%- assign track_parts = track_data | split: '|' -%}
{%- if track_parts[0] != blank -%}
<audio
class="bg-audio-track"
data-track-index="{{ forloop.index0 }}"
data-track-name="{{ track_parts[1] | default: '未知音乐' | escape }}"
data-artist="{{ track_parts[2] | default: '未知艺术家' | escape }}"
preload="metadata"
>
<source src="{{ track_parts[0] }}" type="audio/mpeg">
<source src="{{ track_parts[0] }}" type="audio/ogg">
您的浏览器不支持音频播放功能
</audio>
{%- endif -%}
{%- endfor -%}
</div>
<!-- 播放器控制界面 -->
<div class="music-player-widget {{ settings.music_player_theme }} {{ settings.music_player_position }} {{ settings.music_player_size }}">
<!-- 主控制按钮 -->
<button class="player-toggle-btn" aria-label="播放/暂停背景音乐" tabindex="0">
<svg class="play-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M8 5v14l11-7z"/>
</svg>
<svg class="pause-icon" viewBox="0 0 24 24" fill="currentColor" style="display: none">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
</svg>
</button>
<!-- 扩展控制面板 -->
<div class="player-controls" style="display: none">
<!-- 音乐信息 -->
<div class="track-info">
<div class="track-name">未选择音乐</div>
<div class="artist-name"></div>
</div>
{%- if settings.music_show_progress -%}
<!-- 播放进度 -->
<div class="progress-container">
<div class="progress-bar">
<div class="progress-fill"></div>
<div class="progress-handle"></div>
</div>
<div class="time-display">
<span class="current-time">0:00</span>
<span class="total-time">0:00</span>
</div>
</div>
{%- endif -%}
<!-- 控制按钮组 -->
<div class="control-buttons">
<button class="prev-btn" aria-label="上一首" title="上一首">⏮</button>
<button class="next-btn" aria-label="下一首" title="下一首">⏭</button>
<button class="mode-btn" aria-label="播放模式" title="播放模式">🔄</button>
{%- if settings.music_show_volume_control -%}
<!-- 音量控制 -->
<div class="volume-control">
<button class="volume-btn" aria-label="音量控制" title="音量">🔊</button>
<div class="volume-slider">
<input type="range" min="0" max="100" value="{{ settings.music_default_volume }}" class="volume-range">
</div>
</div>
{%- endif -%}
</div>
</div>
<!-- 展开/收起按钮 -->
<button class="expand-btn" aria-label="展开播放器" title="展开播放器">⚙️</button>
</div>
</section>
<!-- 添加样式和脚本 -->
<style>
/* 这里放入之前的 CSS 样式代码 */
</style>
<script>
/* 这里放入之前的 JavaScript 代码 */
</script>
{%- endif -%}
{%- endif -%}
3. 后台配置步骤
- 进入 Shopify 后台
- 前往”在线商店” → “主题”
- 点击”自定义”
- 在主题设置中找到”背景音乐设置”部分
- 启用背景音乐并配置相关设置
- 添加音乐文件链接和信息
- 保存设置
4. 上传音乐文件
- 将音乐文件上传到 Shopify 后台的”文件”部分
- 复制文件URL用于主题设置配置
- 建议使用MP3格式,文件大小控制在5MB以内
高级功能与最佳实践
性能优化
- 懒加载:音频文件仅在需要时加载,使用
preload="metadata"
- 文件压缩:建议音乐文件压缩至合适的比特率(128-192kbps)
- 缓存策略:利用浏览器缓存,避免重复下载
用户体验优化
- 记住偏好:使用 localStorage 保存用户的音量、播放模式设置
- 自动播放策略:遵循浏览器自动播放政策,提供友好的播放提示
- 无障碍支持:完整的键盘导航和屏幕阅读器支持
故障排除
常见问题解决
-
音乐无法自动播放
- 检查浏览器自动播放政策
- 确保用户已有交互行为
-
音频文件加载失败
- 验证文件URL是否正确
- 检查文件格式兼容性
-
样式显示异常
- 检查CSS样式是否被主题样式覆盖
- 验证响应式断点设置
-
性能问题
- 减少音频文件大小
- 优化播放器初始化时机
扩展功能建议
- 播放列表管理:支持用户自定义播放列表
- 音效可视化:添加音频频谱动画
- 社交分享:分享正在播放的音乐
- AI推荐:根据用户行为推荐音乐
通过这个完整的背景音乐播放器,你可以为Shopify店铺创造独特的品牌氛围,提升用户体验和品牌记忆度。
最后更新时间: