音乐播放器-单html文件

html

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>音乐播放器 - 自定义字体与阴影</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            overflow: hidden;
            background: #000;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            color: white;
        }
        
        .container {
            position: relative;
            width: 100%;
            height: 100vh;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            padding: 2rem;
            background: #000;
        }
        
        .song-title-container {
            text-align: center;
            margin-top: 2rem;
            z-index: 2;
        }
        
        .song-title {
            font-size: 5rem;
            font-weight: bold;
            color: white;
            margin-bottom: 1rem;
            transition: all 0.5s ease;
            line-height: 1.1;
        }
        
        .artist-name {
            font-size: 1.5rem;
            color: rgba(255, 255, 255, 0.7);
            margin-bottom: 2rem;
        }
        
        .controls {
            display: flex;
            justify-content: center;
            gap: 1.5rem;
            margin-top: 2rem;
            flex-wrap: wrap;
            z-index: 2;
        }
        
        button {
            padding: 0.8rem 1.5rem;
            border: none;
            border-radius: 50px;
            background: rgba(255, 255, 255, 0.2);
            color: white;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            backdrop-filter: blur(5px);
            display: flex;
            align-items: center;
            gap: 0.5rem;
        }
        
        button:hover {
            background: rgba(255, 255, 255, 0.3);
            transform: translateY(-3px);
        }
        
        .file-input-container {
            position: relative;
            overflow: hidden;
            display: inline-block;
        }
        
        .file-input-container input[type="file"] {
            position: absolute;
            left: 0;
            top: 0;
            opacity: 0;
            width: 100%;
            height: 100%;
            cursor: pointer;
        }
        
        .customization-panel {
            position: absolute;
            top: 20px;
            right: 20px;
            background: rgba(0, 0, 0, 0.7);
            padding: 1.5rem;
            border-radius: 15px;
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.1);
            z-index: 3;
            width: 300px;
        }
        
        .customization-panel h3 {
            margin-bottom: 1rem;
            font-size: 1.2rem;
            color: white;
            border-bottom: 1px solid rgba(255, 255, 255, 0.2);
            padding-bottom: 0.5rem;
        }
        
        .form-group {
            margin-bottom: 1rem;
        }
        
        .form-group label {
            display: block;
            margin-bottom: 0.5rem;
            font-size: 0.9rem;
            color: rgba(255, 255, 255, 0.8);
        }
        
        .form-control {
            width: 100%;
            padding: 0.5rem;
            border-radius: 5px;
            border: 1px solid rgba(255, 255, 255, 0.2);
            background: rgba(255, 255, 255, 0.1);
            color: white;
        }
        
        .color-input-container {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .color-input {
            width: 40px;
            height: 40px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            background: transparent;
        }
        
        .color-input::-webkit-color-swatch {
            border-radius: 5px;
            border: none;
        }
        
        .color-input::-moz-color-swatch {
            border-radius: 5px;
            border: none;
        }
        
        .progress-container {
            width: 100%;
            height: 6px;
            background: rgba(255, 255, 255, 0.2);
            border-radius: 3px;
            overflow: hidden;
            margin: 2rem 0;
        }
        
        .progress-bar {
            height: 100%;
            width: 0%;
            background: linear-gradient(90deg, #ff6b6b, #ffa500);
            transition: width 0.3s ease;
        }
        
        .time-display {
            display: flex;
            justify-content: space-between;
            font-size: 0.9rem;
            color: rgba(255, 255, 255, 0.7);
            margin-bottom: 1rem;
        }
        
        .music-controls {
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 1rem;
            margin-bottom: 2rem;
        }
        
        .music-controls button {
            padding: 0.8rem;
            width: 50px;
            height: 50px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 50%;
        }
        
        .play-pause-btn {
            width: 60px !important;
            height: 60px !important;
            background: rgba(255, 255, 255, 0.3) !important;
        }
        
        .toggle-customization {
            position: absolute;
            top: 20px;
            left: 20px;
            z-index: 4;
        }
        
        .visualization {
            position: absolute;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 150px;
            z-index: 1;
            opacity: 0.5;
        }
        
        .visual-bar {
            position: absolute;
            bottom: 0;
            width: 8px;
            background: linear-gradient(to top, #ff6b6b, #ffa500);
            border-radius: 4px 4px 0 0;
            transition: height 0.1s ease;
        }
        
        .lyrics-display {
            margin-top: 2rem;
            text-align: center;
            max-height: 200px;
            overflow-y: auto;
            padding: 1rem;
            background: rgba(255, 255, 255, 0.05);
            border-radius: 10px;
        }
        
        .lyrics-line {
            margin-bottom: 0.5rem;
            font-size: 1.1rem;
            color: rgba(255, 255, 255, 0.8);
            transition: all 0.3s ease;
        }
        
        .lyrics-line.active {
            color: #ffa500;
            font-weight: bold;
            font-size: 1.3rem;
        }
        
        @keyframes pulse {
            0% { opacity: 0.5; }
            50% { opacity: 0.8; }
            100% { opacity: 0.5; }
        }
        
        @keyframes glow {
            0% { text-shadow: 0 0 10px currentColor; }
            50% { text-shadow: 0 0 20px currentColor, 0 0 30px currentColor; }
            100% { text-shadow: 0 0 10px currentColor; }
        }
        
        .glow {
            animation: glow 2s infinite;
        }
        
        .hidden {
            display: none;
        }
    </style>
</head>
<body>
    <div class="container">
        <button class="toggle-customization" id="toggleCustomization">
            <i class="bi bi-palette"></i> 自定义
        </button>
        
        <div class="customization-panel" id="customizationPanel">
            <h3>自定义设置</h3>
            
            <div class="form-group">
                <label for="songTitleInput">歌曲标题</label>
                <input type="text" id="songTitleInput" class="form-control" value="夜的第七章" placeholder="输入歌曲标题">
            </div>
            
            <div class="form-group">
                <label for="artistInput">歌手名称</label>
                <input type="text" id="artistInput" class="form-control" value="周杰伦" placeholder="输入歌手名称">
            </div>
            
            <div class="form-group">
                <label for="fontUpload">上传字体</label>
                <div class="file-input-container">
                    <button class="form-control" style="text-align: left;">
                        <i class="bi bi-fonts"></i> 选择字体文件
                    </button>
                    <input type="file" id="fontUpload" accept=".ttf,.otf,.woff,.woff2">
                </div>
            </div>
            
            <div class="form-group">
                <label for="fontSize">字体大小</label>
                <input type="range" id="fontSize" class="form-control" min="2" max="8" step="0.1" value="5">
                <div style="color: rgba(255,255,255,0.6); font-size: 0.8rem; text-align: center; margin-top: 5px;">
                    <span id="fontSizeValue">5rem</span>
                </div>
            </div>
            
            <div class="form-group">
                <label>字体颜色</label>
                <div class="color-input-container">
                    <input type="color" id="fontColor" class="color-input" value="#ffffff">
                    <span id="fontColorValue">#FFFFFF</span>
                </div>
            </div>
            
            <div class="form-group">
                <label>阴影颜色</label>
                <div class="color-input-container">
                    <input type="color" id="shadowColor" class="color-input" value="#ff6b6b">
                    <span id="shadowColorValue">#FF6B6B</span>
                </div>
            </div>
            
            <div class="form-group">
                <label for="shadowBlur">阴影模糊度</label>
                <input type="range" id="shadowBlur" class="form-control" min="0" max="20" value="10">
                <div style="color: rgba(255,255,255,0.6); font-size: 0.8rem; text-align: center; margin-top: 5px;">
                    <span id="shadowBlurValue">10px</span>
                </div>
            </div>
            
            <button id="applySettings" class="form-control" style="background: rgba(255,107,107,0.7); margin-top: 1rem;">
                <i class="bi bi-check-lg"></i> 应用设置
            </button>
        </div>
        
        <div class="song-title-container">
            <div class="song-title" id="songTitle">夜的第七章</div>
            <div class="artist-name" id="artistName">周杰伦</div>
        </div>
        
        <div class="progress-container">
            <div class="progress-bar" id="progressBar"></div>
        </div>
        
        <div class="time-display">
            <span id="currentTime">0:00</span>
            <span id="totalTime">0:00</span>
        </div>
        
        <div class="music-controls">
            <button id="prevBtn"><i class="bi bi-skip-start-fill"></i></button>
            <button id="playBtn" class="play-pause-btn"><i class="bi bi-play-fill"></i></button>
            <button id="nextBtn"><i class="bi bi-skip-end-fill"></i></button>
        </div>
        
        <div class="controls">
            <div class="file-input-container">
                <button id="musicUploadBtn"><i class="bi bi-music-note-beamed"></i> 上传歌曲</button>
                <input type="file" id="musicUpload" accept="audio/*">
            </div>
            <div class="file-input-container">
                <button id="lyricsUploadBtn"><i class="bi bi-file-text"></i> 上传歌词</button>
                <input type="file" id="lyricsUpload" accept=".lrc,.txt">
            </div>
            <button id="toggleVisualization"><i class="bi bi-soundwave"></i> 可视化效果</button>
            <button id="toggleGlow"><i class="bi bi-stars"></i> 发光效果</button>
        </div>
        
        <div class="lyrics-display" id="lyricsDisplay">
            <div class="lyrics-line">请上传歌词文件</div>
        </div>
        
        <div class="visualization" id="visualization"></div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            // 获取DOM元素
            const songTitle = document.getElementById('songTitle');
            const artistName = document.getElementById('artistName');
            const songTitleInput = document.getElementById('songTitleInput');
            const artistInput = document.getElementById('artistInput');
            const fontSize = document.getElementById('fontSize');
            const fontSizeValue = document.getElementById('fontSizeValue');
            const fontColor = document.getElementById('fontColor');
            const fontColorValue = document.getElementById('fontColorValue');
            const shadowColor = document.getElementById('shadowColor');
            const shadowColorValue = document.getElementById('shadowColorValue');
            const shadowBlur = document.getElementById('shadowBlur');
            const shadowBlurValue = document.getElementById('shadowBlurValue');
            const fontUpload = document.getElementById('fontUpload');
            const applySettings = document.getElementById('applySettings');
            const toggleCustomization = document.getElementById('toggleCustomization');
            const customizationPanel = document.getElementById('customizationPanel');
            const musicUpload = document.getElementById('musicUpload');
            const musicUploadBtn = document.getElementById('musicUploadBtn');
            const lyricsUpload = document.getElementById('lyricsUpload');
            const lyricsUploadBtn = document.getElementById('lyricsUploadBtn');
            const lyricsDisplay = document.getElementById('lyricsDisplay');
            const playBtn = document.getElementById('playBtn');
            const prevBtn = document.getElementById('prevBtn');
            const nextBtn = document.getElementById('nextBtn');
            const progressBar = document.getElementById('progressBar');
            const currentTime = document.getElementById('currentTime');
            const totalTime = document.getElementById('totalTime');
            const toggleVisualization = document.getElementById('toggleVisualization');
            const visualization = document.getElementById('visualization');
            const toggleGlow = document.getElementById('toggleGlow');
            
            let audioElement = null;
            let isPlaying = false;
            let isVisualizationVisible = true;
            let isGlowEnabled = false;
            let customFont = null;
            let lyricsData = [];
            let currentLyricIndex = 0;
            
            // 初始化设置
            function initSettings() {
                // 设置字体大小
                fontSizeValue.textContent = `${fontSize.value}rem`;
                songTitle.style.fontSize = `${fontSize.value}rem`;
                
                // 设置字体颜色
                fontColorValue.textContent = fontColor.value.toUpperCase();
                songTitle.style.color = fontColor.value;
                
                // 设置阴影
                updateTextShadow();
                
                // 应用歌曲标题和歌手名称
                songTitle.textContent = songTitleInput.value;
                artistName.textContent = artistInput.value;
            }
            
            // 更新文本阴影
            function updateTextShadow() {
                const blur = `${shadowBlur.value}px`;
                const color = shadowColor.value;
                shadowBlurValue.textContent = `${shadowBlur.value}px`;
                shadowColorValue.textContent = color.toUpperCase();
                
                songTitle.style.textShadow = `0 0 ${blur} ${color}`;
                artistName.style.textShadow = `0 0 ${blur} ${color}`;
            }
            
            // 应用设置
            applySettings.addEventListener('click', () => {
                initSettings();
                
                // 显示成功提示
                const originalText = applySettings.innerHTML;
                applySettings.innerHTML = '<i class="bi bi-check-lg"></i> 已应用';
                applySettings.style.background = 'rgba(76, 175, 80, 0.7)';
                
                setTimeout(() => {
                    applySettings.innerHTML = originalText;
                    applySettings.style.background = 'rgba(255,107,107,0.7)';
                }, 2000);
            });
            
            // 切换自定义面板
            toggleCustomization.addEventListener('click', () => {
                customizationPanel.classList.toggle('hidden');
            });
            
            // 字体大小变化
            fontSize.addEventListener('input', () => {
                fontSizeValue.textContent = `${fontSize.value}rem`;
                songTitle.style.fontSize = `${fontSize.value}rem`;
            });
            
            // 字体颜色变化
            fontColor.addEventListener('input', () => {
                fontColorValue.textContent = fontColor.value.toUpperCase();
                songTitle.style.color = fontColor.value;
            });
            
            // 阴影颜色变化
            shadowColor.addEventListener('input', () => {
                updateTextShadow();
            });
            
            // 阴影模糊度变化
            shadowBlur.addEventListener('input', () => {
                updateTextShadow();
            });
            
            // 上传字体
            fontUpload.addEventListener('change', (e) => {
                const file = e.target.files[0];
                if (file) {
                    const fontUrl = URL.createObjectURL(file);
                    customFont = new FontFace('CustomFont', `url(${fontUrl})`);
                    
                    customFont.load().then((loadedFont) => {
                        document.fonts.add(loadedFont);
                        songTitle.style.fontFamily = 'CustomFont, sans-serif';
                        artistName.style.fontFamily = 'CustomFont, sans-serif';
                        
                        // 显示成功提示
                        musicUploadBtn.innerHTML = `<i class="bi bi-fonts"></i> ${file.name.substring(0, 10)}${file.name.length > 10 ? '...' : ''}`;
                    }).catch((error) => {
                        console.error('字体加载失败:', error);
                        alert('字体加载失败,请尝试其他字体文件。');
                    });
                }
            });
            
            // 上传歌词
            lyricsUpload.addEventListener('change', (e) => {
                const file = e.target.files[0];
                if (file) {
                    const reader = new FileReader();
                    reader.onload = (event) => {
                        const content = event.target.result;
                        parseLyrics(content);
                        displayLyrics();
                        
                        // 更新按钮文本
                        lyricsUploadBtn.innerHTML = `<i class="bi bi-file-text"></i> ${file.name.substring(0, 10)}${file.name.length > 10 ? '...' : ''}`;
                    };
                    reader.readAsText(file);
                }
            });
            
            // 解析歌词
            function parseLyrics(content) {
                lyricsData = [];
                const lines = content.split('\n');
                
                for (let line of lines) {
                    line = line.trim();
                    if (!line) continue;
                    
                    // 尝试解析LRC格式
                    const timeMatch = line.match(/\[(\d+):(\d+\.\d+)\](.*)/);
                    if (timeMatch) {
                        const minutes = parseInt(timeMatch[1]);
                        const seconds = parseFloat(timeMatch[2]);
                        const text = timeMatch[3].trim();
                        const time = minutes * 60 + seconds;
                        
                        lyricsData.push({
                            time: time,
                            text: text
                        });
                    } else if (line.startsWith('[') && line.includes('ti:')) {
                        // 提取歌曲标题
                        const titleMatch = line.match(/\[ti:(.*)\]/);
                        if (titleMatch) {
                            songTitleInput.value = titleMatch[1].trim();
                            songTitle.textContent = titleMatch[1].trim();
                        }
                    } else if (line.startsWith('[') && line.includes('ar:')) {
                        // 提取歌手名称
                        const artistMatch = line.match(/\[ar:(.*)\]/);
                        if (artistMatch) {
                            artistInput.value = artistMatch[1].trim();
                            artistName.textContent = artistMatch[1].trim();
                        }
                    } else {
                        // 普通文本行
                        lyricsData.push({
                            time: null,
                            text: line
                        });
                    }
                }
                
                // 按时间排序
                lyricsData.sort((a, b) => {
                    if (a.time === null) return 1;
                    if (b.time === null) return -1;
                    return a.time - b.time;
                });
            }
            
            // 显示歌词
            function displayLyrics() {
                lyricsDisplay.innerHTML = '';
                
                if (lyricsData.length === 0) {
                    lyricsDisplay.innerHTML = '<div class="lyrics-line">没有找到歌词</div>';
                    return;
                }
                
                lyricsData.forEach((lyric, index) => {
                    const line = document.createElement('div');
                    line.className = 'lyrics-line';
                    line.textContent = lyric.text;
                    line.dataset.index = index;
                    
                    lyricsDisplay.appendChild(line);
                });
            }
            
            // 更新当前歌词
            function updateCurrentLyric() {
                if (!audioElement || lyricsData.length === 0) return;
                
                const currentTime = audioElement.currentTime;
                let newIndex = 0;
                
                // 找到当前时间对应的歌词
                for (let i = 0; i < lyricsData.length; i++) {
                    if (lyricsData[i].time !== null && lyricsData[i].time <= currentTime) {
                        newIndex = i;
                    } else {
                        break;
                    }
                }
                
                // 更新高亮
                if (newIndex !== currentLyricIndex) {
                    const oldLine = lyricsDisplay.querySelector('.lyrics-line.active');
                    if (oldLine) {
                        oldLine.classList.remove('active');
                    }
                    
                    const newLine = lyricsDisplay.querySelector(`.lyrics-line[data-index="${newIndex}"]`);
                    if (newLine) {
                        newLine.classList.add('active');
                        // 滚动到当前歌词
                        newLine.scrollIntoView({
                            behavior: 'smooth',
                            block: 'center'
                        });
                    }
                    
                    currentLyricIndex = newIndex;
                }
            }
            
            // 上传音乐
            musicUpload.addEventListener('change', (e) => {
                const file = e.target.files[0];
                if (file) {
                    if (audioElement) {
                        audioElement.pause();
                    }
                    
                    const url = URL.createObjectURL(file);
                    audioElement = new Audio(url);
                    
                    // 更新按钮文本
                    musicUploadBtn.innerHTML = `<i class="bi bi-music-note-beamed"></i> ${file.name.substring(0, 10)}${file.name.length > 10 ? '...' : ''}`;
                    
                    // 设置音频事件
                    audioElement.addEventListener('loadedmetadata', () => {
                        totalTime.textContent = formatTime(audioElement.duration);
                    });
                    
                    audioElement.addEventListener('timeupdate', () => {
                        const progress = (audioElement.currentTime / audioElement.duration) * 100;
                        progressBar.style.width = `${progress}%`;
                        currentTime.textContent = formatTime(audioElement.currentTime);
                        
                        // 更新歌词
                        updateCurrentLyric();
                    });
                    
                    audioElement.addEventListener('ended', () => {
                        isPlaying = false;
                        playBtn.innerHTML = '<i class="bi bi-play-fill"></i>';
                        progressBar.style.width = '0%';
                        currentTime.textContent = '0:00';
                    });
                    
                    // 自动播放
                    audioElement.play().then(() => {
                        isPlaying = true;
                        playBtn.innerHTML = '<i class="bi bi-pause-fill"></i>';
                    }).catch(error => {
                        console.error('播放错误:', error);
                    });
                }
            });
            
            // 播放/暂停
            playBtn.addEventListener('click', () => {
                if (audioElement) {
                    if (isPlaying) {
                        audioElement.pause();
                        isPlaying = false;
                        playBtn.innerHTML = '<i class="bi bi-play-fill"></i>';
                    } else {
                        audioElement.play().then(() => {
                            isPlaying = true;
                            playBtn.innerHTML = '<i class="bi bi-pause-fill"></i>';
                        }).catch(error => {
                            console.error('播放错误:', error);
                        });
                    }
                }
            });
            
            // 上一曲/下一曲(示例功能)
            prevBtn.addEventListener('click', () => {
                if (audioElement) {
                    audioElement.currentTime = Math.max(0, audioElement.currentTime - 10);
                }
            });
            
            nextBtn.addEventListener('click', () => {
                if (audioElement) {
                    audioElement.currentTime = Math.min(audioElement.duration, audioElement.currentTime + 10);
                }
            });
            
            // 切换可视化效果
            toggleVisualization.addEventListener('click', () => {
                isVisualizationVisible = !isVisualizationVisible;
                visualization.style.opacity = isVisualizationVisible ? '0.5' : '0';
                toggleVisualization.innerHTML = isVisualizationVisible ? 
                    '<i class="bi bi-soundwave"></i> 隐藏可视化' : 
                    '<i class="bi bi-soundwave"></i> 显示可视化';
            });
            
            // 切换发光效果
            toggleGlow.addEventListener('click', () => {
                isGlowEnabled = !isGlowEnabled;
                if (isGlowEnabled) {
                    songTitle.classList.add('glow');
                    toggleGlow.innerHTML = '<i class="bi bi-stars"></i> 关闭发光';
                    toggleGlow.style.background = 'rgba(255,107,107,0.7)';
                } else {
                    songTitle.classList.remove('glow');
                    toggleGlow.innerHTML = '<i class="bi bi-stars"></i> 发光效果';
                    toggleGlow.style.background = 'rgba(255,255,255,0.2)';
                }
            });
            
            // 创建可视化效果
            function createVisualization() {
                visualization.innerHTML = '';
                const barCount = 50;
                const width = visualization.clientWidth / barCount;
                
                for (let i = 0; i < barCount; i++) {
                    const bar = document.createElement('div');
                    bar.className = 'visual-bar';
                    bar.style.left = `${i * width}px`;
                    bar.style.width = `${width - 2}px`;
                    bar.style.height = `${Math.random() * 100 + 20}px`;
                    visualization.appendChild(bar);
                }
                
                // 动画效果
                setInterval(() => {
                    if (isVisualizationVisible && isPlaying) {
                        const bars = document.querySelectorAll('.visual-bar');
                        bars.forEach(bar => {
                            const newHeight = Math.random() * 100 + 20;
                            bar.style.height = `${newHeight}px`;
                        });
                    }
                }, 200);
            }
            
            // 格式化时间
            function formatTime(seconds) {
                const mins = Math.floor(seconds / 60);
                const secs = Math.floor(seconds % 60);
                return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
            }
            
            // 初始化
            initSettings();
            createVisualization();
            
            // 窗口大小变化时重新创建可视化
            window.addEventListener('resize', createVisualization);
        });
    </script>
</body>
</html>
相关推荐
歪歪1003 小时前
ts-jest与其他TypeScript测试工具的对比
前端·javascript·测试工具·typescript·前端框架
CodeSheep3 小时前
JetBrains官宣,又一个IDE可以免费用了!
前端·后端·程序员
刘新明19893 小时前
Frida辅助分析OLLVM虚假控制流程(下)
java·开发语言·前端
江城开朗的豌豆3 小时前
小程序登录不迷路:一篇文章搞定用户身份验证
前端·javascript·微信小程序
aesthetician3 小时前
React 19.2.0: 新特性与优化深度解析
前端·javascript·react.js
FIN66683 小时前
射频技术领域的领航者,昂瑞微IPO即将上会审议
前端·人工智能·前端框架·信息与通信
U.2 SSD4 小时前
ECharts漏斗图示例
前端·javascript·echarts
江城开朗的豌豆4 小时前
我的小程序登录优化记:从短信验证到“一键获取”手机号
前端·javascript·微信小程序
excel4 小时前
Vue Mixin 全解析:概念、使用与源码
前端·javascript·vue.js