这是一个练习的小案例,支持在线搜索,调用的是免费的音乐接口,html
主要用到了:弹性盒,3D效果,Ajax 等技术前端
效果以下:ajax
接口地址: https://api.apiopen.top/searchMusicjson
请求示例: https://api.apiopen.top/searchMusic?name=雅俗共赏后端
请求结果:api
{ "author": "许嵩", "link": "http://music.163.com/#/song?id=411214279", "pic": "http://p2.music.126.net/Wcs2dbukFx3TUWkRuxVCpw==/3431575794705764.jpg?param=300x300", "type": "netease", "title": "雅俗共赏", "lrc": "", "songid": 411214279, "url": "http://music.163.com/song/media/outer/url?id=411214279.mp3" }
总体采用三段式样式,分为左中右三块,数组
左侧为装饰性样式没有实际做用,计划添加 点击切换歌词面板功能app
中间部分为播放器主体,包括搜索框,搜索按钮,歌曲封面,歌曲名,做者,以及audio播放器,ide
右侧没有进行功能添加,计划添加喜欢收藏 下一首 上一首 分享 。函数
HTM代码以下:
<body> <div id="box"> <!-- 搜索信息展现版块 ==>默认display:none --> <div id="display"> <div class="close"><span>X</span></div> <h2>歌曲列表</h2> <div id="infoBox"> <!-- <p>歌曲名-Redbone <span>听这首</span></p> --> </div> </div> <!-- 左侧版块 --> <div class="leftBg"> <!-- 滚动信息 --> <marquee behavior="scroll" direction="left">Current version of Baidu Music Interface</marquee> <!-- 文字 ==> THIS IS MUSIC --> <p class="p1">THIS <br>IS </p> <p class="p2">MUSIC</p> <!-- 白色装饰条 --> <div></div> <div></div> </div> <!-- 中间板块 --> <div class="centerBg"> <!-- 搜索框+搜索按钮 --> <input type="text" value="" id="search"><span id="searchSpan">搜索</span> <div id="bfBox"> <!-- 歌曲图片 --> <div class="imgBox"> <img src="http://p2.music.126.net/5i5SKVW_F1ub2BgDeyjI5A==/3225967119049341.jpg?param=300x300" alt=""> </div> <!-- 歌曲信息 --> <div class="info"> <p>Come and Get Your Love</p> <p>Redbone</p> <!-- 播放器 --> <audio src="http://music.163.com/song/media/outer/url?id=28864241.mp3" controls></audio> </div> </div> </div> <!-- 右侧板块 ==> 未开发 --> <div class="rightBg"> </div> </div> </body>
CSS代码以下:
<style> body{ /* 开启视距 */ perspective: 1400px; position: relative; } /* 主页面 */ #box{ width: 800px; height:500px; background-color: rgb(255, 255, 255); margin: 80px auto; /* transition: 2s; */ /* 开启3D空间 */ transform-style: preserve-3d; display: flex; justify-content: flex-start; box-shadow: 0 15px 35px -5px rgba(50,88,130,.32); } /* 左侧版块 */ #box .leftBg{ width: 190px; height: 440px; background-color: #222; padding: 30px; position: relative; } /* 中间板块 */ #box .centerBg{ width: 500px; height: 500px; background-color: rgb(241, 241, 241); } /* 右侧版块 */ #box .rightBg{ width: 100px; height: 500px; background-color: #222; } /* 左侧滚动信息 */ #box .leftBg marquee{ margin-top: 15px; color: #fff; font-size: 12px; } /* 左侧文字 ==> THIS IS MUSIC */ #box .leftBg p{ transform: translateZ(100px) } #box .leftBg .p1{ color: rgb(253, 0, 0); font-size: 50px; margin: 0; padding-top:50px; } #box .leftBg .p2 { color: rgb(253, 0, 0); font-size: 75px; font-weight: bold; margin: 10px auto; } /* 左侧装饰条两根 */ #box .leftBg div{ width: 100%; height: 5px; background-color: rgb(241, 241, 241); position: absolute; } #box .leftBg div:nth-child(4){ left: 0; bottom:60px; } #box .leftBg div:nth-child(5){ left: 0; bottom:45px; } /* 搜索框样式 */ #box #search{ outline:none; border: none; width: 250px; height: 25px; border-top-left-radius: 30px; border-bottom-left-radius: 30px; background-color: #fff; margin-top: 20px; margin-left: 50px; padding: 5px 15px; } /* 搜索按钮样式 */ #box #searchSpan{ display: inline-block; padding: 5px 15px; width: 25px; height: 25px; text-align: center; line-height: 25px; background-color: #222; color: #fff; font-size: 12px; border-top-right-radius: 30px; border-bottom-right-radius: 30px; cursor: pointer; } /* 中间板块 播放器盒子 */ #box .centerBg #bfBox{ width: 240px; height: 330px; border-radius: 10px; background-color: #eef3f7; margin-left:130px; margin-top: 20px; position: relative; box-shadow: 0 15px 35px -5px rgba(50,88,130,.32); display: flex; align-items: flex-end; padding: 30px; } /* 歌曲图片样式 */ #box .centerBg .imgBox{ width: 160px; height: 160px; border-radius: 10px; position: absolute; top: 30px; left: -30px; box-shadow: 0 10px 20px 0 rgba(76,70,124,.5); transform: translateZ(100px) } #box .centerBg .imgBox img{ width: 160px; height: 160px; border-radius: 5px; } /* 歌曲信息样式 */ #box .centerBg #bfBox .info { width: 100%; height: 45%; } #box .centerBg #bfBox .info p{ margin: 0; color:#71829e; } #box .centerBg #bfBox .info p{ margin-top:15px; font-size: 20px; font-weight: bolder; } #box .centerBg #bfBox .info p:nth-of-type(2){ margin-top: 5px; font-size: 16px; } /* audio播放器样式 */ #box .centerBg #bfBox .info audio{ width: 100%; padding-top: 10px; outline:none; } /* 搜索展现界面样式 */ #display{ width: 400px; height: 500px; background-color: rgb(245, 238, 238); box-shadow: 0 10px 20px 0 rgba(76,70,124,.5); display: none; border-radius: 10px; position: absolute; top: 0; left: 25%; transform: translateZ(110px); padding: 30px; } /* 搜索展现界面 标题====>(歌曲列表) */ #display h2{ text-align: center; color: rgb(255, 0, 0); } #display p { color: #607391; font-size: 12px; margin: 5px; 0; padding:0 10px; height: 35px; line-height: 35px; } #display p:hover{ background-color: #fff; } #display p span { margin-top: 5px; float: right; width: 45px; height: 25px;; box-sizing: border-box; border-radius: 5px; background-color: rgb(55, 110, 214); box-shadow: inset 1px 1px 5px 0px rgba(50,88,130,.32); text-align: center; line-height: 25px; font-size: 12px; color: #ccc; cursor: pointer; } /* 展现版块关闭按钮样式 */ #display .close{ position: relative; } #display .close span{ width: 30px; height: 30px; border-radius: 50%; position: absolute; top: 10px; right: 10px; background-color: lightblue; box-shadow: inset 1px 1px 5px 0px rgba(50,88,130,.32); text-align: center; line-height: 30px; cursor: pointer; } </style>
视差滚动(Parallax Scrolling)是指让多层背景以不一样的速度移动,造成立体的运动效果,带来很是出色的视觉体验。做为网页设计的热点趋势,愈来愈多的网站应用了这项技术。
这是借鉴了视差滚动的原理,使页面产生实时改变的3D效果,具体实现以下:
1.思路:
将播放器开启3D空间,
在鼠标横向移动时,让播放器沿Y轴旋转,在鼠标纵向移动时,让播放器沿X轴旋转,
将视距增大至1400(此时的视距刚恰好)。
2.代码实现:
//body{perspective: 1400px;} 开启视距 // 鼠标在body上移动,将坐标转换成旋转角度,造成视差 document.onmousemove = function (eve){ var e = eve || window.event; that.x = (e.clientX-that.ele.offsetWidth/2)*0.01; that.y = -(e.clientY-that.ele.offsetTop/2)*0.01;; that.display(); } //造成视差 display(){ this.box.style.transform = "rotateY(" + this.x + "deg) rotateX(" + this.y + "deg)"; }
控制台信息:
ajax是前端向后端请求发送数据的重要手段,而且能够实现无刷新加载数据。
该案例使用的接口返回的数据是json,使用ajax能够正确的解析数据
1.思路:
当用户点击搜索按钮时,获取输入框的数据,拼接到接口地址上
使用ajax请求拼接好的地址,拿到数据
2.实现以下:
//搜索框发生改变,生成搜索内容 this.searchBtn.onclick = function(){ var str = ""; that.url = "https://api.apiopen.top/searchMusic"; str = "?name="+that.text.value; that.url += str; that.load(); } // ajax请求数据 load(){ var that = this; ajax({ url:this.url, success:function(res){ that.res = JSON.parse(res); console.log(that.res.result); } }) }
这里使用的是封装好的ajax函数,函数以下
//ajax封装函数 function ajax(options) { var { type, url, success, error, data, timeout } = options; type = type || "get"; data = data || {}; timeout = timeout || 2000; var str = ""; for (var i in data) { str += `${i}=${data[i]}&`; } if (type == "get") { var d = new Date(); url = url + "?" + str + "__qft=" + d.getTime(); } var xhr = new XMLHttpRequest(); xhr.open(type, url, true); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { success && success(xhr.responseText); error = null; } else if (xhr.readyState == 4 && xhr.status != 200) { error && error(xhr.status); success = null; error = null; } } setTimeout(() => { error && error("timeout"); success = null; }, timeout); if (type == "post") { xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhr.send(str) } else { xhr.send() } }
请求到的数据以下
这里咱们须要的是result数组中的信息
因此console.log(that.res.result);获得正确的数据
获得数据以后下面要作的就是将请求到的数据展现出来
在页面结构中,有展现页面的结构,需求是点击搜索按钮,展现页面将数据展现出来
展现格式为:歌曲名-歌手 而且能够选择指定歌曲播放
1.思路:
点击搜索按钮后,展现页面显示(dispaly:“block”),
将数据拼接为HTML代码插入到展现页面中,
给全部的信息绑定事件,点击信息记录当前信息的索引(可使用事件委托优化性能)。
2.代码实现:
//生成搜索内容 //请求完成,得到数据,将数据展现到搜索页面上 display2(){ this.displayPage.style.display = "block" var str = ""; // 若是搜索为空,显示搜索内容为空 //不然,展现搜索内容 if(this.res.result.length == 0){ str = "<h3>搜索内容为空</h3>" }else{ for(var i=0;i<this.res.result.length;i++){ str+=`<p>${this.res.result[i].title}-${this.res.result[i].author} <span>听这首</span></p>` } } this.infoBox.innerHTML = str; this.change(); this.disClose(); } //点击选中的歌曲,改变播放器页面的信息 change(){ var that = this; this.span = document.querySelectorAll("#infoBox p span"); console.log(this.span); // 遍历全部的歌曲span,找到点击所在的索引,保存到num中 //同时:若是选中了歌曲,就关闭搜索展现页面 for(var i=0;i<this.span.length;i++){ this.span[i].index = i; this.span[i].onclick = function (){ this.num = that.span[this.index].index that.reMove(); that.display3(this.num); // console.log(this.num); } } }
点击关闭按钮后,或者选择完成歌曲后,咱们须要关闭展现页面
1.思路:
点击关闭很简单实现,选择关闭须要咱们调用点击关闭的子方法
2.代码实现:
// 关闭按钮方法 ===> 点击关闭按钮(disPageClose) 执行关闭搜索页面 disClose(){ var that = this; this.disPageClose.onclick = function(){ that.reMove(); } } //移除方法 ====> 执行该函数,清空搜索界面全部内容,并隐藏 reMove(){ this.displayPage.style.display = "none"; this.infoBox.innerHTML = ""; }
展现界面以下:
在选择歌曲后,须要根据选择的歌曲改变播放器的封面图 歌曲名 歌手名 以及要播放的歌曲
1.思路:
查看请求的数据咱们知道(以搜索成都为例),根据数据的键名能够找到咱们须要的信息
{ author: "赵雷" link: "http://music.163.com/#/song?id=436514312" lrc: "" pic: "http://p1.music.126.net/34YW1QtKxJ_3YnX9ZzKhzw==/2946691234868155.jpg?param=300x300" songid: 436514312 title: "成都" type: "netease" url: "http://music.163.com/song/media/outer/url?id=436514312.mp3" }
故而须要将数据写入播放器的html中
2.代码实现:
//播放器音乐信息展现方法 ===> 将ajax请求到的数据,写入到播放内容区(bfBox) display3(num){ var str = ""; for(var i=0;i<this.res.result.length;i++){ str = `<div class="imgBox"> <img src="${this.res.result[num].pic}" alt=""> </div> <div class="info"> <p>${this.res.result[num].title}</p> <p>${this.res.result[num].author}</p> <audio src="${this.res.result[num].url}" controls></audio> </div>` } this.bfBox.innerHTML = str; }
因为使用的是H5的audio标签,这时咱们就完成了,播放器的基本功能。
完整代码以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> body{ /* 开启视距 */ perspective: 1400px; position: relative; } /* 主页面 */ #box{ width: 800px; height:500px; background-color: rgb(255, 255, 255); margin: 80px auto; /* transition: 2s; */ /* 开启3D空间 */ transform-style: preserve-3d; display: flex; justify-content: flex-start; box-shadow: 0 15px 35px -5px rgba(50,88,130,.32); } /* 左侧版块 */ #box .leftBg{ width: 190px; height: 440px; background-color: #222; padding: 30px; position: relative; } /* 中间板块 */ #box .centerBg{ width: 500px; height: 500px; background-color: rgb(241, 241, 241); } /* 右侧版块 */ #box .rightBg{ width: 100px; height: 500px; background-color: #222; } /* 左侧滚动信息 */ #box .leftBg marquee{ margin-top: 15px; color: #fff; font-size: 12px; } /* 左侧文字 ==> THIS IS MUSIC */ #box .leftBg p{ transform: translateZ(100px) } #box .leftBg .p1{ color: rgb(253, 0, 0); font-size: 50px; margin: 0; padding-top:50px; } #box .leftBg .p2 { color: rgb(253, 0, 0); font-size: 75px; font-weight: bold; margin: 10px auto; } /* 左侧装饰条两根 */ #box .leftBg div{ width: 100%; height: 5px; background-color: rgb(241, 241, 241); position: absolute; } #box .leftBg div:nth-child(4){ left: 0; bottom:60px; } #box .leftBg div:nth-child(5){ left: 0; bottom:45px; } /* 搜索框样式 */ #box #search{ outline:none; border: none; width: 250px; height: 25px; border-top-left-radius: 30px; border-bottom-left-radius: 30px; background-color: #fff; margin-top: 20px; margin-left: 50px; padding: 5px 15px; } /* 搜索按钮样式 */ #box #searchSpan{ display: inline-block; padding: 5px 15px; width: 25px; height: 25px; text-align: center; line-height: 25px; background-color: #222; color: #fff; font-size: 12px; border-top-right-radius: 30px; border-bottom-right-radius: 30px; cursor: pointer; } /* 中间板块 播放器盒子 */ #box .centerBg #bfBox{ width: 240px; height: 330px; border-radius: 10px; background-color: #eef3f7; margin-left:130px; margin-top: 20px; position: relative; box-shadow: 0 15px 35px -5px rgba(50,88,130,.32); display: flex; align-items: flex-end; padding: 30px; } /* 歌曲图片样式 */ #box .centerBg .imgBox{ width: 160px; height: 160px; border-radius: 10px; position: absolute; top: 30px; left: -30px; box-shadow: 0 10px 20px 0 rgba(76,70,124,.5); transform: translateZ(100px) } #box .centerBg .imgBox img{ width: 160px; height: 160px; border-radius: 5px; } /* 歌曲信息样式 */ #box .centerBg #bfBox .info { width: 100%; height: 45%; } #box .centerBg #bfBox .info p{ margin: 0; color:#71829e; } #box .centerBg #bfBox .info p{ margin-top:15px; font-size: 20px; font-weight: bolder; } #box .centerBg #bfBox .info p:nth-of-type(2){ margin-top: 5px; font-size: 16px; } /* audio播放器样式 */ #box .centerBg #bfBox .info audio{ width: 100%; padding-top: 10px; outline:none; } /* 搜索展现界面样式 */ #display{ width: 400px; height: 500px; background-color: rgb(245, 238, 238); box-shadow: 0 10px 20px 0 rgba(76,70,124,.5); display: none; border-radius: 10px; position: absolute; top: 0; left: 25%; transform: translateZ(110px); padding: 30px; } /* 搜索展现界面 标题====>(歌曲列表) */ #display h2{ text-align: center; color: rgb(255, 0, 0); } #display p { color: #607391; font-size: 12px; margin: 5px; 0; padding:0 10px; height: 35px; line-height: 35px; } #display p:hover{ background-color: #fff; } #display p span { margin-top: 5px; float: right; width: 45px; height: 25px;; box-sizing: border-box; border-radius: 5px; background-color: rgb(55, 110, 214); box-shadow: inset 1px 1px 5px 0px rgba(50,88,130,.32); text-align: center; line-height: 25px; font-size: 12px; color: #ccc; cursor: pointer; } /* 展现版块关闭按钮样式 */ #display .close{ position: relative; } #display .close span{ width: 30px; height: 30px; border-radius: 50%; position: absolute; top: 10px; right: 10px; background-color: lightblue; box-shadow: inset 1px 1px 5px 0px rgba(50,88,130,.32); text-align: center; line-height: 30px; cursor: pointer; } </style> </head> <body> <div id="box"> <!-- 搜索信息展现版块 ==>默认display:none --> <div id="display"> <div class="close"><span>X</span></div> <h2>歌曲列表</h2> <div id="infoBox"> <!-- <p>歌曲名-Redbone <span>听这首</span></p> --> </div> </div> <!-- 左侧版块 --> <div class="leftBg"> <!-- 滚动信息 --> <marquee behavior="scroll" direction="left">Current version of Baidu Music Interface</marquee> <!-- 文字 ==> THIS IS MUSIC --> <p class="p1">THIS <br>IS </p> <p class="p2">MUSIC</p> <!-- 白色装饰条 --> <div></div> <div></div> </div> <!-- 中间板块 --> <div class="centerBg"> <!-- 搜索框+搜索按钮 --> <input type="text" value="" id="search"><span id="searchSpan">搜索</span> <div id="bfBox"> <!-- 歌曲图片 --> <div class="imgBox"> <img src="http://p2.music.126.net/5i5SKVW_F1ub2BgDeyjI5A==/3225967119049341.jpg?param=300x300" alt=""> </div> <!-- 歌曲信息 --> <div class="info"> <p>Come and Get Your Love</p> <p>Redbone</p> <!-- 播放器 --> <audio src="http://music.163.com/song/media/outer/url?id=28864241.mp3" controls></audio> </div> </div> </div> <!-- 右侧板块 ==> 未开发 --> <div class="rightBg"> </div> </div> </body> <!-- <script src="./js/ajax.js"></script> --> <script> class Music{ constructor(ele){ this.ele = ele; this.box = document.getElementById("box"); this.text = document.getElementById("search"); this.bfBox = document.getElementById("bfBox"); this.url = "https://api.apiopen.top/searchMusic"; this.infoBox = document.getElementById("infoBox"); this.displayPage = document.getElementById("display"); this.disPageClose = document.querySelector("#display .close span"); this.searchBtn = document.getElementById("searchSpan"); this.addEvent(); } // 绑定事件函数 addEvent(){ var that = this; // 鼠标在body上移动,将坐标转换成旋转角度,造成视差 document.onmousemove = function (eve){ var e = eve || window.event; that.x = (e.clientX-that.ele.offsetWidth/2)*0.01; that.y = -(e.clientY-that.ele.offsetTop/2)*0.01;; that.display(); } //搜索框发生改变,生成搜索内容 this.searchBtn.onclick = function(){ var str = ""; that.url = "https://api.apiopen.top/searchMusic"; str = "?name="+that.text.value; that.url += str; that.load(); } } // ajax请求数据 load(){ var that = this; ajax({ url:this.url, success:function(res){ that.res = JSON.parse(res); console.log(that.res.result); that.display2(); } }) } //造成视差 display(){ this.box.style.transform = "rotateY(" + this.x + "deg) rotateX(" + this.y + "deg)"; } //生成搜索内容 //请求完成,得到数据,将数据展现到搜索页面上 display2(){ this.displayPage.style.display = "block" var str = ""; // 若是搜索为空,显示搜索内容为空 //不然,展现搜索内容 if(this.res.result.length == 0){ str = "<h3>搜索内容为空</h3>" }else{ for(var i=0;i<this.res.result.length;i++){ str+=`<p>${this.res.result[i].title}-${this.res.result[i].author} <span>听这首</span></p>` } } this.infoBox.innerHTML = str; this.change(); this.disClose(); } //点击选中的歌曲,改变播放器页面的信息 change(){ var that = this; this.span = document.querySelectorAll("#infoBox p span"); console.log(this.span); // 遍历全部的歌曲span,找到点击所在的索引,保存到num中 //同时:若是选中了歌曲,就关闭搜索展现页面 for(var i=0;i<this.span.length;i++){ this.span[i].index = i; this.span[i].onclick = function (){ this.num = that.span[this.index].index that.reMove(); that.display3(this.num); // console.log(this.num); } } } // 关闭按钮方法 ===> 点击关闭按钮(disPageClose) 执行关闭搜索页面 disClose(){ var that = this; this.disPageClose.onclick = function(){ that.reMove(); } } //移除方法 ====> 执行该函数,清空搜索界面全部内容,并隐藏 reMove(){ this.displayPage.style.display = "none"; this.infoBox.innerHTML = ""; } //播放器音乐信息展现方法 ===> 将ajax请求到的数据,写入到播放内容区(bfBox) display3(num){ var str = ""; for(var i=0;i<this.res.result.length;i++){ str = `<div class="imgBox"> <img src="${this.res.result[num].pic}" alt=""> </div> <div class="info"> <p>${this.res.result[num].title}</p> <p>${this.res.result[num].author}</p> <audio src="${this.res.result[num].url}" controls></audio> </div>` } this.bfBox.innerHTML = str; } } //ajax封装函数 function ajax(options) { var { type, url, success, error, data, timeout } = options; type = type || "get"; data = data || {}; timeout = timeout || 2000; var str = ""; for (var i in data) { str += `${i}=${data[i]}&`; } if (type == "get") { var d = new Date(); url = url + "?" + str + "__qft=" + d.getTime(); } var xhr = new XMLHttpRequest(); xhr.open(type, url, true); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { success && success(xhr.responseText); error = null; } else if (xhr.readyState == 4 && xhr.status != 200) { error && error(xhr.status); success = null; error = null; } } setTimeout(() => { error && error("timeout"); success = null; }, timeout); if (type == "post") { xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhr.send(str) } else { xhr.send() } } var body = document.body; new Music(body); </script> </html>