[jQuery基础] jQuery案例 -- qq音乐以及初步解决Ajax 跨域问题
qq音乐案例
案例效果展示
案例效果结构划分
整体布局
歌曲条目部分
顶部栏
底部栏
歌词显示部分
案例实现功能
a. QQ音乐播放器静态页面布局
* 页面整体布局规划和实现
* 页面顶部布局和静态效果
* 工具条布局和静态效果
* 音乐列表布局和静态效果
* 自定义滚动条效果
* 歌曲信息的展示效果
* 底部播放布局和静态效果
* 页面整体的高斯模糊效果
b. QQ音乐播放器加载并播放歌曲
* 实现音乐动态加载逻辑
* 实现底部音乐控制图标的动态切换
* 实现底部音乐播放状态的动态切换
* 实现音乐序号的动画效果
c. QQ音乐播放器操作歌曲(切换、删除等)
* 实现音乐的播放、暂停功能
* 实现音乐切换(切歌)功能
* 实现音乐删除功能
d. QQ音乐播放器歌词加载、显示和同步
* 实现解析歌词并动态加载功能
* 实现歌词与歌曲播放进度同步功能
e. 拖动音乐进度条调整音乐播放进度功能
案例知识点(参考别人)
- CSS
- 设置距离左边的距离:margin-left: 20px; 设置距离右边的距离:margin-right: 20px;
- 设置透明度:opacity: 0.6; 值[0,1]从透明到全不透明
- 设置背景图片:background: url(…/img/player_logo.png) no-repeat 0 0;
- 设背景颜色和透明度:background: rgba(255,255,255,0.5);
- 设置li的样式:list-style: none;
- 设置显示样式为行内块:display: inline-block;
- 设置圆角:border-radius: 5px;
- 设置相对位置:position: relative;
- 背景图片的起始坐标:background-position: 0 -75px;
- JS
- 通过标签获取jQuery对象:var audio=audio =audio=(“audio”);
- 通过选择符获取jQuery对象并设置文本内容:$(".music_progrss_time").text(timeStr);
- 通过选择符,标签名获取对象并获取第i个子元素:$(".song_lyric ul li").eq(index);
- 通过ajax异步获取数据并刷新页面:$.ajax({});
- 通过类选择符获取元素并进行隐藏或显示:$(this).find(".list_menu").stop().fadeIn(100);
- 通过委托动态设置单击事件,主要针对动态生成元素:$(".content_list").delegate(".list_check", “click”, function() {});
- 通过addClass添加类,removeClass删除类,toggleClass切换类,hasClass是否包含类
- 获取与对象同级的兄弟节点:$musicList.siblings();
- 触发相关事件:$(".music_next").trigger(“click”);
案例思路
首先要先布局
头部header、中间区域content、底部footer和背景mask_bg
<!--头部header --> <div class="header"><h1 class="logo"><a href="#"></a></h1><ul class="register"><li>注册</li><li>登陆</li></ul> </div> <!--中间区域content--> <div class="content"><div class="content_in"></div> </div> <!--底部footer--> <div class="footer"><div class="footer_in"></div> </div> <!--背景mask_bg--> <div class="mask_bg"></div>
工具条(收藏、添加到、下载、删除、清空列表),利用雪碧图完成图片
<div class="content_in"><!-- 左边内容 --><div class="content_left"><!-- 左上部分 --><div class="content_toolbar"><!-- 布局文字和图片 --><span><i></i>收藏</span><span><i></i>添加到</span><span><i></i>下载</span><span><i></i>删除</span><span><i></i>清空列表</span></div></div> </div>
初步完成歌曲列表
<!-- 左下部分 --><ul><!-- 每一个歌曲条目 --><li class="list_title"><!-- 选项框 --><div class="list_check"><i></i></div><!-- 数字 --><div class="list_number"></div><!-- 歌曲 --><div class="list_name">歌曲</div><!-- 歌手 --><div class="list_singer">歌手</div><!-- 时长 --><div class="list_time">时长</div></li></ul></div>
完善歌曲部分
- 可以点击选项框
- 再点击每一行的时候会出现暂停,添加,下载,转发,删除等,换到下一行的时候其他行会淡入淡出的消失
function initEvents() {// 1.监听歌曲的移入移出事件 // 要用事件委托因为歌曲都是新增的$(".content_list").delegate(".list_music", "mouseenter", function () {//find 搜索所有与指定表达式相匹配的元素,这个函数是找出正在处理的元素的后代元素的好方法//如果直接用$('.list_menu')所有菜单会一起显示出来// 显示子菜单$(this).find(".list_menu").stop().fadeIn(100);$(this).find(".list_time a").stop().fadeIn(100);// 隐藏时长$(this).find(".list_time span").stop().fadeOut(100);});$(".content_list").delegate(".list_music", "mouseleave", function () {// 隐藏子菜单$(this).find(".list_menu").stop().fadeOut(100);$(this).find(".list_time a").stop().fadeOut(100);// 显示时长$(this).find(".list_time span").stop().fadeIn(100);});/*addClass()是在原有的类基础上增加类属性,仍然保留原有的类的样式toggleClass() 是切换元素class类别,删除原有的class样式,替换为新的class样式. (切换,没有加,有减) */// 2.监听复选框的点击事件$(".content_list").delegate(".list_check", "click", function () {$(this).toggleClass("list_checked");//有就删除,没有就添加}); }
自定义滚动条
自定义滚动条运用到了jQuery的插件,可以利用这个插件来设置不同样式的滚动条 — jQuery custom content scroller
- 首先要从官网上下载
- 在html中添加
<div class="content_list" data-mcs-theme='minimal-dark'></div>
- 在JavaScript中添加
$(".content_list").mCustomScrollbar();
如果不喜欢可以修改默认样式
._mCS_1 .mCSB_dragger .mCSB_dragger_bar{ background-color: red; }
._mCS_2 .mCSB_dragger .mCSB_dragger_bar{ background-color: green; }
#mCSB_3_dragger_vertical .mCSB_dragger_bar{ background-color: blue; }
#mCSB_1_scrollbar_vertical .mCSB_dragger{ height: 100px; }
#mCSB_1_scrollbar_horizontal .mCSB_dragger{ width: 100px; }
.mCSB_1_scrollbar .mCSB_dragger .mCSB_draggerRail{ width: 4px; }
完成音乐信息部分
- html
<div class="content_right"><!-- 右上内容 --><div class="song_info"><!-- 图片 --><a href="javascript:;" class="song_info_pic"><img src="https://s1.ax1x.com/2020/06/20/NQ3rSx.jpg" alt=""></a><div class="song_info_name">歌曲名称:<a href="javascript:;">111</a></div><div class="song_info_singer">歌手名:<a href="javascript:;">222</a></div><div class="song_info_ablum">专辑名:<a href="javascript:;">333</a></div></div><!-- 右下内容 --><div class="song_lyric_container"><ul class="song_lyric"><li class="cur">第一条歌词</li><li>第二条歌词</li></ul></div> </div>
- css
/* 右上内容 */ .content_right .song_info{text-align: center;color: rgba(255,255,255,0.5);line-height: 30px; } .song_info .song_info_pic{display: inline-block;background: url("https://s1.ax1x.com/2020/06/20/NQ3aTJ.png") no-repeat 0 0;width: 201px;height: 180px;text-align: left;border-radius: 50%; } .song_info_pic img{width: 180px;height: 180px;border-radius: 50%; } .song_info div a{text-decoration: none;color: #fff;opacity: 0.5; } .song_info div a:hover{opacity: 1; } /* 右下歌词 */ .content_right .song_lyric_container{margin-top: 30px;height: 150px;overflow: hidden; } .content_right .song_lyric{/* background: greenyellow; */text-align: center;margin-top: 30px;/* overflow: hidden; */ } .content_right .song_lyric li{list-style: none;line-height: 30px;font-weight: bold;color: rgba(255,255,255,0.5); } .content_right .song_lyric .cur{color: #31c27c; }
底部footer
- html
<!-- 底部 --> <div class="footer"><div class="footer_in"><a href="javascript:;" class="music_pre"></a><a href="javascript:;" class="music_play"></a><a href="javascript:;" class="music_next"></a><div class="music_progress_info"><div class="music_progress_top"><span class="music_progress_name">111</span><span class="music_progress_time">00:00 / 05:23</span></div><div class="music_progress_bar"><div class="music_progress_line"><div class="music_progress_dot"></div></div></div></div><a href="javascript:;" class="music_mode"></a><a href="javascript:;" class="music_fav"></a><a href="javascript:;" class="music_down"></a><a href="javascript:;" class="music_comment"></a><a href="javascript:;" class="music_only"></a><div class="music_voice_info"><a href="javascript:;" class="music_voice_icon"></a><div class="music_voice_bar"><div class="music_voice_line"><div class="music_voice_dot"></div></div></div></div></div> </div>
- css
/* 底部 */ .footer{width: 100%;height: 80px;/* background: green; */position: absolute;left: 0;bottom: 0; }/* 版型 */ .footer .footer_in{width: 1200px;height: 100%;/* background: purple; */margin: 0 auto;user-select: none; }.footer_in a{display: inline-block;text-decoration: none;color: #fff;background: url("https://s1.ax1x.com/2020/06/20/NQYwDK.png") no-repeat 0 0;margin-right: 20px; } .footer_in .music_pre{width: 19px;height: 20px;background-position: 0 -30px; } .footer_in .music_play{width: 21px;height: 29px;background-position: 0 0;vertical-align: -5px; } .footer_in .music_play2{background-position: -30px 0; } .footer_in .music_next{width: 19px;height: 20px;background-position: 0 -52px; } .footer_in .music_progress_info{display: inline-block;width: 670px;height: 40px;position: relative;top: 10px; } .music_progress_info .music_progress_top{width: 100%;height: 30px;line-height: 30px;color: #fff; } .music_progress_top .music_progress_name{float: left;opacity: 0.5; } .music_progress_top .music_progress_name:hover{opacity: 1; } .music_progress_top .music_progress_time{float: right;opacity: 0.5; } .music_progress_info .music_progress_bar{width: 100%;height: 4px;background: rgba(255,255,255,0.5);margin-top: 5px;position: relative; } .music_progress_bar .music_progress_line{width: 0px;height: 100%;background: #fff; } .music_progress_line .music_progress_dot{width: 14px;height: 14px;border-radius: 50%;background: #fff;position: absolute;top: -5px;left: 0px; } .footer_in .music_mode{width: 26px;height: 25px;background-position: 0 -205px; } .footer_in .music_mode2{width: 23px;height: 20px;background-position: 0 -260px; } .footer_in .music_mode3{width: 25px;height: 19px;background-position: 0 -74px; } .footer_in .music_mode4{width: 26px;height: 25px;background-position: 0 -232px } .footer_in .music_fav{width: 24px;height: 21px;background-position: 0 -96px; } .footer_in .music_fav2{background-position: -30px -96px; } .footer_in .music_down{width: 22px;height: 21px;background-position: 0 -120px; } .footer_in .music_comment{width: 24px;height: 24px;background-position: 0 -400px; } .footer_in .music_only{width: 74px;height: 27px;background-position: 0 -281px; } .footer_in .music_only2{background-position: 0 -310px; } .footer_in .music_voice_info{display: inline-block;width: 100px;height: 40px;line-height: 40px;position: relative;top: 10px; } .music_voice_info .music_voice_icon{width: 26px;height: 21px;background-position: 0 -144px;position: absolute;left: 0;top: 10px; } .music_voice_info .music_voice_icon2{background-position: 0 -182px; } .music_voice_info .music_voice_bar{width: 70px;height: 4px;background: rgba(255,255,255,0.5);position: absolute;right: 0;top: 18px; } .music_voice_bar .music_voice_line{width: 70px;height: 100%;background: #fff; } .music_voice_line .music_voice_dot{width: 14px;height: 14px;border-radius: 50%;background: #fff;position: relative;top: -5px;left: 70px; }
之后,要加载歌曲
这里就要利用ajax方法
// 1.加载歌曲列表 getPlayerList(); function getPlayerList() {$.ajax({//从哪加载url: "./source/musiclist.json",//加载的是什么类型dataType: "json",// 成功之后做什么success: function (data) {player.musicList = data;// 3.1遍历获取到的数据, 创建每一条音乐var $musicList = $(".content_list ul");$.each(data, function (index, ele) {var $item = crateMusicItem(index, ele);$musicList.append($item);});initMusicInfo(data[0]);initMusicLyric(data[0]);},// 失败之后做什么error: function (e) {console.log(e);}}); } getPlayerList();// 定义一个方法创建一条音乐 function crateMusicItem(index, music) {var $item = $("" +"<li class=\"list_music\">\n" +"<div class=\"list_check\"><i></i></div>\n" +"<div class=\"list_number\">"+(index + 1)+"</div>\n" +"<div class=\"list_name\">"+music.name+"" +" <div class=\"list_menu\">\n" +" <a href=\"javascript:;\" title=\"播放\" class='list_menu_play'></a>\n" +" <a href=\"javascript:;\" title=\"添加\"></a>\n" +" <a href=\"javascript:;\" title=\"下载\"></a>\n" +" <a href=\"javascript:;\" title=\"分享\"></a>\n" +" </div>\n" +"</div>\n" +"<div class=\"list_singer\">"+music.singer+"</div>\n" +"<div class=\"list_time\">\n" +" <span>"+music.time+"</span>\n" +" <a href=\"javascript:;\" title=\"删除\" class='list_menu_del'></a>\n" +"</div>\n" +"</li>");return $item; }
完成音乐播放时图标切换
保证歌曲条目开始或暂停时让底部的保持同步
// 3.添加子菜单播放按钮的监听
var $musicPlay = $(".music_play");
$(".content_list").delegate(".list_menu_play", "click", function () {var $item = $(this).parents(".list_music");// console.log($item.get(0).index);// console.log($item.get(0).music);// 3.1切换播放图标$(this).toggleClass("list_menu_play2");// 3.2复原其它的播放图标//先找点击的祖先list_music,再用siblings()方法找list_music的兄弟 $item.siblings().find(".list_menu_play").removeClass("list_menu_play2");// 3.3同步底部播放按钮if($(this).hasClass("list_menu_play2") !=-1){// 能找到list_menu_play2// 当前子菜单的播放按钮是播放状态$musicPlay.addClass("music_play2"); // 让文字高亮$item.find("div").css("color", "#fff");$item.siblings().find("div").css("color", "rgba(255,255,255,0.5)"); }else{// 当前子菜单的播放按钮不是播放状态$musicPlay.removeClass("music_play2");// 让文字不高亮$item.find("div").css("color", "rgba(255,255,255,0.5)");}
});
播放时的动画效果
// 3.4切换序号的状态 $item.find(".list_number").toggleClass("list_number2"); $item.siblings().find(".list_number").removeClass("list_number2");
播放暂停音乐
- 首先先封装一个工具库player.js,利用这个工具库实现功能
- 插入一个< audio>标签
- 当我们点击音乐键时,调用工具库中播放音乐的方法
- 主要判断是否是同一首音乐
function Player($audio) {return new Player.prototype.init($audio); }Player.prototype = {constructor: Player,musicList: [],init: function ($audio) {this.$audio = $audio;this.audio = $audio.get(0);},currentIndex: -1, // 4 3playMusic: function (index, music) {// 判断是否是同一首音乐if(this.currentIndex == index){// 同一首音乐if(this.audio.paused){this.audio.play();}else{this.audio.pause();}}else {// 不是同一首this.$audio.attr("src", music.link_url);this.audio.play();this.currentIndex = index;}} }
实现底部栏的上一曲/下一曲/暂停
- 上一曲/下一曲
- 当歌曲为第一首时,如果在点击上一曲,要回到最后一首
- 当歌曲为最后一首时,如果在点击下一曲,要回到第一首
// 5.监听底部控制区域上一首按钮的点击 $(".music_pre").click(function () {$(".list_music").eq(player.preIndex()).find(".list_menu_play").trigger("click"); }); // 6.监听底部控制区域下一首按钮的点击 $(".music_next").click(function () {$(".list_music").eq(player.nextIndex()).find(".list_menu_play").trigger("click"); });
- 暂停(判断)
- 点击播放过
- 继续播放
- 没有播放过
- 播放第一首
- 点击播放过
// 4.监听底部控制区域播放按钮的点击 $musicPlay.click(function () {// 判断有没有播放过音乐if(player.currentIndex == -1){// 没有播放过音乐$(".list_music").eq(0).find(".list_menu_play").trigger("click");}else{// 已经播放过音乐$(".list_music").eq(player.currentIndex).find(".list_menu_play").trigger("click");} });
- 上一曲/下一曲
删除音乐操作
- 保证删除后后台数据不能丢失
- 保证删除后顺序不能错乱
// 7.监听删除按钮的点击
$(".content_list").delegate(".list_menu_del", "click", function () {// 找到被点击的音乐var $item = $(this).parents(".list_music");// 判断当前删除的是否是正在播放的if($item.get(0).index == player.currentIndex){$(".music_next").trigger("click");}item.remove();player.changeMusic($item.get(0).index);// 重新排序$(".list_music").each(function (index, ele) {ele.index = index;$(ele).find(".list_number").text(index + 1);});
});
- 歌词的切换
在点击切换上一曲/下一曲/删除后,要随时切换歌曲名称、歌手名、专辑名、歌词和时间等
// 2. 初始化歌曲信息
function initMusicInfo(music) {// 获取对应的元素var $musicImage = $(".song_info_pic img");var $musicName = $(".song_info_name a");var $musicSinger = $(".song_info_singer a");var $musicAblum = $(".song_info_ablum a");var $musicProgressName = $(".music_progress_name");var $musicProgressTime = $(".music_progress_time");var $musicBg = $(".mask_bg");// 给获取的到的元素赋值$musicImage.attr("src", music.cover);$musicName.text(music.name);$musicSinger.text(music.singer);$musicAblum.text(music.album);$musicProgressName.text(music.name + "/" + music.singer);$musicProgressTime.text("00:00 / " + music.time);$musicBg.css("background", 'url("' + music.cover + '")');
}// 3.初始化歌词信息
function initMusicLyric(music){lyric = new Lyric(music.link_lrc);var $lryicContainer = $(".song_lyric");// 清空上一首音乐的歌词$lryicContainer.html("");lyric.loadLyric(function () {// 创建歌词列表$.each(lyric.lyrics, function (index, ele) {var $item = $("<li>"+ele+"</li>");$lryicContainer.append($item);});});
}$.ajax({success: function (data) {initMusicInfo(data[0]);},
});
$(".content_list").delegate(".list_menu_play", "click", function () {// 3.6 切换歌曲信息initMusicInfo($item.get(0).music);
});
进度条
- 时间与进度条同步
musicTimeUpdate: function (callBack) {var $this = this;this.$audio.on("timeupdate", function () {var duration = $this.audio.duration;var currentTime = $this.audio.currentTime;var timeStr = $this.formatDate(currentTime, duration);callBack(currentTime, duration, timeStr);}); }, formatDate: function (currentTime, duration) {var endMin = parseInt(duration / 60); // 2var endSec = parseInt(duration % 60);if(endMin < 10){endMin = "0" + endMin;}if(endSec < 10){endSec = "0" + endSec;}var startMin = parseInt(currentTime / 60); // 2var startSec = parseInt(currentTime % 60);if(startMin < 10){startMin = "0" + startMin;}if(startSec < 10){startSec = "0" + startSec;}return startMin+":"+startSec+" / "+endMin+":"+endSec; }player.musicTimeUpdate(function (currentTime, duration, timeStr) {// 同步时间$(".music_progress_time").text(timeStr); }
- 信息与进度条同步
// 8.监听播放的进度
player.musicTimeUpdate(function (currentTime, duration, timeStr) {// 同步进度条// 计算播放比例var value = currentTime / duration * 100;progress.setProgress(value);// 实现歌词同步var index = lyric.currentIndex(currentTime);var $item = $(".song_lyric li").eq(index);$item.addClass("cur");$item.siblings().removeClass("cur");// 实现歌词滚动if(index <= 2) return;$(".song_lyric").css({marginTop: (-index + 2) * 30});
});
案例代码
下载地址
解决Ajax 跨域问题
什么是Ajax跨域
前端调用后端服务接口时
Ajax跨域原因
- 浏览器限制:浏览器安全校验限制
- 跨域(协议、域名、端口任何一个不一样都会认为是跨域)
- XHR(XMLHttpRequest)请求
解决qq音乐跨域问题
第一种
打开
cmd
,然后找到所在项目目录下,先安装npm install -g live-server
接下来输入
live-server
,回车注意这里默认打开的是index.html
live-server实时简易服务器
第二种
- 如果第一种不想用的话,可以直接用WebStorm,简单方便
- 下载WebStorm
- WebStorm激活码
[jQuery基础] jQuery案例 -- qq音乐以及初步解决Ajax 跨域问题相关推荐
- js请求结果拦截机器_js利用jquery的jsonp来解决ajax跨域请求被浏览器拦截结果的问题...
先来个表.页面太多对不起我也不知道这张表是从哪个博客保存过来的,所以无法注明博客地址.非常抱歉.URL说明是否允许通信 http://www.a.com/a.jshttp://www.a.com/b. ...
- 利用JSONP解决AJAX跨域问题的原理与jQuery解决方案
写在前面 跨域的解决方案有多种,其中最常见的是使用同一服务器下的代理来获取远端数据,再通过ajax进行读取,而在这期间经过了两次请求过程,使得获取数据的效率大大降低,这篇文章蓝飞就为大家介绍一下解决跨 ...
- jQuery利用JSONP解决AJAX跨域请求
出于安全方面的考虑,页面中的JavaScript无法访问其他服务器上的数据,即"同源策略".而跨域就是通过某些手段来绕过同源策略限制,实现不同服务器之间通信的效果. JSON(Ja ...
- 普元EOS中, 子系统和portal不在同一个域中,使用jquery的jsonp来解决portal跨域访问
转至元数据起始 [背景] 子系统和portal不在同一个域中且项目中要求不能使用nginx.apache等反向代理软件,故使用jsonp从代码角度解决ajax跨域问题 [实现思路] 通过jquery的 ...
- jQuery中的ajax、jquery中ajax全局事件、load实现页面无刷新局部加载、ajax跨域请求jsonp、利用formData对象向服务端异步发送二进制数据,表单序列化(异步获取表单内容)
jQuery中使用ajax: 在jQuery中使用ajax首先需要引入jQuery包,其引入方式可以采用网络资源,也可以下载包到项目文件中,这里推荐下载包到文件中:市面上有多个版本的jQuery库,这 ...
- JQuery实现Ajax跨域访问--Jsonp原理
JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为"Same-Origin Policy"(同源策略). ...
- ajax 跨域请求数据,JQuery Ajax执行跨域请求数据的解决方案
JQuery Ajax执行跨域请求数据的解决方案 今天前端因为需要ajax调用两个不同的项目,请求域不一样,所以涉及ajax跨域的问题 ,其实很简单,具体如下 原来的ajax请求如下: $.ajax( ...
- Jetty Cross Origin Filter解决jQuery Ajax跨域访问的方法
当使用jQuery Ajax post请求时可能会遇到类似这样的错误提示 XMLHttpRequest cannot load http://xxxxxx. Origin http://xxxxxx ...
- PHP+JQuery实现ajax跨域
jQuery实现ajax跨域 1.dataType:'jsonp' 2.type: 'get' 3.把要传的参数以url方式传出去 url:'http://gameapi.feiliu.com/lq ...
最新文章
- FutureTask 实现预加载数据 在线看电子书、浏览器浏览网页等
- 【Android 安全】DEX 加密 ( Proguard 简介 | 默认 ProGuard 分析 )
- ML:MLOps系列讲解之《端到端 ML工作流生命周期》解读
- Atcoder AGC031C Differ By 1 Bit (构造、二进制)
- java 选中当前,Java开发网 - 请问如何获得SWT中List widget当前选中的项目
- python状态码及其含义_Shell退出状态码及其应用详解
- HashMap的小知识点
- 加快网站速度的最佳做法_(3)script脚本放在底部
- stm32单片机屏幕一直闪_STM32物联网实战项目 - 项目需求
- react,react-router,redux+react-redux 构建一个React Demo
- SylixOS SylixOS CAN总线驱动之三
- app邀请分享免填邀请码解决方案-邀请机制的要点、形式
- Reporter对象的几个鲜为人知的方法
- java求面积_Java计算几何图形的面积
- Error while importing package: Couldn’t decompress package
- 文件压缩zip(浏览器下载)
- Testlink使用文档
- DRV8824,DRV8825新的解决方案
- c语言tcp实现网络断点续传,简单实现tcp/ip下的文件断点续传
- html格式发邮件,怎么用HTML格式发送邮件.既怎么发HTML格式的邮件?