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 相关文章推荐
JavaScript 创建对象和构造类实现代码
Jul 30 Javascript
javascript十个最常用的自定义函数(中文版)
Sep 07 Javascript
jQuery实现表头固定效果的实例代码
May 24 Javascript
javascript中typeof的使用示例
Dec 19 Javascript
node.js中的fs.fchmodSync方法使用说明
Dec 16 Javascript
ECMAScript 6即将带给我们新的数组操作方法前瞻
Jan 06 Javascript
JQuery中DOM事件冒泡实例分析
Jun 13 Javascript
uploadify多文件上传参数设置技巧
Nov 16 Javascript
jQuery过滤选择器用法示例
Sep 12 Javascript
angularjs实现搜索的关键字在正文中高亮出来
Jun 13 Javascript
JavaScript中严格判断NaN的方法
Feb 16 Javascript
详解nginx配置vue h5 history去除#号
Nov 09 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 ajax 静态分页过程形式
2011/09/02 PHP
php函数间的参数传递(值传递/引用传递)
2013/09/23 PHP
thinkphp集成前端脚手架Vue-cli的教程图解
2018/08/30 PHP
关于php开启错误提示的总结
2019/09/24 PHP
jQuery之end()和pushStack()使用介绍
2012/02/07 Javascript
关于JS控制代码暂停的实现方法分享
2012/10/11 Javascript
javascript arguments使用示例
2014/12/16 Javascript
JavaScript限定图片显示大小的方法
2015/03/11 Javascript
JavaScript创建对象的方式小结(4种方式)
2015/12/17 Javascript
JS中用三种方式实现导航菜单中的二级下拉菜单
2016/10/31 Javascript
jQuery插件FusionCharts绘制2D环饼图效果示例【附demo源码】
2017/04/10 jQuery
gulp解决跨域的配置文件问题
2017/06/08 Javascript
mpvue跳转页面及注意事项
2018/08/03 Javascript
vue中render函数的使用详解
2018/10/12 Javascript
对 Vue-Router 进行单元测试的方法
2018/11/05 Javascript
详解react native页面间传递数据的几种方式
2018/11/07 Javascript
Vue项目部署在Spring Boot出现页面空白问题的解决方案
2018/11/26 Javascript
vue组件之间通信实例总结(点赞功能)
2018/12/05 Javascript
实例讲解JS中pop使用方法
2019/01/27 Javascript
Python搭建FTP服务器的方法示例
2018/01/19 Python
解决win64 Python下安装PIL出错问题(图解)
2018/09/03 Python
Python3安装Pillow与PIL的方法
2019/04/03 Python
Django 多环境配置详解
2019/05/14 Python
Django ImageFiled上传照片并显示的方法
2019/07/28 Python
python3爬虫中异步协程的用法
2020/07/10 Python
Python如何使用ConfigParser读取配置文件
2020/11/12 Python
html5 Canvas画图教程(5)—canvas里画曲线之arc方法
2013/01/09 HTML / CSS
香港网上花店:FlowerAdvisor香港
2019/05/30 全球购物
趣天网日本站:Qoo10 JP
2019/09/18 全球购物
机械设计及其自动化专业推荐信
2013/10/31 职场文书
教师自我鉴定
2013/12/13 职场文书
《谁的本领大》教后反思
2014/04/25 职场文书
农村党支部书记党群众路线四风问题整改措施
2014/09/26 职场文书
党的群众路线教育实践活动调研报告
2014/11/03 职场文书
校长师德表现自我评价
2015/03/05 职场文书
新兵入伍决心书
2015/09/22 职场文书