07.vue.2.x开发音乐App-歌手详情页

github:https://github.com/Ching-Lee/vue-music

1.子路由配置

  • 创建详情页组件


  • 在rooter/index.js中添加子路由
  {
      path: '/singer',
      component: Singer,
      children: [
        {
          path: ':singer_id',
          component: SingerDetail
        }
      ]
    },
  • listView是基础组件,我们为每个li点击添加事件派发
<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>
 // 点击歌手,跳转到该歌手的歌单页面
    // 这里派发了事件
    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>

// 手动跳转

 selectSinger (singer) {
      this.$router.push({
        path: `/singer/${singer.singer_id}`
      })
    }
  • 跳转发现看不到组件内容,去设置样式
    这里的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音乐后台数据


这里每次请求15个数据,请求参数中有begin表示请求开始的索引,num是15表示一次15个。
请求参数中有singerid,通过singerid返回不同歌手的信息。
音乐信息在list中。


  • 在api添加歌手详情页获取后台信息的部分


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

// 获取歌手详情页面相关数据
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中获取数据,赋值给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.头部组件开发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>

默认属性:

props: {
    image: {
      type: String,
      default: ''
    },
    name: {
      type: String,
      default: ''
    },
    fans: {
      type: String,
      default: ''
    },
    intruduce: {
      type: String,
      default: ''
    }
  },

css样式:
图片和介绍:是一个左边固定右边自适应的布局。

左边固定右边自适应的实现方法:
1)左边float:left,就会脱离文档流,然后解决高度塌陷的问题
2)position:absolute,使用绝对定位,左边的left:0,右边的right:0
3 ) flex布局,整体的盒子display:flex,右边flex:1
4 ) grid布局,display:grid,template-grid-column:左边宽度 auto
5)table布局,容器宽度设置为100%,左右设置为display:table-cell
这里使用float实现

<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;
  }

/*设置三行内容,超出...*/
  .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>

怎么让图片和文字对齐
父元素里的所有元素设置成内敛块元素,然后居中
.button *{
display:inline-block;
vertical-align:middle
}

怎么设置三行内容,多余的超出:
通过设置行高+绝对定位
/设置三行内容,超出.../
.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;
}

  • 然后去设置背景图片
 mounted () {
    this._setBackgroundPic()
  },
  methods: {
    _setBackgroundPic () {
      let target = this.$refs.detailtop
      target.style.backgroundImage = `url(${this.image})`
      target.style.backgroundSize = '100% auto'
    }
  }
  • 父组件中调用传递属性
<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组件开发


<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.加载更多组件

  • 实现loadMore功能
    hasmore属性:表示是否还有数据
    number属性:number表示已经加载的数据数量,当大于全部数量时,hasMore就是false
    list:存储数据的列表
    isLoading: 正在加载
    begin: 发起请求时的请求参数,开始的索引
    singer_detail中添加更改属性和方法
export default {
  data () {
    return {
      singerDetail: null,
      begin: 0,
      isLoading: false,
      list: [],
      number: 0, // number表示已经加载的数据数量,当大于全部数量时,hasMore就是false
      hasMore: true, // 表示是否还有数据
      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)
      }
    },
  • 调用musiclist的时候传递属性
    @loadmore是接收触发
<music-list v-bind:list="list" @loadmore="_loadFn" v-bind:hasMore="hasMore"></music-list>

misiclist中调用load-more组件,完成分发

 <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组件
    如果有更多,并且当前没有在加载,就显示加载更多。当点击时就触发事件传递。
    没有更多,就显示我是有底线的。
<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>

  • 这时候会发现点击时,请求到了新的数据,但是滚动条不能向下滚动。
    我们需要在music_list中添加对list列表改变进行watch
 watch: {
    list: function () {
      this.$refs.scrollView.refresh()
    }
  },
  • 添加上滑自动加载
 methods: {
    dispachload () {
      this.$emit('loadmore')
    },
    /* pullDown () {
      console.log('pullDown')
    }, */
    pullUp () {
      this.dispachload()
    }
  }

8.弹出歌手详细介绍的模态框


一个大的div,设置成绝对定位,top:0,left:0,right:0,bottom:0,设置背景颜色和透明度
里面包裹着一个中间显示的div,设置背景为白色。

<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()">关闭</div>
          </div>
        </div>
      </div>
  </transition>
</template>

通过属性showMoreDec控制显示与否,当点击singer-detail-header组件中的介绍时,触发分发alert事件给父组件sing_detail,在父组件中改变属性showMoreDec值为true

 data () {
showMoreDec: false
}
 methods: {16
 _alertfn () {
      this.showMoreDec = true
    },
    _closefn () {
      this.showMoreDec = false
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容