github:https://github.com/Ching-Lee/vue-music
1.子路由配置
-
創(chuàng)建詳情頁組件
- 在rooter/index.js中添加子路由
{
path: '/singer',
component: Singer,
children: [
{
path: ':singer_id',
component: SingerDetail
}
]
},
- listView是基礎(chǔ)組件,我們?yōu)槊總€li點擊添加事件派發(fā)
<li v-for="(item, index) in (value)" v-bind:key="index" class="singer_item" @click="selectItem(item)">
<img v-lazy="item.singer_pic" class="singerPic">
<span class="singer_name">{{item.name}}</span>
</li>
// 點擊歌手扔役,跳轉(zhuǎn)到該歌手的歌單頁面
// 這里派發(fā)了事件
selectItem (item) {
this.$emit('select', item)
}
- 在singer.vue中注冊
<div class="singer" v-if="singerlist.length">
<listview v-bind:data=" _singerCountryMap()" @select="selectSinger"></listview>
<router-view></router-view>
</div>
// 手動跳轉(zhuǎn)
selectSinger (singer) {
this.$router.push({
path: `/singer/${singer.singer_id}`
})
}
- 跳轉(zhuǎn)發(fā)現(xiàn)看不到組件內(nèi)容,去設(shè)置樣式
這里的z-index要比頭部的大,才能蓋住頭部脊框。
.singer_detail{
z-index: 2;
position:fixed;
top:0;
left: 0;
right: 0;
bottom: 0;
background-color: white;
}
2.做漸入漸出的動畫特效
<template>
<transition name="slide">
<div class="singer_detail">
<span>歌手詳情頁</span>
</div>
</transition>
</template>
.slide-enter-active, .slide-leave-active {
transition: all .3s;
}
.slide-enter, .slide-leave-to /* .fade-leave-active below version 2.1.8 */
{
transform: translate3d(100%, 0, 0);
}
點擊的時候會有滑屏的效果江耀。
3.使用qq音樂后臺數(shù)據(jù)
這里每次請求15個數(shù)據(jù)屈张,請求參數(shù)中有begin表示請求開始的索引擒权,num是15表示一次15個。
請求參數(shù)中有singerid阁谆,通過singerid返回不同歌手的信息。
音樂信息在list中愉老。
-
在api添加歌手詳情頁獲取后臺信息的部分
import jsonp from '../assets/js/jsonp'
import {commonParams, options} from './config'
// 獲取歌手詳情頁面相關(guān)數(shù)據(jù)
export function getSingerDetail (singerid) {
const url = 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg'
const param = Object.assign({}, commonParams, {
singerid: singerid,
uin: 0,
format: 'json',
platform: 'h5page',
needNewCode: 1,
order: 'listen',
from: 'h5',
num: 15,
begin: 0,
_: 1528443902453
})
return jsonp(url, param, options)
}
- 在singer_detail.vue中獲取數(shù)據(jù)场绿,賦值給singerDetail
export default {
data () {
return {
singerDetail: null
}
},
computed: {
getFans () {
return `粉絲:${(this.singerDetail.fans / 10000).toFixed(2)}萬人`
},
getImage () {
return `http://y.gtimg.cn/music/photo_new/T001R150x150M000${this.singerDetail.singer_mid}.jpg?max_age=2592000`
}
},
created () {
this._getSinerDetailbyid(this.$route.params.singer_id)
},
methods: {
_getSinerDetailbyid (singerid) {
getSingerDetail(singerid).then((result) => {
if (result.code === ERR_OK) {
this.singerDetail = result.data
}
})
}
},
}
4.頭部組件開發(fā)singer_detail_header
布局是左邊圖片div,右邊介紹div嫉入,下面按鈕div
<template>
<div class="detail_top" ref="detailtop">
<div class="detail_header clearfix">
<div class="detail_left">
<img v-bind:src=image />
</div>
<div class="detail_right">
<h2>{{name}}</h2>
<P class="fans">{{fans}}</P>
<p class="intruduce">{{intruduce}}</p>
</div>
</div>
<div class="bottom_detail">
<div class="button">
<i class="icon-player"></i>
<span>播放全部</span>
</div>
</div>
</div>
</template>
默認(rèn)屬性:
props: {
image: {
type: String,
default: ''
},
name: {
type: String,
default: ''
},
fans: {
type: String,
default: ''
},
intruduce: {
type: String,
default: ''
}
},
css樣式:
圖片和介紹:是一個左邊固定右邊自適應(yīng)的布局焰盗。
左邊固定右邊自適應(yīng)的實現(xiàn)方法:
1)左邊f(xié)loat:left,就會脫離文檔流,然后解決高度塌陷的問題
2)position:absolute,使用絕對定位咒林,左邊的left:0,右邊的right:0
3 ) flex布局熬拒,整體的盒子display:flex,右邊f(xié)lex:1
4 ) grid布局,display:grid,template-grid-column:左邊寬度 auto
5)table布局垫竞,容器寬度設(shè)置為100%澎粟,左右設(shè)置為display:table-cell
這里使用float實現(xiàn)
<style>
.detail_header {
background-color:rgba(0, 0, 0, 0.6);
padding: 1rem;
}
.detail_left {
float: left;
width: 150px;
margin-right: 0.5rem;
}
.clearfix:after {
clear: both;
content: '';
display: table;
}
.detail_right h2 {
font-size: 1.2rem;
margin-top: 1rem;
color: white;
}
.detail_right .fans {
font-size: 1rem;
margin: 1rem 0;
color: whitesmoke;
}
/*設(shè)置三行內(nèi)容蛀序,超出...*/
.detail_right .intruduce {
white-space: initial;
font-size: 0.8rem;
line-height: 1.2rem;
color: whitesmoke;
height:3.6rem;
overflow: hidden;
position: relative;
}
.detail_right .intruduce:after{
content:'...';
font-weight: bold;
position: absolute;
bottom: 0;
right: 0;
}
.bottom_detail {
background-color:rgba(0, 0, 0, 0.6);
padding-bottom: 1rem;
text-align: center;
}
.button{
display: inline-block;
background-color: rgba(0, 0, 0, 0);
border-radius: 3rem;
padding: 0.4rem 1.2rem;
color: white;
border: 1px orange solid;
}
/*怎么讓圖片和文字對齊*/
.button *{
display:inline-block;
vertical-align:middle
}
.button i{
font-size: 1.5rem;
color: orange;
}
</style>
怎么讓圖片和文字對齊
父元素里的所有元素設(shè)置成內(nèi)斂塊元素,然后居中
.button *{
display:inline-block;
vertical-align:middle
}
怎么設(shè)置三行內(nèi)容活烙,多余的超出:
通過設(shè)置行高+絕對定位
/設(shè)置三行內(nèi)容徐裸,超出.../
.detail_right .intruduce {
line-height: 1.2rem;
/height是line-height的3倍/
height:3.6rem;
overflow: hidden;
position: relative;
}
.detail_right .intruduce:after{
content:'...';
font-weight: bold;
position: absolute;
bottom: 0;
right: 0;
}
- 然后去設(shè)置背景圖片
mounted () {
this._setBackgroundPic()
},
methods: {
_setBackgroundPic () {
let target = this.$refs.detailtop
target.style.backgroundImage = `url(${this.image})`
target.style.backgroundSize = '100% auto'
}
}
- 父組件中調(diào)用傳遞屬性
<template>
<transition name="slide">
<div class="singer_detail" v-if="singerDetail" >
<singer-detail-header v-bind:image=getImage v-bind:name="singerDetail.singer_name" v-bind:fans="getFans" v-bind:intruduce="singerDetail.SingerDesc"></singer-detail-header>
<p class="total_song">歌曲 共{{singerDetail.total}}首</p>
</div>
</transition>
</template>
5.music-list組件開發(fā)
<template>
<div>
<ul class="music_list">
<li v-for="(item, index) in list" v-bind:key="index">
<h2>{{item.musicData.songname}}</h2>
<p>{{item.musicData.singer[0].name}} {{item.musicData.albumdesc}}</p>
</li>
</ul>
</div>
</template>
<script type="text/ecmascript-6">
export default{
props: {
list: {
type: Array,
default: null
}
}
}
</script>
<style>
.music_list li{
padding: 1rem;
border-bottom: 1px solid whitesmoke;
}
.music_list li h2{
font-size: 1rem;
}
.music_list li p{
font-size: 0.8rem;
margin-top: 10px;
color: orange;
line-height: 1rem;
}
</style>
6.讓music-list組件能夠滑動
使用vue-iscroll-view,參考文檔
https://dafrok.github.io/vue-iscroll-view/
-
首先安裝
- 在main.js中use
import IScrollView from 'vue-iscroll-view'
import IScroll from 'iscroll'
Vue.use(IScrollView, IScroll)
- music.list中添加
<template>
<iscroll-view ref='scrollView' class='scroll_view' :options="{preventDefault: true}">
<ul class="music_list">
<li v-for="(item, index) in list" v-bind:key="index">
<h2>{{item.musicData.songname}}</h2>
<p>{{item.musicData.singer[0].name}} {{item.musicData.albumdesc}}</p>
</li>
</ul>
</iscroll-view>
</template>
mounted () {
this.$refs.scrollView.refresh()
}
.scroll_view{
touch-action:none;
position: fixed;
left: 0;
right: 0;
top: 280px;
bottom: 0;
overflow: hidden;
}
7.加載更多組件
- 實現(xiàn)loadMore功能
hasmore屬性:表示是否還有數(shù)據(jù)
number屬性:number表示已經(jīng)加載的數(shù)據(jù)數(shù)量啸盏,當(dāng)大于全部數(shù)量時重贺,hasMore就是false
list:存儲數(shù)據(jù)的列表
isLoading: 正在加載
begin: 發(fā)起請求時的請求參數(shù),開始的索引
singer_detail中添加更改屬性和方法
export default {
data () {
return {
singerDetail: null,
begin: 0,
isLoading: false,
list: [],
number: 0, // number表示已經(jīng)加載的數(shù)據(jù)數(shù)量回懦,當(dāng)大于全部數(shù)量時气笙,hasMore就是false
hasMore: true, // 表示是否還有數(shù)據(jù)
showMoreDec: false
}
},
methods: {
_getSinerDetailbyid (singerid, begin) {
console.log(singerid)
getSingerDetail(singerid, begin).then((result) => {
if (result.code === ERR_OK) {
this.singerDetail = result.data
//在用push方法時報錯
this.list = this.list.concat(result.data.list)
this.number = this.number + result.data.list.length
if (this.number >= result.data.total) {
this.hasMore = false
}
this.isLoading = false
}
})
},
_loadFn () {
if (this.hasMore) {
this.isLoading = true
this.begin = this.begin + 15
this._getSinerDetailbyid(this.$route.params.singer_id, this.begin)
}
},
- 調(diào)用musiclist的時候傳遞屬性
@loadmore是接收觸發(fā)
<music-list v-bind:list="list" @loadmore="_loadFn" v-bind:hasMore="hasMore"></music-list>
misiclist中調(diào)用load-more組件,完成分發(fā)
<load-more @loadmore="dispachload()" v-bind:isLoading="isLoading" v-bind:hasMore="hasMore"></load-more>
export default {
props: {
list: {
type: Array,
default: null
},
isLoading: {
type: Boolean,
default: false
},
hasMore: {
type: Boolean,
default: true
}
},
components: {
'load-more': LoadMore
},
methods: {
dispachload () {
this.$emit('loadmore')
},
- loadMore組件
如果有更多怯晕,并且當(dāng)前沒有在加載健民,就顯示加載更多。當(dāng)點擊時就觸發(fā)事件傳遞贫贝。
沒有更多秉犹,就顯示我是有底線的。
<template>
<div v-if='hasMore' ref="loaddiv" v-show="!isLoading" v-on:click="dispachload()" class="loaddiv">上拉加載更多</div>
<div class="loaddiv" v-else>我是有底線的</div>
</template>
<script type="text/ecmascript-6">
export default{
props: {
isLoading: {
type: Boolean,
default: false
},
hasMore: {
type: Boolean,
default: true
}
},
methods: {
dispachload () {
this.$emit('loadmore')
}
}
}
</script>
<style>
.loaddiv{
text-align: center;
line-height: 1rem;
}
</style>
- 這時候會發(fā)現(xiàn)點擊時稚晚,請求到了新的數(shù)據(jù)崇堵,但是滾動條不能向下滾動。
我們需要在music_list中添加對list列表改變進(jìn)行watch
watch: {
list: function () {
this.$refs.scrollView.refresh()
}
},
- 添加上滑自動加載
methods: {
dispachload () {
this.$emit('loadmore')
},
/* pullDown () {
console.log('pullDown')
}, */
pullUp () {
this.dispachload()
}
}
8.彈出歌手詳細(xì)介紹的模態(tài)框
一個大的div客燕,設(shè)置成絕對定位鸳劳,top:0,left:0,right:0,bottom:0,設(shè)置背景顏色和透明度
里面包裹著一個中間顯示的div,設(shè)置背景為白色也搓。
<template>
<transition name="slide">
<div class="singer_detail" v-if="singerDetail" >
<singer-detail-header @alert="_alertfn" v-bind:image=getImage v-bind:name="singerDetail.singer_name" v-bind:fans="getFans" v-bind:intruduce="singerDetail.SingerDesc"></singer-detail-header>
<p class="total_song">歌曲 共{{singerDetail.total}}首</p>
<music-list v-bind:list="list" @loadmore="_loadFn" v-bind:hasMore="hasMore"></music-list>
<div class="back" v-show="showMoreDec">
<div id="moredec">
<div id="dectext">{{singerDetail.SingerDesc}}</div>
<div id="closebutton" v-on:click="_closefn()">關(guān)閉</div>
</div>
</div>
</div>
</transition>
</template>
通過屬性showMoreDec控制顯示與否赏廓,當(dāng)點擊singer-detail-header組件中的介紹時,觸發(fā)分發(fā)alert事件給父組件sing_detail傍妒,在父組件中改變屬性showMoreDec值為true
data () {
showMoreDec: false
}
methods: {16
_alertfn () {
this.showMoreDec = true
},
_closefn () {
this.showMoreDec = false
}
}