Vue2.0 实现歌手列表滚动及右侧快速入口功能


Posted in Javascript onAugust 08, 2018

1 歌手列表

歌手列表页类似于手机通讯录,我们也将其作为一个基础组件独立出来,这部分的逻辑比较简单,这里不做过多的讲解

// base/listview/listview.vue
<template>
  <scroll class="listview" :data="data">
    <ul>
      <li v-for="(group, index) in data" :key="index" class="list-group">
        <h2 class="list-group-title">{{group.title}}</h2>
        <uL>
          <li v-for="(item, index) in group.items" :key="index" class="list-group-item">
            <img class="avatar" v-lazy="item.avatar">
            <span class="name">{{item.name}}</span>
          </li>
        </uL>
      </li>
    </ul>
  </scroll>
</template>
<script type="text/ecmascript-6">
  import Scroll from 'base/scroll/scroll'
  export default {
    props: {
      data: {
        type: Array,
        default: () => []
      }
    },
    components: {
      Scroll
    }
  }
</script>
<style scoped lang="stylus" rel="stylesheet/stylus">
  @import "~common/stylus/variable"
  .listview
    position: relative
    width: 100%
    height: 100%
    overflow: hidden
    background: $color-background
    .list-group
      padding-bottom: 30px
      .list-group-title
        height: 30px
        line-height: 30px
        padding-left: 20px
        font-size: $font-size-small
        color: $color-text-l
        background: $color-highlight-background
      .list-group-item
        display: flex
        align-items: center
        padding: 20px 0 0 30px
        .avatar
          width: 50px
          height: 50px
          border-radius: 50%
        .name
          margin-left: 20px
          color: $color-text-l
          font-size: $font-size-medium
    .list-shortcut
      position: absolute
      z-index: 30
      right: 0
      top: 50%
      transform: translateY(-50%)
      width: 20px
      padding: 20px 0
      border-radius: 10px
      text-align: center
      background: $color-background-d
      font-family: Helvetica
      .item
        padding: 3px
        line-height: 1
        color: $color-text-l
        font-size: $font-size-small
        &.current
          color: $color-theme
          font-weight: bolder
    .list-fixed
      position: absolute
      top: -1px
      left: 0
      width: 100%
      .fixed-title
        height: 30px
        line-height: 30px
        padding-left: 20px
        font-size: $font-size-small
        color: $color-text-l
        background: $color-highlight-background
    .loading-container
      position: absolute
      width: 100%
      top: 50%
      transform: translateY(-50%)
</style>
// singer.vue
<template>
 <div class="singer">
  <list-view :data="singerList"></list-view>
 </div>
</template>
<script type="text/ecmascript-6">
 import ListView from 'base/listview/listview'
 export default {
  ...
  components: {
   ListView
  }
 }
</script>

Vue2.0 实现歌手列表滚动及右侧快速入口功能 

运行结果

2 右侧快速入口_点击滚动

同样是类比于手机通讯录,悬浮于屏幕右侧的 A-Z 可以帮助我们快速找到对应的歌手,为此,我们需要获取 title 的集合数组

// listview.vue
<div class="list-shortcut">
  <ul>
    <li v-for="(item, index) in shortcutList" :key="index" class="item">{{item}}</li>
  </ul>
</div>
<script type="text/ecmascript-6">
  export default {
    ...
    computed: {
      shortcutList() {
        return this.data.map((group) => {
          return group.title.substr(0, 1)
        })
      }
    }
  }
</script>

Vue2.0 实现歌手列表滚动及右侧快速入口功能 

运行结果

快速入口出现了之后,我们接下来就为其添加点击事件,当我们点击对应字母时,需要获取其索引,这里我们直接获取 v-for 提供的 index 即可

// listview.vue
<ul>
  <li v-for="(item, index) in shortcutList" :key="index" @touchstart="onShortcutTouchStart($even, index)" class="item">{{item}}</li>
</ul>
export default {
  ...
  methods: {
    onShortcutTouchStart(e, index) {
      console.log(index)
    }
  }
}

点击之后,我们需要页面滚动到相应位置,这里需要扩展 scroll 组件的方法,这里扩展的方法都是来自 better-scroll 组件所封装的方法,这里提一下 scrollToElement 方法的第二个参数是动画时间,可根据自身需求进行设置

// scroll.vue
methods: {
 ...
 scrollTo() {
  this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
 },
 scrollToElement() {
  this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
 }
}

随后给 scroll 组件添加 ref="listview" 以及歌手列表添加 ref="listGroup" 方便我们调用

// listview.vue
export default {
  ...
  methods: {
    onShortcutTouchStart(e, index) {
      this.$refs.listview.scrollToElement(this.$refs.listGroup[index], 0)
    }
  }
}

Vue2.0 实现歌手列表滚动及右侧快速入口功能 

运行结果

3 右侧快速入口_滑动滚动

当我们的手指在右侧快速入口上滑动时,歌手列表也会同步进行滚动,当我们滚动右侧快速入口时,我们需要阻止歌手列表滚动,以及浏览器原生滚动,所以要使用 @touchmove.stop.prevent 阻止冒泡,并且在 onShortcutTouchStart 事件中记录触碰点的初始位置,以及 onShortcutTouchMove 事件中触碰点的位置,通过两个位置的像素差,来滚动歌手列表

// listview.vue
<div class="list-shortcut" @touchmove.stop.prevent="onShortcutTouchMove">
  <ul>
    <li v-for="(item, index) in shortcutList" :key="index" @touchstart="onShortcutTouchStart($event, index)" class="item">{{item}}</li>
  </ul>
</div>
<script type="text/ecmascript-6">
  const ANCHOR_HEIGHT = 18
  export default {
    created() {
      this.touch = {}
    },
    ...
    methods: {
      onShortcutTouchStart(e, index) {
        let firstTouch = e.touches[0]
        this.touch.y1 = firstTouch.pageY
        this.touch.anchorIndex = index
        this._scrollTo(index)
      },
      onShortcutTouchMove(e) {
        let firstTouch = e.touches[0]
        this.touch.y2 = firstTouch.pageY
        let delta = (this.touch.y2 - this.touch.y1) / ANCHOR_HEIGHT | 0
        let anchorIndex = this.touch.anchorIndex + delta
        this._scrollTo(anchorIndex)
      },
      _scrollTo(index) {
        this.$refs.listview.scrollToElement(this.$refs.listGroup[index], 0)
      }
    },
    components: {
      Scroll
    }
  }
</script>

Vue2.0 实现歌手列表滚动及右侧快速入口功能 

运行结果

4 右侧快速入口_高亮设置

当歌手列表滚动时,我们想要在右侧快速入口中,高亮当前显示的 title ,这就需要我们监听 scroll 组件的滚动事件,来获取当前滚动的位置

// scroll.vue
<script type="text/ecmascript-6">
 export default {
  props: {
   ...
   listenScroll: {
    type: Boolean,
    default: false
   }
  },
  methods: {
   _initScroll() {
    ...
    if (this.listenScroll) {
     let me = this
     this.scroll.on('scroll', (pos) => {
      me.$emit('scroll', pos)
     })
    }
   }
  }
 }
</script>

我们当初给参数 probeType 设的默认值为 1,即会非实时(屏幕滑动超过一定时间后)派发 scroll 事件,我们在屏幕滑动的过程中,需要实时派发 scroll 事件,所以在 listview 中将 probeType 的值设为 3

// listview.vue
<template>
    <scroll class="listview"
            :data="data"
            ref="listview"
            :probe-type="probeType"
            :listenScroll="listenScroll"
            @scroll="scroll">
        <ul>
            ...
        </ul>
        <div class="list-shortcut" @touchmove.stop.prevent="onShortcutTouchMove">
            <ul>
                <li v-for="(item, index) in shortcutList"
                    :key="index"
                    :class="{'current':currentIndex===index}"
                    @touchstart="onShortcutTouchStart($event, index)"
                    class="item">{{item}}</li>
            </ul>
        </div>
    </scroll>
</template>
<script type="text/ecmascript-6">
    export default {
        created() {
            ...
            this.listHeight = []
            this.probeType = 3
        },
        data() {
            return {
                scrollY: -1,
                currentIndex: 0
            }
        },
        methods: {
            ...
            scroll(pos) {
                this.scrollY = pos.y
            },
            _scrollTo(index) {
                this.scrollY = -this.listHeight[index]
                this.$refs.listview.scrollToElement(this.$refs.listGroup[index], 0)
            },
            _calculateHeight() {
                this.listHeight = []
                const list = this.$refs.listGroup
                let height = 0
                this.listHeight.push(height)
                for (let i = 0; i < list.length; i++) {
                    let item = list[i]
                    height += item.clientHeight
                    this.listHeight.push(height)
                }
            }
        },
        watch: {
            data() {
                this.$nextTick(() => {
                    this._calculateHeight()
                })
            },
             scrollY(newY) {
                const listHeight = this.listHeight
                // 当滚动到顶部,newY>0
                if (newY > 0) {
                    this.currentIndex = 0
                    return
                }
                // 在中间部分滚动
                for (let i = 0; i < listHeight.length - 1; i++) {
                    let height1 = listHeight[i]
                    let height2 = listHeight[i + 1]
                    if (-newY >= height1 && -newY < height2) {
                        this.currentIndex = i
                        return
                    }
                }
                // 当滚动到底部,且-newY大于最后一个元素的上限
                this.currentIndex = listHeight.length - 2
            }
        },
        components: {
            Scroll
        }
    }
</script>

Vue2.0 实现歌手列表滚动及右侧快速入口功能 

运行结果

5 滚动固定标题

当我们滚动歌手列表页时,希望该歌手的 title 一直显示在顶部,并且滚动到下一个 title 时,新的 title 将旧的 title 顶替掉,这里就需要我们计算一个 title 的高度

// listview.vue
<template>
    <scroll class="listview"
            :data="data"
            ref="listview"
            :probe-type="probeType"
            :listenScroll="listenScroll"
            @scroll="scroll">
        ...
        <div class="list-fixed" ref="fixed" v-show="fixedTitle">
            <div class="fixed-title">{{fixedTitle}}</div>
        </div>
    </scroll>
</template>
<script type="text/ecmascript-6">
    import Scroll from 'base/scroll/scroll'
    const TITLE_HEIGHT = 28
    const ANCHOR_HEIGHT = 18
    export default {
        ...
        data() {
            return {
                scrollY: -1,
                currentIndex: 0,
                diff: -1
            }
        },
        computed: {
            ...
            fixedTitle() {
                if (this.scrollY > 0) {
                    return ''
                }
                return this.data[this.currentIndex] ? this.data[this.currentIndex].title : ''
            }
        },
        watch: {
            ...
            scrollY(newY) {
                ...
                for (let i = 0; i < listHeight.length - 1; i++) {
                    ...
                    if (-newY >= height1 && -newY < height2) {
                        ...
                        this.diff = height2 + newY
                        return
                    }
                }
                ...
            },
            diff(newVal) {
                let fixedTop = (newVal > 0 && newVal < TITLE_HEIGHT) ? newVal - TITLE_HEIGHT : 0
                if (this.fixedTop === fixedTop) {
                    return
                }
                this.fixedTop = fixedTop
                this.$refs.fixed.style.transform = `translate3d(0,${fixedTop}px,0)`
            }
        }
    }
</script>

Vue2.0 实现歌手列表滚动及右侧快速入口功能 

运行结果

该章节的内容到这里就全部结束了,源码我已经发到了 GitHub Vue_Music_06 上了,有需要的同学可自行下载

总结

以上所述是小编给大家介绍的Vue2.0 实现歌手列表滚动及右侧快速入口功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
Dom加载让图片加载完再执行的脚本代码
May 15 Javascript
js实现tab切换效果实例
Sep 16 Javascript
最简单的JavaScript图片轮播代码(两种方法)
Dec 18 Javascript
Bootstrap里的文件分别代表什么意思及其引用方法
May 01 Javascript
Vue.js手风琴菜单组件开发实例
May 16 Javascript
利用JS测试目标网站的打开响应速度
Dec 01 Javascript
在Vue中使用Compass的方法
Mar 02 Javascript
用ES6写全屏滚动插件的示例代码
May 02 Javascript
微信小程序收藏功能的实现代码
Jun 12 Javascript
vue实现路由懒加载及组件懒加载的方式
Jun 11 Javascript
angular6开发steps步骤条组件
Jul 04 Javascript
js点击事件的执行过程实例分析【冒泡与捕获】
Apr 11 Javascript
JavaScript引用类型Date常见用法实例分析
Aug 08 #Javascript
js使用ajax传值给后台,后台返回字符串处理方法
Aug 08 #Javascript
JavaScript引用类型Object常见用法实例分析
Aug 08 #Javascript
微信小程序wepy框架笔记小结
Aug 08 #Javascript
angularJs中$http获取后台数据的实例讲解
Aug 08 #Javascript
JavaScript常见JSON操作实例分析
Aug 08 #Javascript
vue.js与后台数据交互的实例讲解
Aug 08 #Javascript
You might like
php开发文档 会员收费1期
2012/08/14 PHP
Java中final关键字详解
2015/08/10 PHP
php使用yield对性能提升的测试实例分析
2019/09/19 PHP
简单实用jquery版三级联动select示例
2013/07/04 Javascript
JavaScript操作XML/HTML比较常用的对象属性集锦
2015/10/30 Javascript
详解JavaScript的回调函数
2015/11/20 Javascript
原生js页面滚动延迟加载图片
2015/12/20 Javascript
浅析Javascript中bind()方法的使用与实现
2016/05/30 Javascript
JavaScript中的this引用(推荐)
2016/08/05 Javascript
JavaScript 计算笛卡尔积实例详解
2016/12/02 Javascript
JS封装通过className获取元素的函数示例
2016/12/20 Javascript
原生JS轮播图插件
2017/02/09 Javascript
详解Vue的钩子函数(路由导航守卫、keep-alive、生命周期钩子)
2018/07/24 Javascript
javascript实现点击产生随机图形
2021/01/25 Javascript
Python Mysql数据库操作 Perl操作Mysql数据库
2009/01/12 Python
介绍Python中的__future__模块
2015/04/27 Python
Python中的if、else、elif语句用法简明讲解
2016/03/11 Python
python字符类型的一些方法小结
2016/05/16 Python
Python实现的当前时间多加一天、一小时、一分钟操作示例
2018/05/21 Python
解决python opencv无法显示图片的问题
2018/10/28 Python
使用python将请求的requests headers参数格式化方法
2019/01/02 Python
python print出共轭复数的方法详解
2019/06/25 Python
python中的Elasticsearch操作汇总
2019/10/30 Python
Pytorch之view及view_as使用详解
2019/12/31 Python
CSS3之多背景background使用示例
2013/10/18 HTML / CSS
护理专业毕业生推荐信
2013/10/31 职场文书
专业幼师实习生自我鉴定范文
2013/12/08 职场文书
幼儿园教育教学反思
2014/01/31 职场文书
党的群众路线调研报告
2014/11/03 职场文书
家庭财产分割协议书范本
2014/11/24 职场文书
2014年银行个人工作总结
2014/12/05 职场文书
医生辞职信范文
2015/03/02 职场文书
2015年119消防宣传日活动总结
2015/03/24 职场文书
反腐倡廉影片观后感
2015/06/08 职场文书
mysql联合索引的使用规则
2021/06/23 MySQL
cypress测试本地web应用
2022/06/01 Javascript