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:void(0)的问题使用探讨
Apr 10 Javascript
详解js中的apply与call的用法
Jul 30 Javascript
scroll事件实现监控滚动条并分页显示(zepto.js)
Dec 18 Javascript
js实现网页定位导航功能
Mar 07 Javascript
JavaScript 中调用 Kotlin 方法实例详解
Jun 09 Javascript
微信小程序canvas写字板效果及实例
Jun 15 Javascript
vue拖拽排序插件vuedraggable使用方法详解
Aug 21 Javascript
layui复选框限制选择个数的方法
Sep 18 Javascript
Nuxt页面级缓存的实现
Mar 09 Javascript
js+css3实现简单时钟特效
Sep 13 Javascript
基于react项目打包css引用路径错误解决方案
Oct 28 Javascript
如何利用JavaScript编写一个格斗小游戏
Jan 06 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下实现农历日历的代码
2007/03/07 PHP
php gd2 上传图片/文字水印/图片水印/等比例缩略图/实现代码
2010/05/15 PHP
10个对初学者非常有用的PHP技巧
2016/04/06 PHP
php好代码风格的阶段性总结
2016/06/25 PHP
yii2 在控制器中验证请求参数的使用方法
2019/06/19 PHP
js的一些常用方法小结
2011/06/29 Javascript
JS实现同一个网页布局滑动门和TAB选项卡实例
2015/09/23 Javascript
JS实现仿腾讯微博无刷新删除微博效果代码
2015/10/16 Javascript
jQuery Validation Plugin验证插件手动验证
2016/01/26 Javascript
使用vue编写一个点击数字计时小游戏
2016/08/31 Javascript
jquery uploadify隐藏上传进度的实现方法
2017/02/06 Javascript
AngularJS中scope的绑定策略实例分析
2017/10/30 Javascript
JS模拟实现哈希表及应用详解
2018/05/04 Javascript
详解vue文件中使用echarts.js的两种方式
2018/10/18 Javascript
JS函数本身的作用域实例分析
2020/03/16 Javascript
介绍Python的Urllib库的一些高级用法
2015/04/30 Python
Python爬虫信息输入及页面的切换方法
2018/05/11 Python
Python 爬取携程所有机票的实例代码
2018/06/11 Python
python修改txt文件中的某一项方法
2018/12/29 Python
对python条件表达式的四种实现方法小结
2019/01/30 Python
python实现诗歌游戏(类继承)
2019/02/26 Python
Python中字符串String的基本内置函数与过滤字符模块函数的基本用法
2019/05/27 Python
Python基于os.environ从windows获取环境变量
2020/06/09 Python
python切片作为占位符使用实例讲解
2021/02/17 Python
CSS3 2D模拟实现摩天轮旋转效果
2016/11/16 HTML / CSS
Madewell美德威尔美国官网:美国休闲服饰品牌
2016/11/25 全球购物
日本索尼音乐商店:Sony Music Shop
2018/07/17 全球购物
JAVA中的关键字有什么特点
2014/03/07 面试题
几道Java和数据库的面试题
2013/05/30 面试题
信息系统专业个人求职信范文
2013/12/07 职场文书
会计系个人求职信范文分享
2013/12/20 职场文书
社区志愿者活动方案
2014/08/18 职场文书
带香烟到学校抽的检讨书
2014/09/25 职场文书
驾驶员管理制度范本
2015/08/06 职场文书
CSS 伪元素::marker详解
2021/06/26 HTML / CSS
OpenCV绘制圆端矩形的示例代码
2021/08/30 Python