Vue 综合应用 -网页音乐播放器

综合应用 - 悦听player 案例

使用 Vue 框架 + axios + api ,开发一个简易的网页音乐播放器

网易云免费歌曲接口:

  1. 歌曲搜索接口

  • 地址:https://autumnfish.cn/search

  • 方法:GET

  • 参数:keywords 查询关键字

  • 响应:歌曲搜索结果 ( 包含要使用的 歌曲 idmvid

  • 在这里插入图片描述

  1. 歌曲url获取接口

  • 地址:https://autumnfish.cn/song/url

  • 方法:GET

  • 参数:id 歌曲id,可以从 api 1 中获取

  • 响应:歌曲url地址

  1. 歌曲详情获取

  • 地址:https://autumnfish.cn/song/detail

  • 方法:GET

  • 参数:ids 歌曲id,可以从 api 1 中获取

  • 响应:歌曲详情 (包括封面信息)

  1. 热门评论获取

  • 地址:https://autumnfish.cn/comment/hot?type=0

  • 方法:GET

  • 参数:id (歌曲 id , 地址中的 type 固定为 0) 可以从 api 1 中获取

  • 响应:歌曲的热门评论

  1. mv地址获取

  • 地址:https://autumnfish.cn/mv/url

  • 方法:GET

  • 参数:id ( mvid , 为 0 表示没有mv) 可以从 api 1 中获取

  • 响应:mv 的地址


成品效果

在这里插入图片描述


引入 Vue 、 axios

  • 这里使用的是本地的 Vue.js,下载地址:https://v1-cn.vuejs.org/guide/installation.html
<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
<script src="../../../dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

静态资源


分析结构

  1. 搜索界面

    • 按下 enter 键搜索
  2. 内容界面

    • 歌曲列表

      • 展示获取的歌曲 (列表)
      • 播放按钮
      • MV 按钮
    • 歌曲详情 (播放时展示)

      • 播放碟片旋转 (通过添加 playing 类名)
      • 展示歌曲的封面
    • 热门评论 (播放时展示)

      • 展示热门用户的评论内容 (列表)
      • 显示用户的头像、用户昵称
  3. 歌曲播放界面

    • 按下播放按钮,歌曲播放
  4. MV 界面

    • 按下 MV 按钮,播放歌曲 mv

1. 基本容器、实例

html 代码 </>

<div class="wrap">
    <!-- 播放器主体区域、容器 -->
    <div class="play_wrap" id="player">
        <!-- 搜索 todo -->
        <!-- 内容 todo -->
        <!-- 音乐 todo -->
        <!-- MV 视频 todo -->
    </div>
</div>

javascript 代码 </>

// 创建 Vue 实例
new Vue({
    el:"#player",
    data:{},
    methods:{}
})

2. 搜索界面

html 代码 </>

  • + @keyup.enter="searchMusic" enter 键抬起,调用搜索方法
  • + v-model="query" 获取用户输入
<div class="search_bar">
    <img src="images/player_title.png" alt="logo" />
    <!-- 搜索歌曲 、获取用户输入-->
    <input @keyup.enter="searchMusic" type="text" autofocus autocomplete="off" v-model="query" />
</div>

javascript 代码 </>

  • + query 保存用户输入
  • + musicList:[] 保存歌曲列表
  • + searchMusic: function (){} 搜索功能函数
// Vue 实例
new Vue({
    el:"#player",
    data:{
        query:"",
        musicList:[]
    },
    methods:{
        // 搜索功能
        searchMusic: function ()
        {
            if (this.query.trim() === "") return;
            let self = this;
            // 搜索歌曲 返回歌曲数据
            axios.get(`https://autumnfish.cn/search?keywords=${this.query}`)
                .then(res => self.musicList = res.data.result.songs)
                .catch(err => console.error(err))
        }
    }
})

3. 内容界面

html 代码 </>

<div class="center_con">
    <!-- 歌曲列表 todo -->
    <!-- 歌曲信息容器 todo -->
    <!-- 评论容器 todo -->
</div>
  • 歌曲列表

  • + v-for="(item, index) in musicList" 生成歌曲列表结构
  • + @click="playMusic(item.id)" 播放歌曲按钮
  • + {{item.name}} 展示歌曲名称
  • + v-if="item.mvid!=0" @click="playMv(item.mvid)" 显示和隐藏 MV 按钮、播放 MV

html 代码 </>

<!-- 歌曲列表 -->
<div class='song_wrapper'>
    <ul class="song_list">
        <!-- 生成歌曲列表 -->
        <li v-for="(item, index) in musicList">
            <!-- 播放按钮、拿到歌曲 id -->
            <a href="javascript:;" @click="playMusic(item.id)"></a>
            <!-- 拿到歌曲名称 -->
            <b>{{item.name}}</b>
            <!-- 播放歌曲 MV 按钮、拿到歌曲的 mvid -->
            <span v-if="item.mvid!=0" @click="playMv(item.mvid)"><i><i></span>
        </li>
    </ul>
    <img src="images/line.png" class="switch_btn" alt="1">
</div>

javascript 代码 </>

  • + playMusic: function (musicId){} 播放歌曲功能
  • + playMv: function (mvid){} 播放歌曲 MV 功能
  • + musicUrl 保存歌曲 url
  • + musicCover 保存歌曲封面 url
  • + hotComments: [] 保存热门评论数组
  • + mvUrl 保存歌曲MV url
  • + isPlaying 音频播放状态
  • + isMask MV 视频遮罩状态
new Vue({
    el:"#player",
    data:{
        query:"",
        musicList:[],
        musicUrl:"",
        musicCover:"",
        hotComments:"",
        mvUrl: "",
        isPlaying: false,
        isMask: false,
    },
    methods:{
        // 搜索
        searchMusic: function ()
        {
            if (this.query.trim() === "") return;
            let self = this;
            // 搜索歌曲 返回歌曲数据
            axios.get(`https://autumnfish.cn/search?keywords=${this.query}`)
                .then(res => self.musicList = res.data.result.songs)
                .catch(err => console.error(err))
        },
        // 播放歌曲
        playMusic: function (musicId)
        {
            let self = this;
            // 1. 获取歌曲 url
            axios.get(`https://autumnfish.cn/song/url?id=${musicId}`)
                .then(res => self.musicUrl = res.data.data[0].url)
                .catch(err => console.error(err))

            // 2. 歌曲详情,获取歌曲封面url
            axios.get(`https://autumnfish.cn/song/detail?ids=${musicId}`)
                .then(res => self.musicCover = res.data.songs[0].al.picUrl)
                .catch(err => console.error(err))

            // 3. 获取歌曲评论
            axios.get(`https://autumnfish.cn/comment/hot?type=0&id=${musicId}`)
                .then(res => self.hotComments = res.data.hotComments)
                .catch(err => console.error(err))
        },
        // 播放MV
        playMv: function (mvid)
        {
            axios.get(`https://autumnfish.cn/mv/url?id=${mvid}`)
            .then(res =>
            {
                // 显示视频遮罩
                this.isMask = true;
                // 获取 mv url
                this.mvUrl = res.data.data.url;
            })
            .catch(err => console.error(err))
        },      

    }
})

歌曲信息、封面

html 代码</>

  • + :class="{playing:isPlaying}" 绑定 class=“playing” 属性,有没有值取决于 isPlaying
  • + :src="musicCover" 歌曲封面
<!-- 拿到播放状态 -->
<div class="player_con" :class="{playing:isPlaying}">
    <img src="images/player_bar.png" class="play_bar" />
    <img src="images/disc.png" class="disc autoRotate" />
    <!-- 拿到歌曲封面的 URL 地址 -->
    <img :src="musicCover" class="cover autoRotate" />
</div>

热门、评论容器

  • + v-for="(item, index) in hotComments" 热门评论列表
  • + :src="item.user.avatarUrl" 用户头像
  • + {{item.user.nickname}} 用户昵称
  • + {{item.content}} 评论内容
<div class="comment_wrapper">
    <h5 class='title'>热门留言</h5>
    <div class='comment_list'>
        <!-- 生成热门评论列表 -->
        <dl v-for="(item, index) in hotComments">
            <dt>
                <!-- 拿到用户的头像 URL 地址 -->
                <img :src="item.user.avatarUrl" alt="user">
            </dt>
            <dd class="name">
                <!-- 用户昵称 -->
                {{item.user.nickname}}
            </dd>
            <dd class="detail">
                <!-- 用户的热门评论内容 -->
                {{item.content}}
            </dd>
        </dl>
    </div>
    <img src="images/line.png" class="right_line">
</div>

4. 歌曲播放界面

  • + :src="musicUrl" 绑定歌曲 url
  • + @play="play" 绑定 audio 播放事件(碟片开始旋转)
  • + @pause="pause"" 绑定 audio 暂停事件(碟片停止旋转)

html </>

<div class="audio_con">
    <!-- 拿到歌曲的 URL 地址、绑定事件 -->
    <audio ref='audio' :src="musicUrl" @play="play" @pause="pause" autoplay controls loop class="myaudio"></audio>
</div>

javascript </> (完整)

  • + play: function (){} 音乐开始播放时
  • + pause: function (){} 音乐暂停时
  • + hide: function (){} 隐藏MV视频遮罩
// Vue 实例
new Vue({
    el:"#player",
    data:{
        query:"",           // 用户输入,搜索
        musicList:[],       // 每次搜索返回的歌曲数组
        musicUrl:"",        // 歌曲的 URL 地址
        musicCover:"",      // 歌曲的 URL 封面
        hotComments:"",     // 一个歌曲的热门评论数组
        mvUrl: "",          // MV 视频的 URL 地址
        isPlaying: false,   // 音乐播放的状态
        isMask: false,      // MV 视频的遮罩状态
    },
    methods:{
        // 搜索功能
        searchMusic: function ()
        {   
            if (this.query.trim() === "") return;
            let self = this;
            // 搜索歌曲 => 返回歌曲数据
            axios.get(`https://autumnfish.cn/search?keywords=${this.query}`)
                .then(res => self.musicList = res.data.result.songs)
                .catch(err => console.error(err))
        },
        // 播放歌曲功能
        playMusic: function (musicId)
        {
            let self = this;
            // 1. 获取歌曲 url 
            axios.get(`https://autumnfish.cn/song/url?id=${musicId}`)
                .then(res => self.musicUrl = res.data.data[0].url)
                .catch(err => console.error(err))

            // 2. 歌曲详情,获取歌曲封面 url
            axios.get(`https://autumnfish.cn/song/detail?ids=${musicId}`)
                .then(res => self.musicCover = res.data.songs[0].al.picUrl)
                .catch(err => console.error(err))

            // 3. 热门评论获取
            axios.get(`https://autumnfish.cn/comment/hot?type=0&id=${musicId}`)
                .then(res => self.hotComments = res.data.hotComments)
                .catch(err => console.error(err))
        },
        // 播放 MV 功能
        playMv: function (mvid)
        {
            axios.get(`https://autumnfish.cn/mv/url?id=${mvid}`)
                .then(res =>
                {
                    // 显示视频遮罩
                    this.isMask = true;
                    // 获取 mv url
                    this.mvUrl = res.data.data.url;
                })
                .catch(err => console.error(err))
                .finally(() => document.querySelector("video").play())
        },
        // 播放
        play: function ()
        {           
            this.isPlaying = true;
        },
        // 暂停
        pause: function ()
        {           
            this.isPlaying = false;
        },
          // 隐藏遮罩
        hide: function ()
        {
            this.isMask = false;
            document.querySelector("video").pause();
        },

    }
})

5. MV 播放界面

  • + v-show="isMask" 显示、隐藏遮罩
  • + :src="mvUrl" MV 视频 url
  • + @click="hide" 点击,隐藏遮罩

html </>

<!-- 拿到 MV 视频遮罩状态,显示和隐藏 MV 界面 -->
<div class="video_con" style="display: none;" v-show="isMask">
    <!-- 拿到歌曲 MV 的 URL 地址 -->
    <video :src="mvUrl" controls="controls"></video>
    <!-- 点击视频外面,隐藏视频遮罩 -->
    <div class="mask" @click="hide"></div>
</div>