第5章 歌手頁面開發(待續)

內容均爲《Vue2.0開發企業級移動端音樂Web App 》學習筆記javascript

包括歌手數據的抓取和處理、Singer 類的封裝、類通信錄組件 listview開發和應用。html

5-1 歌手頁面佈局和設計講解

作一個相似於通信錄的功能,當滑動左邊的列表,右側的相應的字母分類加上選中的樣式,當點擊右側的字母的時候,滑動到左側相應的項,頭部標題固定。 咱們但願獲得的數據是vue

5-2 歌手數據接口抓取

src\api\singer.jsjava

import {commonParams,options} from './config'
import jsonp  from 'common/js/jsonp.js'

export function getsingerList(){
const url = 'https://c.y.qq.com/v8/fcg-bin/v8.fcg'
const data=Object.assign({},commonParams,{
    channel: 'singer',
    page: 'list',
    key: 'all_all_all',
    pagesize: 100,
    pagenum: 1,
    hostUin: 0,
    needNewCode: 0,
    platform: 'yqq',
    g_tk: 1664029744, 
})   
return jsonp(url,data,options)

在singer.vue中請求數據
created(){
    this._getsingerList()  
},
methods:{
 _getsingerList(){
    getsingerList().then(res=>{
        if(res.code===ERR_OK){
            //將數據作過濾,過濾出咱們須要的數據,咱們將前10當是熱門的數據
             this._normalizeSinger(res.data.list)
        }
    }).catch(err=>{
        console.log(err);
    })
},
複製代碼

獲得的數據以下 json

在這裏插入圖片描述

5-3 歌手數據處理和 Singer 類的封裝

對歌手數據進行處理api

_normalizeSinger(list){
            //首先咱們先對數據進行分類
            let map={
                hot:{
                   title: HOT_NAME,
                   items: []
                }
            }
            //首先咱們先獲得熱門的歌曲,咱們將獲得的數據的前十條做爲熱門數據
            list.forEach((item,index) => {
                //在這裏咱們獲得了熱門的歌手
                if(index<HOT_SINGER_LEN){
                  map.hot.items.push({
                       id: item.Fsinger_mid,
                       name: item.Fsinger_name,
                       avatar: `https://y.gtimg.cn/music/photo_new/T001R300x300M000${item.Fsinger_mid}.jpg?max_age=2592000`
                  });
                }
                //在這裏咱們獲得各個字母的的分類的歌手
                let key=item.Findex;
                if(!map[key]){
                    //當沒有當前的字母項,咱們建立一個
                    map[key]={
                        title: key,
                        items: []
                    }
                }
                //把相應的項添加到map[key]中
                map[key].items.push({
                     id: item.Fsinger_mid,
                    name: item.Fsinger_name,
                    avatar: `https://y.gtimg.cn/music/photo_new/T001R300x300M000${item.Fsinger_mid}.jpg?max_age=2592000`
                })

            });
        }
複製代碼

咱們發如今push歌手信息的時候,這部分的代碼是同樣的,而avatar的計算是根據id計算的,咱們但願構造一個歌手類,經過傳入id和name獲得咱們想要的數據格式。提升代碼的複用性 common\js\singer.js數組

export default class Singer {
    constructor({name,id}){
        this.name=name,
        this.id=id
        this.avatar = `https://y.gtimg.cn/music/photo_new/T001R300x300M000${id}.jpg?max_age=2592000`
    }
}
複製代碼

作調整bash

//引入歌手類文件
import Singer from 'common/js/singer'

 //對歌手數據進行處理
        _normalizeSinger(list){
            //首先咱們先對數據進行分類
            let map={
                hot:{
                   title: HOT_NAME,
                   items: []
                }
            }
            //首先咱們先獲得熱門的歌曲,咱們將獲得的數據的前十條做爲熱門數據
            list.forEach((item,index) => {
                //在這裏咱們獲得了熱門的歌手
                if(index<HOT_SINGER_LEN){
                  map.hot.items.push(new Singer({
                       id: item.Fsinger_mid,
                       name: item.Fsinger_name,
                    })
                  );
                }
                //在這裏咱們獲得各個字母的的分類的歌手
                let key=item.Findex;
                if(!map[key]){
                    //當沒有當前的字母項,咱們建立一個
                    map[key]={
                        title: key,
                        items: []
                    }
                }
                //把相應的項添加到map[key]中
                map[key].items.push(new Singer({
                       id: item.Fsinger_mid,
                       name: item.Fsinger_name,
                    })
                )

            });

            console.log(map);
        }
複製代碼

咱們發現這個順序是雜亂無章的,咱們其實但願的是按照順序排列,而且數據的結構是一個數組,如今咱們來處理一下這些數據。對上面的數據進行排序 熱門>A>B>C...app

let hot=[]
let ret=[]
//對數據進行分類,分紅字母類數組和熱門類數組
for(let key in map){
    let val=map[key];
    if(val.title.match(/[a-zA-Z]/)){
          ret.push(val);
    }else if(val.title===HOT_NAME){
        hot.push(val);
    }
}
//數組的字母類數組進行排序
ret.sort((a,b)=>{
    return a.title.charCodeAt(0) - b.title.charCodeAt(0)
})
return hot.concat(ret);
複製代碼

在_getsingerList()中獲得ingerListdom

this.singerList=this._normalizeSinger(res.data.list)
複製代碼

5-4 listview 基礎組件的開發和應用-滾動列表實現

獲得ingerList以後,咱們就能夠作滾動列表了,把data傳入到scroll裏面 引入scroll

import scroll from '../scroll/scroll'
複製代碼
<template>
    <scroll :data="data" class="listview">
          <ul>
              <li class="list-group" v-for="(item,index) in data" :key="index">
              <h2 class="list-group-title">{{item.title}}</h2>
              <ul>
                  <li class="list-group-item" v-for="singer in item.items" :key="singer.id">
                    <img class="avatar" v-lazy="singer.avatar">
                    <span class="name">{{singer.name}}</span>
                  </li>
              </ul>
              </li>
          </ul>
    </scroll>
</template>
複製代碼

5-5 listview 基礎組件的開發和應用-右側快速入口實現(1)

佈局

shortcut(){////獲得title的集合數組,‘熱門’取1個字
    let arr=[];
    this.data.forEach(item => {
      arr.push(item.title.substr(0,1));
    });
    return arr
}
複製代碼
<!-- 右側點點部分-->
  <div class="list-shortcut">
      <ul>
        <li :data-index="index" class="item" v-for="(item,index) in shortcut" :key="index">
          {{item}}
        </li>
      </ul>
  </div>
複製代碼

5-6 listview 基礎組件的開發和應用-右側快速入口實現(2)

觸摸右側標題 爲了獲得當前觸摸的是哪個點點,咱們給加上了屬性data-index

<div class="list-shortcut">
      <ul @touchstart="onShortcutTouchStart" @touchmove.stop.prevent="onShortcutTouchMove">
        <li v-for="(item,index) in shortcut" :key="index" :data-index="index" class="item" :class="{current:index==currentIndex}" >
          {{item}}
        </li>
      </ul>
  </div>
複製代碼

當咱們點擊ul的時候咱們須要獲取到當前的點擊元素的data-index來判斷點擊的是哪個元素,那麼怎麼獲取到data-index 這個屬性呢,咱們在dom,.js中export一個getData的方法。來設置或者獲取屬性

//給元素添加屬性或者獲得屬性的值
export function getData(el,attrname,value){
    let prefix='data-'
    let  name=prefix+attrname
    if(value){
        el.setAttribute(name,value);
    }else{
        return el.getAttribute(name);
    }
}
複製代碼

當開始觸屏的時候記錄當前的y1 和 當前的索引,而且滾動到相應的位置。 在scroll組件中定義兩個方法

scrollTo() {
        // 滾動到指定的位置;這裏使用apply 將傳入的參數,傳入到this.scrollTo()
        this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
    },
    scrollToElement(){
        //滾動到指定的元素
        this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
    }
複製代碼

在listview的右側字母列表中監聽觸摸事件

onShortcutTouchStart(e) {
  //記錄開始的位置
  this.touch.y1=e.touches[0].pageY;//開始的y座標
   this.touch.anchorIndex=anchorIndex;
  //去到listHeigth數組的某一項
  this._scollTo(anchorIndex);
},
複製代碼

listHeigth用來存 左側的每個項的 的clientHeight。這樣咱們能夠計算當前的元素索引在左側的哪一個區間。

watch: {
    data(){
      setTimeout(()=>{
          this.listHeigth=[];
          let height=0;
          this.listHeigth.push(0);
          let list=[...this.$refs.listGroup];
          for(let i=0;i<list.length;i++){
              height+=list[i].clientHeight;
              this.listHeigth.push(height);
          }
      },20)
    }
  },


 //滑動到哪裏
  _scollTo(index){
    this.$refs.listview.scrollTo(0,-this.listHeigth[index],0);
    this.currentIndex=index;
  }

複製代碼

當手指滑動的時候,計算y2 和 y1的差值/字母塊的高度,獲得須要偏移多少個字母塊,再加上當前的位置,獲得須要滾動到的index,再滾動到相應的位置。 由於scroll自己能夠滑動,當咱們滑動右側的時候,咱們會阻止默認行爲,阻止事件冒泡

@touchmove.stop.prevent="onShortcutTouchMove"
複製代碼
//計算手機放下的位置,和move以後的位置,比較,讓左邊的滾動,用this.touch來記錄位置信息
  onShortcutTouchMove(e){
       this.touch.y2=e.touches[0].pageY;//開始的y座標
       let delta=(this.touch.y2-this.touch.y1)/CUTHEIGHT | 0//向下取整。獲取到最接近的值
       let anchorIndex=parseInt(this.touch.anchorIndex)+delta
       this._scollTo(anchorIndex);
  },
複製代碼

5-7 listview 基礎組件的開發和應用-右側快速入口實現(3)

當咱們滑動左側的時候,咱們須要監聽咱們當前滑動的縱向y的值,來判斷當前滑動的是哪個區間,來肯定應該指向的索引

5-8 listview 基礎組件的開發和應用-右側快速入口實現(4)

5-9 listview 基礎組件的開發和應用-滾動固定標題實現(上)

5-10 listview 基礎組件的開發和應用-滾動固定標題實現(下)

包括歌手數據的抓取和處理、Singer 類的封裝、類通信錄組件 listview開發和應用。

5-1 歌手頁面佈局和設計講解

作一個相似於通信錄的功能,當滑動左邊的列表,右側的相應的字母分類加上選中的樣式,當點擊右側的字母的時候,滑動到左側相應的項,頭部標題固定。 咱們但願獲得的數據是

5-2 歌手數據接口抓取

src\api\singer.js

import {commonParams,options} from './config'
import jsonp  from 'common/js/jsonp.js'

export function getsingerList(){
const url = 'https://c.y.qq.com/v8/fcg-bin/v8.fcg'
const data=Object.assign({},commonParams,{
    channel: 'singer',
    page: 'list',
    key: 'all_all_all',
    pagesize: 100,
    pagenum: 1,
    hostUin: 0,
    needNewCode: 0,
    platform: 'yqq',
    g_tk: 1664029744, 
})   
return jsonp(url,data,options)

在singer.vue中請求數據
created(){
    this._getsingerList()  
},
methods:{
 _getsingerList(){
    getsingerList().then(res=>{
        if(res.code===ERR_OK){
            //將數據作過濾,過濾出咱們須要的數據,咱們將前10當是熱門的數據
             this._normalizeSinger(res.data.list)
        }
    }).catch(err=>{
        console.log(err);
    })
},
複製代碼

獲得的數據以下

在這裏插入圖片描述

5-3 歌手數據處理和 Singer 類的封裝

對歌手數據進行處理

_normalizeSinger(list){
            //首先咱們先對數據進行分類
            let map={
                hot:{
                   title: HOT_NAME,
                   items: []
                }
            }
            //首先咱們先獲得熱門的歌曲,咱們將獲得的數據的前十條做爲熱門數據
            list.forEach((item,index) => {
                //在這裏咱們獲得了熱門的歌手
                if(index<HOT_SINGER_LEN){
                  map.hot.items.push({
                       id: item.Fsinger_mid,
                       name: item.Fsinger_name,
                       avatar: `https://y.gtimg.cn/music/photo_new/T001R300x300M000${item.Fsinger_mid}.jpg?max_age=2592000`
                  });
                }
                //在這裏咱們獲得各個字母的的分類的歌手
                let key=item.Findex;
                if(!map[key]){
                    //當沒有當前的字母項,咱們建立一個
                    map[key]={
                        title: key,
                        items: []
                    }
                }
                //把相應的項添加到map[key]中
                map[key].items.push({
                     id: item.Fsinger_mid,
                    name: item.Fsinger_name,
                    avatar: `https://y.gtimg.cn/music/photo_new/T001R300x300M000${item.Fsinger_mid}.jpg?max_age=2592000`
                })

            });
        }
複製代碼

咱們發如今push歌手信息的時候,這部分的代碼是同樣的,而avatar的計算是根據id計算的,咱們但願構造一個歌手類,經過傳入id和name獲得咱們想要的數據格式。提升代碼的複用性 common\js\singer.js

export default class Singer {
    constructor({name,id}){
        this.name=name,
        this.id=id
        this.avatar = `https://y.gtimg.cn/music/photo_new/T001R300x300M000${id}.jpg?max_age=2592000`
    }
}
複製代碼

作調整

//引入歌手類文件
import Singer from 'common/js/singer'

 //對歌手數據進行處理
        _normalizeSinger(list){
            //首先咱們先對數據進行分類
            let map={
                hot:{
                   title: HOT_NAME,
                   items: []
                }
            }
            //首先咱們先獲得熱門的歌曲,咱們將獲得的數據的前十條做爲熱門數據
            list.forEach((item,index) => {
                //在這裏咱們獲得了熱門的歌手
                if(index<HOT_SINGER_LEN){
                  map.hot.items.push(new Singer({
                       id: item.Fsinger_mid,
                       name: item.Fsinger_name,
                    })
                  );
                }
                //在這裏咱們獲得各個字母的的分類的歌手
                let key=item.Findex;
                if(!map[key]){
                    //當沒有當前的字母項,咱們建立一個
                    map[key]={
                        title: key,
                        items: []
                    }
                }
                //把相應的項添加到map[key]中
                map[key].items.push(new Singer({
                       id: item.Fsinger_mid,
                       name: item.Fsinger_name,
                    })
                )

            });

            console.log(map);
        }
複製代碼

咱們發現這個順序是雜亂無章的,咱們其實但願的是按照順序排列,而且數據的結構是一個數組,如今咱們來處理一下這些數據。對上面的數據進行排序 熱門>A>B>C...

let hot=[]
let ret=[]
//對數據進行分類,分紅字母類數組和熱門類數組
for(let key in map){
    let val=map[key];
    if(val.title.match(/[a-zA-Z]/)){
          ret.push(val);
    }else if(val.title===HOT_NAME){
        hot.push(val);
    }
}
//數組的字母類數組進行排序
ret.sort((a,b)=>{
    return a.title.charCodeAt(0) - b.title.charCodeAt(0)
})
return hot.concat(ret);
複製代碼

在_getsingerList()中獲得ingerList

this.singerList=this._normalizeSinger(res.data.list)
複製代碼

5-4 listview 基礎組件的開發和應用-滾動列表實現

獲得ingerList以後,咱們就能夠作滾動列表了,把data傳入到scroll裏面 引入scroll

import scroll from '../scroll/scroll'
複製代碼
<template>
    <scroll :data="data" class="listview">
          <ul>
              <li class="list-group" v-for="(item,index) in data" :key="index">
              <h2 class="list-group-title">{{item.title}}</h2>
              <ul>
                  <li class="list-group-item" v-for="singer in item.items" :key="singer.id">
                    <img class="avatar" v-lazy="singer.avatar">
                    <span class="name">{{singer.name}}</span>
                  </li>
              </ul>
              </li>
          </ul>
    </scroll>
</template>
複製代碼

5-5 listview 基礎組件的開發和應用-右側快速入口實現(1)

佈局

shortcut(){////獲得title的集合數組,‘熱門’取1個字
    let arr=[];
    this.data.forEach(item => {
      arr.push(item.title.substr(0,1));
    });
    return arr
}
複製代碼
<!-- 右側點點部分-->
  <div class="list-shortcut">
      <ul>
        <li :data-index="index" class="item" v-for="(item,index) in shortcut" :key="index">
          {{item}}
        </li>
      </ul>
  </div>
複製代碼

5-6 listview 基礎組件的開發和應用-右側快速入口實現(2)

觸摸右側標題 爲了獲得當前觸摸的是哪個點點,咱們給加上了屬性data-index

<div class="list-shortcut">
      <ul @touchstart="onShortcutTouchStart" @touchmove.stop.prevent="onShortcutTouchMove">
        <li v-for="(item,index) in shortcut" :key="index" :data-index="index" class="item" :class="{current:index==currentIndex}" >
          {{item}}
        </li>
      </ul>
  </div>
複製代碼

當咱們點擊ul的時候咱們須要獲取到當前的點擊元素的data-index來判斷點擊的是哪個元素,那麼怎麼獲取到data-index 這個屬性呢,咱們在dom,.js中export一個getData的方法。來設置或者獲取屬性

//給元素添加屬性或者獲得屬性的值
export function getData(el,attrname,value){
    let prefix='data-'
    let  name=prefix+attrname
    if(value){
        el.setAttribute(name,value);
    }else{
        return el.getAttribute(name);
    }
}
複製代碼

當開始觸屏的時候記錄當前的y1 和 當前的索引,而且滾動到相應的位置。 在scroll組件中定義兩個方法

scrollTo() {
        // 滾動到指定的位置;這裏使用apply 將傳入的參數,傳入到this.scrollTo()
        this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
    },
    scrollToElement(){
        //滾動到指定的元素
        this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
    }
複製代碼

在listview的右側字母列表中監聽觸摸事件

onShortcutTouchStart(e) {
  //記錄開始的位置
  this.touch.y1=e.touches[0].pageY;//開始的y座標
   this.touch.anchorIndex=anchorIndex;
  //去到listHeigth數組的某一項
  this._scollTo(anchorIndex);
},
複製代碼

listHeigth用來存 左側的每個項的 的clientHeight。這樣咱們能夠計算當前的元素索引在左側的哪一個區間。

watch: {
    data(){
      setTimeout(()=>{
          this.listHeigth=[];
          let height=0;
          this.listHeigth.push(0);
          let list=[...this.$refs.listGroup];
          for(let i=0;i<list.length;i++){
              height+=list[i].clientHeight;
              this.listHeigth.push(height);
          }
      },20)
    }
  },


 //滑動到哪裏
  _scollTo(index){
    this.$refs.listview.scrollTo(0,-this.listHeigth[index],0);
    this.currentIndex=index;
  }

複製代碼

當手指滑動的時候,計算y2 和 y1的差值/字母塊的高度,獲得須要偏移多少個字母塊,再加上當前的位置,獲得須要滾動到的index,再滾動到相應的位置。 由於scroll自己能夠滑動,當咱們滑動右側的時候,咱們會阻止默認行爲,阻止事件冒泡

@touchmove.stop.prevent="onShortcutTouchMove"
複製代碼
//計算手機放下的位置,和move以後的位置,比較,讓左邊的滾動,用this.touch來記錄位置信息
  onShortcutTouchMove(e){
       this.touch.y2=e.touches[0].pageY;//開始的y座標
       let delta=(this.touch.y2-this.touch.y1)/CUTHEIGHT | 0//向下取整。獲取到最接近的值
       let anchorIndex=parseInt(this.touch.anchorIndex)+delta
       this._scollTo(anchorIndex);
  },
複製代碼

5-7 listview 基礎組件的開發和應用-右側快速入口實現(3)

當咱們滑動左側的時候,咱們須要監聽咱們當前滑動的縱向y的值,來判斷當前滑動的是哪個區間,來肯定應該指向的索引

5-8 listview 基礎組件的開發和應用-右側快速入口實現(4)

5-9 listview 基礎組件的開發和應用-滾動固定標題實現(上)

5-10 listview 基礎組件的開發和應用-滾動固定標題實現(下)

相關文章
相關標籤/搜索