Skip to content

贡献指南

欢迎为 NeteaseMiniPlayer v2 (NMP v2) 项目做出贡献!本指南将帮助你了解如何参与项目开发。

🤝 如何贡献

贡献方式

  • 🐛 报告 Bug:发现问题请提交 Issue
  • 💡 功能建议:提出新功能想法
  • 📝 文档改进:完善项目文档
  • 🔧 代码贡献:修复 Bug 或添加新功能
  • 🌐 翻译工作:帮助翻译文档

参与流程

  1. Fork 项目

    bash
    # 在 GitHub 上 Fork 项目到你的账户
  2. 克隆仓库

    bash
    git clone https://github.com/your-username/NeteaseMiniPlayer.git
    cd NeteaseMiniPlayer
  3. 创建分支

    bash
    git checkout -b feature/your-feature-name
    # 或
    git checkout -b fix/your-bug-fix
  4. 安装依赖

    bash
    npm install
  5. 开发和测试

    bash
    # 启动开发服务器
    npm run dev
    
    # 运行测试
    npm test
  6. 提交更改

    bash
    git add .
    git commit -m "feat: 添加新功能描述"
  7. 推送分支

    bash
    git push origin feature/your-feature-name
  8. 创建 Pull Request

    • 在 GitHub 上创建 PR
    • 详细描述你的更改
    • 等待代码审查

📋 开发规范

代码风格

JavaScript 规范

javascript
// ✅ 推荐的代码风格
class MusicPlayer {
  constructor(options = {}) {
    this.config = {
      theme: 'auto',
      position: 'bottom-right',
      ...options
    }
  }

  /**
   * 初始化播放器
   * @param {Object} config - 配置选项
   * @returns {Promise<void>}
   */
  async init(config) {
    try {
      await this.loadResources()
      this.render()
    } catch (error) {
      console.error('播放器初始化失败:', error)
      throw error
    }
  }

  // 私有方法使用下划线前缀
  _validateConfig(config) {
    if (!config.songId && !config.playlistId) {
      throw new Error('必须提供 songId 或 playlistId')
    }
  }
}

// 常量使用大写
const DEFAULT_CONFIG = {
  THEME: 'auto',
  POSITION: 'bottom-right'
}

// 使用 const/let,避免 var
const apiUrl = 'https://api.hypcvgm.top'
let currentSong = null

CSS 规范

css
/* ✅ 推荐的 CSS 风格 */
.netease-mini-player {
  /* 使用 BEM 命名规范 */
  position: relative;
  background: var(--nmp-bg-color);
  border-radius: 8px;
  transition: all 0.3s ease;
}

.netease-mini-player__controls {
  display: flex;
  align-items: center;
  gap: 12px;
}

.netease-mini-player__button {
  padding: 8px;
  border: none;
  background: transparent;
  cursor: pointer;
}

.netease-mini-player__button--active {
  color: var(--nmp-primary-color);
}

/* 响应式设计 */
@media (max-width: 768px) {
  .netease-mini-player {
    width: 100%;
    border-radius: 0;
  }
}

/* 深色主题 */
.netease-mini-player[data-theme="dark"] {
  --nmp-bg-color: #1a1a1a;
  --nmp-text-color: #ffffff;
}

命名规范

  • 变量和函数:使用 camelCase
  • 常量:使用 UPPER_SNAKE_CASE
  • 类名:使用 PascalCase
  • CSS 类:使用 kebab-case 或 BEM
  • 文件名:使用 kebab-case

注释规范

javascript
/**
 * 播放器核心类
 * @class MusicPlayer
 * @description 提供音乐播放功能的核心类
 */
class MusicPlayer {
  /**
   * 播放指定歌曲
   * @param {string} songId - 歌曲 ID
   * @param {Object} options - 播放选项
   * @param {boolean} options.autoplay - 是否自动播放
   * @returns {Promise<void>}
   * @throws {Error} 当歌曲 ID 无效时抛出错误
   */
  async playSong(songId, options = {}) {
    // 实现代码...
  }
}

🧪 测试要求

测试覆盖率

  • 单元测试:覆盖率 ≥ 80%
  • 集成测试:覆盖主要功能流程
  • E2E 测试:覆盖用户关键操作

测试示例

单元测试

javascript
// tests/unit/player.test.js
import { describe, it, expect, beforeEach } from 'vitest'
import { MusicPlayer } from '../src/player.js'

describe('MusicPlayer', () => {
  let player

  beforeEach(() => {
    player = new MusicPlayer()
  })

  it('应该正确初始化默认配置', () => {
    expect(player.config.theme).toBe('auto')
    expect(player.config.position).toBe('bottom-right')
  })

  it('应该验证必需的配置参数', () => {
    expect(() => {
      player._validateConfig({})
    }).toThrow('必须提供 songId 或 playlistId')
  })
})

集成测试

javascript
// tests/integration/api.test.js
import { describe, it, expect } from 'vitest'
import { ApiService } from '../src/services/api.js'

describe('ApiService Integration', () => {
  it('应该能够获取歌曲信息', async () => {
    const api = new ApiService()
    const songInfo = await api.getSongInfo('1823012873')
    
    expect(songInfo).toHaveProperty('name')
    expect(songInfo).toHaveProperty('artist')
    expect(songInfo).toHaveProperty('url')
  })
})

E2E 测试

javascript
// tests/e2e/player.spec.js
import { test, expect } from '@playwright/test'

test('播放器基本功能', async ({ page }) => {
  await page.goto('/demo')
  
  // 检查播放器是否渲染
  const player = page.locator('.netease-mini-player')
  await expect(player).toBeVisible()
  
  // 测试播放按钮
  const playButton = page.locator('.play-button')
  await playButton.click()
  await expect(playButton).toHaveClass(/playing/)
})

运行测试

bash
# 运行所有测试
npm test

# 运行单元测试
npm run test:unit

# 运行集成测试
npm run test:integration

# 运行 E2E 测试
npm run test:e2e

# 生成覆盖率报告
npm run test:coverage

📝 提交规范

Commit Message 格式

使用 Conventional Commits 规范:

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

类型说明

  • feat: 新功能
  • fix: Bug 修复
  • docs: 文档更新
  • style: 代码格式调整
  • refactor: 代码重构
  • test: 测试相关
  • chore: 构建过程或辅助工具的变动

示例

bash
# 新功能
git commit -m "feat(player): 添加歌词显示功能"

# Bug 修复
git commit -m "fix(api): 修复歌曲信息获取失败的问题"

# 文档更新
git commit -m "docs: 更新 API 使用说明"

# 重构
git commit -m "refactor(ui): 优化播放器组件结构"

🔍 Pull Request 检查清单

提交 PR 前请确保:

  • [ ] 代码遵循项目规范
  • [ ] 添加了必要的测试
  • [ ] 测试全部通过
  • [ ] 更新了相关文档
  • [ ] Commit message 符合规范
  • [ ] 没有引入 breaking changes(如有请说明)

PR 模板

markdown
## 📋 变更说明

### 变更类型
- [ ] Bug 修复
- [ ] 新功能
- [ ] 文档更新
- [ ] 性能优化
- [ ] 代码重构

### 变更描述
简要描述你的更改...

### 测试
- [ ] 添加了单元测试
- [ ] 添加了集成测试
- [ ] 手动测试通过

### 截图(如适用)
添加截图来展示你的更改...

### 相关 Issue
Closes #123

🎯 开发环境设置

推荐工具

  • 编辑器:VS Code
  • Node.js:≥ 16.0.0
  • 包管理器:npm 或 yarn
  • 浏览器:Chrome(用于调试)

VS Code 扩展推荐

json
{
  "recommendations": [
    "esbenp.prettier-vscode",
    "dbaeumer.vscode-eslint",
    "bradlc.vscode-tailwindcss",
    "ms-vscode.vscode-typescript-next"
  ]
}

项目配置

json
// .vscode/settings.json
{
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "files.associations": {
    "*.vue": "vue"
  }
}

📞 获取帮助

如果你在贡献过程中遇到问题:

  1. 搜索现有的 Issues
  2. 创建新的 Issue 描述你的问题

🙏 致谢

感谢所有为 NeteaseMiniPlayer v2 做出贡献的开发者!


记住:每一个贡献都很重要,无论大小。让我们一起打造更好的音乐播放器! 🎵

Copyright © 2025 NeteaseMiniPlayer