在这一个月期间跟着逆战班级做的一个基于vue的音乐App项目
项目目录结构如下:
public文件夹用于存放公用文件、src用于存放项目源代码
1、App组件代码
<template>
<div id="app">
<Header></Header>
<Nav></Nav>
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
</div>
</template>
<script>
import Header from "./components/Header/Header";
import Nav from "./components/Nav/Nav";
export default {
data() {
return {};
},
components: {
Header,
Nav
}
};
</script>
<style lang="less" scoped>
@import "./style/reset.css";
</style>
3、路由结构
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import Recommend from '../components/Recommend';
import Singer from '../components/Singer/index.vue';
import Ranking from '../components/Ranking'
import Search from '../components/Search'
const router = new VueRouter({
routes: [
{
path: '/recommend',
component: Recommend,
meta: {
keepAlive: true
}
},
{
path: '/singer',
component: Singer,
meta: {
keepAlive: true
}
},
{
path: '/ranking',
component: Ranking,
meta: {
keepAlive: true
}
},
{
path: '/search',
component: Search,
meta: {
keepAlive: true
}
},
{
path: '/',
redirect: '/recommend',
meta: {
keepAlive: true
}
}
]
})
export default router
4、推荐页面(Recommend)代码如下(包含Content 、Swiper两个组件)
Recommend页面
<!-- -->
<template>
<div class="wrapper">
<div class="test">
<Swiper></Swiper>
<Content></Content>
</div>
</div>
</template>
<script>
import Swiper from "./Swiper";
import Content from "./recommend-cont";
import BScorll from "better-scroll";
export default {
//import引入的组件需要注入到对象中才能使用
components: {
Swiper,
Content
},
data() {
//这里存放数据
return {};
},
//监听属性 类似于data概念
computed: {},
//监控data中的数据变化
watch: {},
//方法集合
methods: {
init() {
new BScorll(".wrapper", {});
}
},
mounted() {
this.init();
}
};
</script>
<style scoped>
.wrapper {
position: fixed;
top: 120px;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
.wrapper .test {
height: auto;
}
</style>
Content 组件
<template>
<div class="cont_box">
<h5>热门歌单推荐</h5>
<div class="cont">
<ul>
<li v-for="item in list" :key="item.dissid">
<div class="cont-left">
<img v-lazy="item.imgurl" alt />
</div>
<div class="cont-right">
<span class="con_title">{{item.creator.name}}</span>
<p class="con_all">{{item.dissname}}</p>
</div>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
//import引入的组件需要注入到对象中才能使用
components: {},
data() {
//这里存放数据
return {
list: []
};
},
//监听属性 类似于data概念
computed: {},
//监控data中的数据变化
watch: {},
//方法集合
methods: {},
//生命周期 - 创建完成(可以访问当前this实例)
created() {
let url =
"/api/getDiscList?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8¬ice=0&format=json&platform=yqq&hostUin=0&sin=0&ein=29&sortId=5&needNewCode=0&categoryId=10000000&rnd=0.7841041983308066";
this.$axios.get(url).then(res => {
this.list = res.data.list;
});
},
mounted() {}
};
</script>
<style lang="less" scoped>
@import "../../style/mixin.less";
ul li {
.w(375);
height: 60px;
padding: 13px;
list-style: none;
}
.cont_box h5 {
.w(375);
height: 65px;
text-align: center;
line-height: 65px;
color: #ffcd32;
font-size: 14px;
}
.cont_box h3 {
color: #fff;
}
.cont-left {
float: left;
height: 60px;
}
.cont_box img {
width: 60px;
height: 60px;
}
.cont-right {
float: left;
height: 60px;
}
.con_title {
display: block;
color: #fff;
font-size: 14px;
margin-top: 10px;
margin-left: 20px;
}
.con_all {
color: #888;
font-size: 13px;
margin-left: 20px;
margin-top: 10px;
}
</style>
Swiper(轮播图组件),这里采用了swiper插件来实现(具体使用方法请访问https://www.swiper.com.cn/)
<template>
<div id="swiper">
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="(item,index) in imgSrc" :key="index">
<img :src="item.picUrl" alt />
</div>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
</template>
<script>
import Swiper from "swiper";
export default {
data() {
return {
imgSrc: []
};
},
created() {
let url =
"/api/getTopBanner?g_tk=1928093487&inCharset=utf8&outCharset=utf-8¬ice=0&format=json&platform=yqq.json&hostUin=0&needNewCode=0&-=recom7744651407995646&data=%7B%22comm%22:%7B%22ct%22:24%7D,%22category%22:%7B%22method%22:%22get_hot_category%22,%22param%22:%7B%22qq%22:%22%22%7D,%22module%22:%22music.web_category_svr%22%7D,%22recomPlaylist%22:%7B%22method%22:%22get_hot_recommend%22,%22param%22:%7B%22async%22:1,%22cmd%22:2%7D,%22module%22:%22playlist.HotRecommendServer%22%7D,%22playlist%22:%7B%22method%22:%22get_playlist_by_category%22,%22param%22:%7B%22id%22:8,%22curPage%22:1,%22size%22:40,%22order%22:5,%22titleid%22:8%7D,%22module%22:%22playlist.PlayListPlazaServer%22%7D,%22new_song%22:%7B%22module%22:%22newsong.NewSongServer%22,%22method%22:%22get_new_song_info%22,%22param%22:%7B%22type%22:5%7D%7D,%22new_album%22:%7B%22module%22:%22newalbum.NewAlbumServer%22,%22method%22:%22get_new_album_info%22,%22param%22:%7B%22area%22:1,%22sin%22:0,%22num%22:10%7D%7D,%22new_album_tag%22:%7B%22module%22:%22newalbum.NewAlbumServer%22,%22method%22:%22get_new_album_area%22,%22param%22:%7B%7D%7D,%22toplist%22:%7B%22module%22:%22musicToplist.ToplistInfoServer%22,%22method%22:%22GetAll%22,%22param%22:%7B%7D%7D,%22focus%22:%7B%22module%22:%22QQMusic.MusichallServer%22,%22method%22:%22GetFocus%22,%22param%22:%7B%7D%7D%7D";
this.$axios.get(url).then(res => {
this.imgSrc = res.data.slider;
this.$nextTick(() => {
this.init();
});
});
},
methods: {
init() {
new Swiper(".swiper-container", {
direction: "horizontal",
loop: true,
autoplay: true,
pagination: {
el: ".swiper-pagination",
bulletActiveClass: "my-bullet-active"
}
});
}
}
};
</script>
<style lang="less" scoped>
@import "~swiper/css/swiper.min.css";
@import "../../style/mixin.less";
.swiper-container {
.w(375);
.h(150);
}
.swiper-slide img {
.w(375);
.h(150);
}
.my-bullet-active {
background: #fff;
opacity: 0.6;
}
</style>
效果图
5、歌手页面(Singer)
这里的难点
1、首先处理后台返回的数据
2、实现滚动屏幕、右边的字母跟着滚动
3、点击右边的字母,左边歌手列表跳到对应的位置
4、点击字母不放手向上或向下滚动、左边对应跟着滚动
实现代码如下
<template>
<div class="singer">
<div class="wrapper" ref="wrapper">
<div class="content">
<ul>
<li :ref="item.Findex" v-for="(item,index) in singerData" :key="index">
<div class="name_type">{{item.Findex}}</div>
<div class="singer_info" v-for="(singer_info,index) in item.list" :key="index">
<img v-lazy="singer_info.imgsrc" alt />
<div class="singer_name">{{singer_info.Fsinger_name}}</div>
</div>
</li>
</ul>
</div>
</div>
<div class="slider">
<ul>
<li
@click="jump(item)"
:class="state==item? 'slider-active' :''"
v-for="(item,index) in slideData"
:key="index"
>{{item}}</li>
</ul>
</div>
</div>
</template>
<script>
import { nomalData } from "./index.js";
import Bs from "better-scroll";
export default {
//import引入的组件需要注入到对象中才能使用
components: {},
data() {
//这里存放数据
return {
singerData: [],
state: "hot"
};
},
created() {
// 发请求,这里没有用jsonp插件所以根据axios请求回来的数据进行处理
let url =
"/v8/fcg-bin/v8.fcg?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8¬ice=0&format=jsonp&channel=singer&page=list&key=all_all_all&pagesize=100&pagenum=1&hostUin=0&needNewCode=0&platform=yqq&jsonpCallback=jp0";
this.$axios.get(url).then(res => {
let str = res.replace(/jp0\(/g, "");
let newdata = JSON.parse(str.replace(/\)/g, ""));
newdata.data.list.forEach(el => {
el.imgsrc = `https://y.gtimg.cn/music/photo_new/T001R300x300M000${el.Fsinger_mid}.jpg?max_age=2592000`;
});
let result = nomalData(newdata.data.list);
// 把处理好的数据存进组件共有数据里
this.singerData = result;
this.$nextTick(() => {
// 页面渲染好后初始化better-scroll
this.init();
});
});
},
computed: {
slideData() {
let result = this.singerData.map(item => {
return item.Findex;
});
return result;
}
},
methods: {
// 定义初始化better-scroll方法
init() {
this.bscroll = new Bs(this.$refs.wrapper, {
probeType: 3,
click: true, //点击
pullUpLoad: true //上拉加载更多
});
let disposition = [];
for (const key in this.$refs) {
if (key != "wrapper") {
disposition.push(this.$refs[key][0].offsetTop);
}
}
// 监听滚动来实现对应滚动监听功能
this.bscroll.on("scroll", position => {
let pos = parseInt(position.y * -1);
for (let index = 0; index < disposition.length; index++) {
if (pos >= disposition[index] && pos <= disposition[index + 1]) {
this.state = this.slideData[index];
}
}
});
},
// 此方法用于点击后跳转到对应的地方
jump(item) {
let targe = this.$refs[item][0];
console.log(targe);
this.bscroll.scrollToElement(targe);
}
},
mounted() {}
};
</script>
<style scoped>
.wrapper {
position: fixed;
top: 100px;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
.wrapper .content {
margin-top: 20px;
}
.name_type {
width: 100%;
height: 21px;
color: hsla(0, 0%, 100%, 0.5);
background: #333;
padding: 9px;
font-size: 14px;
}
.singer_info {
width: 100%;
height: 50px;
padding: 20px;
}
.singer_info img {
height: 50px;
width: 50px;
border-radius: 50%;
display: block;
float: left;
}
.singer_name {
float: left;
color: hsla(0, 0%, 100%, 0.5);
font-size: 13px;
padding: 15px;
}
.slider {
width: 20px;
height: 466px;
position: absolute;
right: 5px;
top: 150px;
background: rgba(0, 0, 0, 0.3);
border-radius: 7px;
}
.slider li {
list-style: none;
color: hsla(0, 0%, 100%, 0.5);
font-size: 12px;
padding-top: 4px;
text-align: center;
}
.slider .slider-active {
color: yellow;
}
</style>
效果图
6、排行页面(Ranking)
代码如下
<!-- -->
<template>
<div class="wrapper">
<div class="content">
<div class="box" v-for="(item,index) in rankdata" :key="index">
<div class="left">
<img v-lazy="item.picUrl" alt />
</div>
<div class="right">
<ul>
<li
v-for="(sing_info,index) in item.songList"
:key="index"
>{{index+1}}{{sing_info.songname}}-{{sing_info.singername}}</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
import BScorll from "better-scroll";
export default {
//import引入的组件需要注入到对象中才能使用
components: {},
data() {
//这里存放数据
return {
rankdata: []
};
},
//监听属性 类似于data概念
computed: {},
//监控data中的数据变化
watch: {},
//方法集合
methods: {
init() {
new BScorll(".wrapper", {});
}
},
//生命周期 - 创建完成(可以访问当前this实例)
created() {
let url =
"/v8/fcg-bin/fcg_myqq_toplist.fcg?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8¬ice=0&format=jsonp&uin=0&needNewCode=1&platform=h5&jsonpCallback=jp0";
this.$axios(url).then(res => {
let str = res.replace(/jp0\(/g, "");
let data = JSON.parse(str.slice(0, length - 1));
this.rankdata = data.data.topList;
});
},
mounted() {
this.init();
}
};
</script>
<style lang="less" scoped>
.box {
width: 94%;
height: 100px;
margin-left: 10px;
background: #333;
margin-top: 20px;
}
ul li {
color: hsla(0, 0%, 100%, 0.3);
line-height: 22px;
font-size: 12px;
list-style: none;
padding-left: 10px;
margin-top: 5px;
width: 155px;
height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.wrapper {
position: fixed;
top: 130px;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
.wrapper .content {
height: auto;
margin-top: 20px;
}
.left {
float: left;
height: 100px;
}
.left img {
width: 100px;
height: 100px;
display: block;
}
.right {
height: 100px;
width: 50%;
overflow: hidden;
float: left;
}
.right ul {
height: 100px;
}
</style>
效果图
7、搜索页面(Search)
代码如下
<!-- -->
<template>
<div class="search">
<div class="input_box">
<input type="text" v-model="word" placeholder="搜索歌声、歌曲" />
<div class="icon"></div>
</div>
<img
class="loading"
v-if="loading"
src="data:image/gif;base64,R0lGODlhZABkAKIEAN7e3rq6uv///5mZmQAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpBRjA4RUZDMDI3MjA2ODExODA4M0Y1OTQyMzVDRDM3MyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCMzE0Rjk3NDdDRTgxMUUzOUJCRjk0NjAxMUE1NzRBMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCMzE0Rjk3MzdDRTgxMUUzOUJCRjk0NjAxMUE1NzRBMCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RDVBMTZDQjczOTIwNjgxMTgwODNGNTk0MjM1Q0QzNzMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QUYwOEVGQzAyNzIwNjgxMTgwODNGNTk0MjM1Q0QzNzMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+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"
alt
/>
<div v-show="searched" class="searched">
<div class="wrapper" ref="wrapper">
<div class="content">
<span
v-for="(searchitem,index) in list"
:key="index"
>{{searchitem.songname}}-{{searchitem.singer[0].name}}</span>
</div>
</div>
</div>
<div v-show="keyword" class="keyword">
<span class="search_title">热门搜索</span>
<ul>
<li v-for="(item,index) in keywordData.slice(0, 15)" :key="index">{{item.k}}</li>
</ul>
</div>
</div>
</template>
<script>
import Bs from "better-scroll";
export default {
//import引入的组件需要注入到对象中才能使用
components: {},
data() {
//这里存放数据
return {
keywordData: [],
word: "",
loading: false,
keyword: true,
searched: false,
list: []
};
},
created() {
//https://c.y.qq.com/splcloud/fcgi-bin/gethotkey.fcg?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8¬ice=0&format=jsonp&uin=0&needNewCode=1&platform=h5&jsonpCallback=jp0
let url =
"/splcloud/fcgi-bin/gethotkey.fcg?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8¬ice=0&format=jsonp&uin=0&needNewCode=1&platform=h5&jsonpCallback=jp0";
this.$axios.get(url).then(res => {
let str = res.replace(/jp0\(/g, "");
let data = JSON.parse(str.slice(0, length - 1));
this.keywordData = data.data.hotkey;
this.$nextTick(() => {
this.init();
});
});
},
methods: {
init() {
new Bs(this.$refs.wrapper, {});
}
},
watch: {
word(val) {
this.searched = true;
if (val == "") {
this.searched = false;
this.keyword = true;
this.loading = false;
return;
} else {
this.keyword = false;
this.loading = true;
this.$axios
.get(
`/search?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8¬ice=0&format=json&w=${val}&p=1&perpage=20&n=20&catZhida=1&zhidaqu=1&t=0&flag=1&ie=utf-8&sem=1&aggr=0&remoteplace=txt.mqq.all&uin=0&needNewCode=1&platform=h5`
)
.then(res => {
this.list = [];
res.data.song.list.forEach(item => {
if (item.songname.indexOf(val) != -1) {
this.list.push(item);
}
});
this.loading = false;
});
}
}
}
};
</script>
<style lang="less" scoped>
@import "../../style/mixin.less";
.search {
.w(375);
height: 100%;
}
.input_box {
.w(337);
height: 40px;
margin: 20px auto;
position: relative;
input {
width: 100%;
height: 35px;
padding: 5px;
background: #333;
border: 1px solid #222;
border-radius: 10px;
color: #fff;
text-indent: 2em;
}
.icon {
width: 25px;
height: 25px;
background: url("../../../public/search.png") no-repeat;
position: absolute;
top: 20px;
}
}
input:focus {
outline: none;
}
.search_title {
color: hsla(0, 0%, 100%, 0.5);
font-size: 14px;
width: 100%;
text-indent: 1.5em;
}
.keyword {
width: 100%;
padding: 20px;
}
.keyword li {
display: block;
margin-left: 9px;
background: #333;
float: left;
padding: 6px;
border-radius: 5px;
color: hsla(0, 0%, 100%, 0.2);
margin-top: 20px;
font-size: 14px;
}
.loading {
width: 30px;
height: 30px;
margin-left: 45%;
margin-top: 20px;
}
.wrapper {
position: fixed;
top: 160px;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
.content {
height: auto;
margin-top: 40px;
padding: 20px;
overflow: hidden;
span {
display: block;
width: 100%;
height: 30px;
padding: 5px;
margin-top: 5px;
font-size: 16px;
color: hsla(0, 0%, 100%, 0.5);
}
}
}
</style>
效果图
这个项目用到的主要技术栈为(vue、vue-cli、axios、vue-router、better-scroll插件、Swiper插件)
未完成的部分我将在下一篇文章继续完善