|
|
请马上登录,朋友们都在花潮里等着你哦:)
您需要 登录 才可以下载或查看,没有账号?立即注册
x
- /** audioplayer.js(2026年5月5日更新)
- 在指定父元素生成播放器+全屏按钮,
- 支持添加多个自定义音频控制按钮,
- 支持热键操作(F11、Alt+X/N/P/L)
- 1. 前台配置:
- let option = {
- pa: '.pa'; // 或者 '#pa' | pa
- urls: [
- ['歌曲地址1', '曲名1'],
- ['歌曲地址2', '曲名2'],
- ],
- fs: false, // 禁用全屏按钮,缺省值 true(启用)
- btns: [dom1, dom2, dom2], // 自定义播放控制器(若需要)
- }
- 2. 实例化举例:const aud = new AudPlayer(option);
- 3. 前台CSS:
- ① 播 放 器: .player { width: 420px; bottom: 10px; right: 20px; color: gold; }
- ② 全屏按钮: .btnFs { top: 20px; right: 20px; color: gold; }
- */
- class AudPlayer {
- constructor(config = {}) {
- // 基础配置
- this.config = {
- pa: config.pa || document.body,
- urls: config.urls || [],
- fs: true,
- btns: config.btns,
- };
- // 关键DOM+核心状态
- this.pa = this.getParentElement();
- this.aud = new Audio();
- this.fs_btn = null;
- this.playList = [...this.config.urls]; // 原始歌单
- this.randomQueue = []; // 随机播放队列
- this.currentIndex = 0; // 当前播放索引
- this.isPlaying = false;
- this.isSingle = this.playList.length === 1;
- // 初始化
- this.generateUI();
- this.initRandomQueue();
- this.placeMList();
- this.displayPlayer();
- this.bindAudEvents();
- this.playFirst();
- }
- // 加载+播放曲目
- loadTrack(index) {
- if (index < 0 || index >= this.playList.length) return;
- this.currentIndex = index;
- const [url, title] = this.playList[index];
- this.aud.src = url;
- this.aud.play().catch(err => this.showError('自动播放受限,请点击播放按钮'));
- // 歌单高亮+翻页
- if (!this.isSingle) {
- this.mlist.dataset.currentsong = '正在播放 :' + title;
- const lists = this.mlist.querySelectorAll('li');
- const curList = this.mlist.querySelector(`li[data-idx="${index}"]`);
- lists.forEach(li => li.classList.remove('list-highlight'));
- curList.classList.add('list-highlight');
- curList.scrollIntoView({ behavior: 'smooth'});
- console.log(this.mlist.scrollHeight, curList.offsetTop)
- }
- this.mState();
- }
- // 首次播放
- playFirst() {
- const idx = Math.floor(Math.random() * this.playList.length);
- this.loadTrack(idx);
- }
- // 手动选曲(不影响随机队列)
- selectTrack(index) {
- this.loadTrack(index);
- }
- // 上一首
- playPrev() {
- if (this.isSingle) return;
- let prevIndex = this.currentIndex - 1;
- if (prevIndex < 0) prevIndex = this.playList.length - 1;
- this.loadTrack(prevIndex);
- }
- // 下一首
- playNext() {
- if (this.isSingle) return;
- let nextIndex = this.currentIndex + 1;
- if (nextIndex >= this.playList.length) nextIndex = 0;
- this.loadTrack(nextIndex);
- }
- // 切换播放/暂停
- togglePlay() {
- if (this.isPlaying) {
- this.aud.pause();
- } else {
- this.aud.play().catch(err => this.showError('播放失败,请检查音频链接'));
- }
- }
- // 按钮、视频等状态维护
- mState() {
- const vids = this.pa.querySelectorAll('video');
- if (this.aud.paused) {
- this.playbtn.classList.remove('clip-pause');
- this.playbtn.classList.add('clip-play');
- this.pa.style.setProperty('--state', 'paused');
- if (vids) vids.forEach(vid => vid.pause());
- } else {
- this.playbtn.classList.remove('clip-play');
- this.playbtn.classList.add('clip-pause');
- this.pa.style.setProperty('--state', 'running');
- if (vids) vids.forEach(vid => vid.play());
- }
- }
- // 播放结束处理
- handlePlayEnd() {
- if (this.isSingle) {
- // 单曲循环
- this.aud.currentTime = 0;
- this.aud.play();
- } else {
- // 多曲:从随机队列取歌
- if (this.randomQueue.length === 0) {
- this.resetRandomQueue(); // 周期结束,重置随机队列
- }
- const nextTrack = this.randomQueue.shift();
- const nextIndex = this.playList.findIndex(item => item[0] === nextTrack[0]);
- this.loadTrack(nextIndex);
- }
- }
- // 初始化随机播放队列
- initRandomQueue() {
- if (this.isSingle) return;
- this.randomQueue = [...this.playList].sort(() => Math.random() - 0.5);
- }
- // 重置随机队列(一个周期结束后)
- resetRandomQueue() {
- this.initRandomQueue();
- }
- // 音频事件绑定
- bindAudEvents() {
- // 时间更新
- this.aud.addEventListener('timeupdate', () => {
- const { currentTime, duration } = this.aud;
- this.prog.style.setProperty('--prog', `${currentTime / duration * 100}%`);
- this.tmsg.textContent = `${this.s2m(currentTime)} / ${this.s2m(duration)}`;
- });
- // 播放结束
- this.aud.addEventListener('ended', () => {
- this.handlePlayEnd();
- });
- // 播放/暂停状态同步
- this.aud.addEventListener('play', () => {
- this.isPlaying = true;
- this.mState();
- });
- // 暂停
- this.aud.addEventListener('pause', () => {
- this.isPlaying = false;
- this.mState();
- });
- // 出错
- this.aud.addEventListener('error', (e) => {
- this.showError(`播放失败:${this.playList[this.currentIndex][1]}`);
- this.handlePlayEnd();
- });
- }
- // 创建UI
- generateUI() {
- if (document.querySelector('#audio-player-style')) return;
- const style = document.createElement('style');
- style.id = 'audio-player-style';
- style.textContent = [
- `.player { position: absolute; padding: 6px; width: 460px; height: 40px; line-height: 40px; display: flex; align-items: center; gap: 10px; transition: .75s; opacity: var(--opacity); }`,
- `.player * { box-sizing: border-box; }`,
- `.aud-btn { width: 35px; height: 35px; border: 1px solid currentColor; border-radius: 50%; cursor: pointer; position: relative; display: grid; place-items: center; }`,
- `.aud-btn:hover { background: rgba(0,0,0,.25); }`,
- `.aud-btn::before { content: ''; position: absolute; width: 50%; height: 50%; background: currentColor; clip-path: var(--clip-path); }`,
- `.aud-prog { flex-grow: 1; height: 12px; background: linear-gradient(to right, currentColor var(--prog), transparent var(--prog), transparent 0); border: 1px solid currentColor; border-radius: 12px; cursor: pointer; --prog: 0%; }`,
- `.common-btn { width: 26px; height: 26px; border: 1px solid currentColor; border-radius: 6px; padding: 0; font: normal 16px/26px sans-serif; text-align: center; user-select: none; cursor: pointer; }`,
- `.common-btn:hover { background: rgba(0,0,0,.25); }`,
- `.music-list { position: absolute; left: 50%; transform: translateX(-50%); width: 100%; max-width: 460px; min-height: 100%; height: 232px; border-radius: 6px; background: rgba(0,0,0,.25); box-shadow: 3px 3px 6px gray; display: none; }`,
- `.music-list::before { position: sticky; content: attr(data-currentsong); font-weight: bold; padding: 5px 15px;}`,
- `.music-list ol { height: 160px; overflow: auto; scrollbar-width: thin; scrollbar-color: currentColor transparent; }`,
- `.music-list ol li span { cursor: pointer; }`,
- `.music-list ol li span:hover { opacity: .75; }`,
- `.aud-tmsg { user-select: none; cursor: default; }`,
- `.clip-play { --clip-path: polygon(0 0, 0 100%, 100% 50%);}`,
- `.clip-pause { --clip-path: polygon(45% 0, 45% 100%, 10% 100%, 10% 0, 90% 0, 90% 100%, 55% 100%, 55% 0); }`,
- `.list-highlight { color: red; }`,
- `.btnFs { position: absolute; padding: 6px 12px; border: 3px solid currentColor; border-radius: 12px; font-size: 1.2em; color: currentColor; background: rgba(0,0,0,.25); transition: .75s; opacity: var(--opacity); user-select: none; cursor: pointer; }`,
- `.btnFs:hover { font-weight: bold; }`,
- ].join('');
- document.head.appendChild(style);
- // 播放器容器
- this.player = document.createElement('div');
- this.player.classList.add('player');
- // 前一首按钮
- if (!this.isSingle) {
- const btnPrev = document.createElement('div');
- btnPrev.classList.add('common-btn');
- btnPrev.textContent = '←';
- btnPrev.title = '前一首(Alt+P)';
- btnPrev.addEventListener('click', () => this.playPrev());
- this.player.appendChild(btnPrev);
- }
- // 播放|暂停按钮
- this.playbtn = document.createElement('div');
- this.playbtn.classList.add('aud-btn', 'clip-pause');
- this.playbtn.title = '播放/暂停(Alt+X)';
- this.playbtn.addEventListener('click', () => this.togglePlay());
- this.player.appendChild(this.playbtn);
- // 下一首按钮
- if (!this.isSingle) {
- const btnNext = document.createElement('div');
- btnNext.classList.add('common-btn');
- btnNext.textContent = '→';
- btnNext.title = '下一首(Alt+N)';
- btnNext.addEventListener('click', () => this.playNext());
- this.player.appendChild(btnNext);
- }
- // 进度条
- this.prog = document.createElement('div');
- this.prog.classList.add('aud-prog');
- this.prog.addEventListener('click', (e) => {
- const duration = this.aud.duration;
- if (isNaN(duration)) return;
- this.aud.currentTime = duration * e.offsetX / this.prog.offsetWidth;
- });
- this.prog.addEventListener('mousemove', (e) => {
- const duration = this.aud.duration;
- this.prog.title = this.s2m(duration * e.offsetX / this.prog.offsetWidth);
- });
- this.player.appendChild(this.prog);
- // 数字时间
- this.tmsg = document.createElement('div');
- this.tmsg.classList.add('aud-tmsg');
- this.tmsg.textContent = '00:00 / 00:00';
- this.player.appendChild(this.tmsg);
- // 列表控制按钮
- if (!this.isSingle) {
- this.listControl = document.createElement('div');
- this.listControl.classList.add('common-btn');
- this.listControl.textContent = '▼';
- this.listControl.title = '音乐列表(Alt+L)';
- // 列表弹出/收起+按钮箭头变换
- this.listControl.addEventListener('click', () => {
- let hide = this.mlist.style.display === 'block';
- this.mlist.style.display = hide ? 'none' : 'block';
- this.listControl.textContent = this.listControl.textContent === '▲' ? '▼' : '▲';
- if (!hide) {
- this.mlist.querySelector(`li[data-idx="${this.currentIndex}"]`).scrollIntoView({behavior: 'smooth'});
- }
- });
- this.player.appendChild(this.listControl);
- // 音乐列表
- this.mlist = document.createElement('div');
- this.mlist.classList.add('music-list');
- this.generateMusicList();
- this.player.appendChild(this.mlist);
- }
- // 全屏按钮
- if (this.config.fs) {
- this.fs_btn = document.createElement('div');
- this.fs_btn.classList.add('btnFs');
- this.fullScreen(this.fs_btn);
- this.pa.appendChild(this.fs_btn);
- }
- this.pa.appendChild(this.player);
- // 自定义添加的播放按钮(数组doms传参)
- if (this.config.btns) {
- this.config.btns.forEach(btn => {
- btn.title = '播放/暂停(Alt+X)';
- btn.addEventListener('click', () => {
- this.togglePlay();
- });
- });
- }
- // 热键
- document.addEventListener('keydown', (e) => {
- if(e.altKey) {
- if (e.key === 'x') this.togglePlay();
- if (e.key === 'p') this.playPrev();
- if (e.key === 'n') this.playNext();
- if (e.key === 'l') this.listControl.click();
- }
- });
- }
- // 列表定位+控制按钮状态
- placeMList() {
- if (this.isSingle) return;
- const style = window.getComputedStyle(this.player);
- const up = parseInt(style.getPropertyValue('bottom')) >= parseInt(style.getPropertyValue('top'));
- const ar = ['▲','▼' ];
- this.listControl.textContent = ar[+up];
- this.mlist.style.setProperty(`${up ? 'top' : 'bottom'}`, '100%');
- }
- // 生成列表
- generateMusicList() {
- const ol = document.createElement('ol');
- this.playList.forEach((list, idx) => {
- const li = document.createElement('li');
- li.innerHTML = `<span>${list[1]}</span>`;
- li.dataset.idx = idx;
- li.onclick = () => {
- this.selectTrack(idx);
- }
- ol.appendChild(li);
- });
- this.mlist.appendChild(ol);
- }
- // 全屏
- fullScreen = (btn) => {
- let isFullscreen = false;
- btn.textContent = '进入全屏';
- btn.title = 'F11';
- btn.addEventListener('click', () => {
- isFullscreen ? document.exitFullscreen() : this.pa.requestFullscreen();
- });
- document.addEventListener('fullscreenchange', () => {
- if (document.fullscreenElement !== null) {
- isFullscreen = true;
- btn.textContent = '退出全屏';
- } else {
- isFullscreen = false;
- btn.textContent = '进入全屏';
- }
- });
- document.addEventListener('keydown', (e) => {
- if (e.key === 'F11') {
- e.preventDefault();
- isFullscreen ? document.exitFullscreen() : this.pa.requestFullscreen();
- }
- });
- };
- // 播放器+全屏隐身现身
- displayPlayer() {
- let timerId;
- this.pa.addEventListener('mousemove', () => {
- clearTimeout(timerId);
- this.pa.style.setProperty('--opacity', '1');
- timerId = setTimeout(() => this.pa.style.setProperty('--opacity', '0'), 3000);
- });
- }
- // 获取元素(支持 id/class/元素实体)
- getParentElement() {
- const pa = this.config.pa;
- if (pa instanceof HTMLElement) return pa;
- return document.querySelector(pa) || document.body;
- }
- // 错误处理
- showError(msg) {
- this.mlist.dataset.currentsong = msg;
- }
- // 时间格式化
- s2m(seconds) {
- const min = Math.floor(seconds / 60).toString().padStart(2, '0');
- const sec = Math.floor(seconds % 60).toString().padStart(2, '0');
- return `${min}:${sec}`;
- }
- }
复制代码 |
评分
-
| 参与人数 1 | 威望 +50 |
金钱 +100 |
经验 +50 |
收起
理由
|
红影
| + 50 |
+ 100 |
+ 50 |
匠心独运,细节精致入微! |
查看全部评分
|