在singer.vue中,點擊某一歌手,根據路由跳轉到singer-detail.vue在vue-muscie:singer.vue頁面的5.數據序列化後傳入list-vue中相關邏輯
vue
selectSinger(singer) { //導航至singer-detail.vue頁面 this.$router.push({ path: `/singer/${singer.id}` }) //同時,將singer的信息放入vuex中 this.setSinger(singer) },
因爲singer-detail.vue頁面具備共同性,所以封裝成一個組件music-list.vueweb
這個組件比較簡單,一個殼子,獲取數據傳入組件
vuex
_getDetail() { //若是在歌手詳情頁面刷新,沒法獲取singer.id,則直接返回歌手列表頁面 if (!this.singer.id) { this.$router.push('/singer') } getSingerDetail(this.singer.id).then((res) => { if (res.code === ERR_OK) { this.songs = this._normallizeSongs(res.data.list) } }) },
_normallizeSongs(list) { let ret = [] list.forEach((item) => { let {musicData} = item if (musicData.songid && musicData.albummid) { ret.push(createSong(musicData)) } }) return ret }
這裏使用createSong,建立一個song實例
瀏覽器
這個組件需求:app
組件須要接收的數據props函數
props: { bgImage: { //背景圖片 type: String, default: '' }, songs: { //歌手詳情數據songs type: Array, default: () => [] }, title: { //標題title type: String, default: '' }, }
背景圖片的利用:style 和 computedthis
<div class="bg-image" :style="bgStyle" ref="bgImage"> computed: { bgStyle() { return `background-image:url(${this.bgImage})` } },
根據歌手查詢到歌曲列表,須要滾動scroll.vueurl
<div class="bg-layer" ref="layer"></div> <scroll @scroll="scroll" //須要派發滾動位置,觸發的事件 :probe-type="probeType" //不須要截流 :listen-scroll="listenScroll" //派發滾動位置 :data="songs" //接收數據,初始化scroll class="list" ref="list"> <div class="song-list-wrapper"> <song-list @select="selectItem" :songs="songs" :rank="rank"></song-list> </div> </scroll>
mounted() { //背景圖圖片的高度 this.imageHeight = this.$refs.bgImage.clientHeight //滾動的邊界:滾動到此 背景圖片 ——(減去) 頂部title的高度 this.minTranslateY = -this.imageHeight + RESERVED_HEIGHT(40) //初始化的時候列表設置top值:爲了列表向上滾動而進行traslate3d this.$refs.list.$el.style.top = `${this.$refs.bgImage.clientHeight}px` },
觸發滾動事件spa
scroll(pos) { this.scrollY = pos.y },
監聽滾動位置scrollY3d
watch: { scrollY(newY) { //往上滑動newY是負數 translateY往上移動是負數 //沒有滑到臨界值的時候translateY=newY 滑動頂部40的時候translateY=this.minTranslateY let translateY = Math.max(this.minTranslateY, newY) this.$refs.layer.style['transform'] = `translate3d(0, ${translateY}px,0)` this.$refs.layer.style['webkitTransform'] = `translate3d(0, ${translateY}px,0)` let zIndex = 0 //縮放 let scale = 1 //比例 let perscent = Math.abs(newY / this.imageHeight) //高斯模糊 let blur = 0 //下拉的時候 if (newY > 0) { scale = 1 + perscent zIndex = 10 } else { //上滑的時候:高斯模糊 blur = Math.min(20 * perscent, 20) } if (newY < this.minTranslateY) { //上滑 `過` 臨界值的時候,背景圖片相應改變,按鈕消失 zIndex = 10 this.$refs.bgImage.style.paddingTop = 0 this.$refs.bgImage.style.height = `${RESERVED_HEIGHT}px` this.$refs.playButton.style.display = 'none' } else { //下滑 `未過` 臨界值的時候 this.$refs.bgImage.style.paddingTop = '70%' this.$refs.bgImage.style.height = '0' this.$refs.playButton.style.display = '' } this.$refs.bgImage.style.zIndex = zIndex //爲何從頂部顯示scale縮放:由於下面的CSS .bg-image中 transform-origin: top //下拉的時候放大效果 this.$refs.bgImage.style[transform] = `scale(${scale})` //高斯模糊 IOS this.$refs.bgImage.style[backdrop] = `blur(${blur}px)` } },
在使用transform以及back-drop的時候,須要根絕瀏覽器添加一些前綴,封裝成方法調用
let elementStyle = document.createElement('div').style //自執行函數:瀏覽器兼容的前綴 let vender = (() => { const tranforNames = { webkit:'webkitTransfrom', Moz:'MozTransfrom', O:'OTransfrom', ms:'msTransfrom', standard:'standard' } for(let key in transforNames){ if(elementStyle[transfromNames[key]] !== undefined){ return key } } return false })() export function prefixStyle(style){ if(vendor === false){ return false } if(ventor === 'standard'){ return style } return vendor + style.charAt(0).toUpperCase() + style.substr(1) }
在music-list.vue中引入
const transform = prefixStyle('transform')
列表很常見,封裝成組件song-list.vue
傳入songs數據
功能:展現數據,傳出點擊的數據
<div class="song-list"> <ul> <li @click="selectItem(song,index)" :key="song.id" v-for="(song,index) in songs" class="item"> <div class="content"> <h2 class="name">{{song.name}}</h2> <p class="desc">{{getDesc(song)}}</p> </div> </li> </ul> </div> methods:{ getDesc(song) { return `${song.singer} . ${song.album}` }, selectItem(item, index) { this.$emit('select', item, index) }, }