[Vue音樂專案] 第九節 歌手頁面(點選跳轉+滑動聯動)
阿新 • • 發佈:2020-10-22
上一節完成了頁面的展示及滾動效果,接下來實現歌手列表和歌手索引的聯動效果,點選右側的字母,中間跳轉到相應的歌手位置,滑動歌手頁面時,右側的字母列表也隨之改變。
-
開啟src/base/listview/index.vue(沒有則建立),實現點選跳轉
//實現原理: 因為字母列表索引和歌手列表相對應,在觸屏開始的時候,記錄下開 //始索引index及當前元素位於瀏覽器器的 //Top偏移值y1;在觸屏移動的時候,記錄下當前top偏移值y2,根據(y2-y1)/元素高度 //得到偏移索引,開始索引index+偏移索引等於當前索引。把當前 //索引傳遞進_scrollTo, <template> <ul> <li ref="grouplist"> <h2> ... </h2> <ul> <li ref="itemlist"> </ul> </li> </ul> //新增兩個事件監聽,1.觸屏開始 2.觸屏移動 <div class="list-shortcut" @touchStart="onTS" @touchMove.top.prevent="onTM"> </div> </template> <script> export default { created() { this.touch = {}, } methods: { //[1] 為索引列表新增觸屏開始事件處理程式 onTS(e) { //獲取開始li元素的data_index屬性 let index = getData(e.target,'index') //獲取開始li元素的偏移值 this.touch.y1 = e.touchs[0].pageY //放置當前索引 this.touch.index = index //[3] 歌手列表滾動到指定位置 this._scrollTo(index) }, //[2] 為索引列表新增觸屏移動事件處理程式 onTM(e) { //儲存當前li元素的偏移值 this.touch.y2 = e.touchs[0].pageY //獲取偏移索引 let offset = (this.touch.y2-this.touch.y1) / 18 | 0 //計算得出當前索引 let index = parseInt(this.touch.index) + offset //[3] 歌手列表滾動到指定位置 this._scrollTo(index) }, //[方法] 歌手列表滾動到指定位置 _scrollTo(index) { //對index做預先處理 ps: heights最後兩個高度是多餘的 if(!index && index!=0) return if(index < 0) { index = 0 } else if(index > this.heights.length - 2) { index = this.heights.length - 2 } //滾動歌手列表 ps:方法scrollToElement在Scroll元件定義 this.$refs.listview.scrollToElement(this.$refs.grouplist[index],0) } }, } </script> //scr/base/scroll/index.vue,methods新增以下方法 scrollToElement() { this.scroll && this.scroll.scrollToElement.apply(this.scroll,arguments) } //scr/common/js/dom.js 新增以下內容 export function getData(el,name,value) { const prefix = 'data-' name = prefix + name if(value) { return el.setAttribute(name,value) } else { return el.getAttribute(name) } }
-
實現兩邊聯動效果
<template> //[2.1] 滾動時,新增監聽函式 <m-scroll @scroll="scroll" > <ul> <li> <h2> ... </h2> <ul> //[3] 動態改變右側字母索引的樣式 <li :class="{'current': currentIndex == index}" > </ul> </li> </ul> <div> </div> //[fixed 1](共三步) 歌手列表固定欄 通過fixed變數動態改變 <div class="list-fixed" v-show="fixedTitle" ref="fixed"> <div class="fixed-title">{{fixedTitle}}</div> </div> </scroll> </template> <script> export default { computed: { //[fixed 2] 計算是否固定 fixed() { if(this.scrollY > 0) return undefined return this.data[this.currentIndex] ? this.data[this.currentIndex].title : undefined } }, methods: { //如果手動點選,更新歌手列表的ScrollY值 scroll() { ... this.scrollY = -this.heightList[index] }, _calculateHeight() { var height = 0 this.heightList.push(height) for(let i=0; i<this.$refs.listgroup.length; i++) { height += this.$refs.listgroup[i].clientHeight this.heightList.push(height) } }, //[2.2] 監聽處理函式,賦值給scrollY scroll(pos) { this.scrollY = pos.y } }, watch: { data() { //[1] 獲取歌手列表各分組高度 this._calculateHeight() }, //[3] scrollY變化時,處理得到currentIndex scrollY(newValue) { if(newY > 0) { this.currentIndex = 0 return } for(let i=0; i<this.heightList.length; i++) { let height1 = this.heightList[i] let height2 = this.heightList[i+1] if(-newY >= height1 && -newY < height2) { this.currentIndex = i [fixed 3] 監聽父組到頂部的距離,固定欄減少該段距離 this.diff = height2 + newY return } } this.currentIndex = this.heightList.length - 2 } }, //實現固定欄逐漸減少高度的動畫,平滑過渡 diff(newVal) { let fixedTop = (newVal>0 && newVal<30) ? newVal - 30 : 0 if(this.fixedTop == fixedTop) return this.fiexedTop = fixedTop this.$refs.fixed.style.transform = `translate3d(0,${fixedTop}px,0)` } } </script>