1.项目常常须要无缝滚动效果,当时写jq的时候用用msClass这个老插件,相对不上很好用。2.后来转向vue在vue-awesome没有找到好的无缝滚动插件,除了配置swiper能够实现可是相对来讲过重了,因而本身造了个轮子。javascript
3.在这分享下,当时写这个插件的坑,本身也复习下,若是代码上有瑕疵欢迎指出。html
html
1.solt提供默认插槽位来放置父组件传入的htmlvue
<template> <div @mouseenter="enter" @mouseleave="leave"> <div ref="wrapper" :style="pos"> <slot></slot> </div> </div> </template>
javascript
1.animationFrame 动画api兼容处理java
2.arrayEqual 判断数组是否相等 来监听data的变化来实现更新无缝滚动git
<script> require('comutils/animationFrame') //requestAnimationFrame api const arrayEqual = require('comutils/arrayEqual') export default { data () { return { yPos: 0, reqFrame: null } }, props: { data: { // data 数据 type: Array, default: [] }, classOption: { //参数 type: Object, default: {} } }, computed: { pos () { // 给父元素的style return {transform: `translate(0,${this.yPos}px)`} }, defaultOption () { return { step: 1, //步长 limitMoveNum: 5, //启动无缝滚动最小数据数 hoverStop: true, //是否启用鼠标hover控制 direction: 1 //1 往上 0 往下 } }, options () { // 合并参数 return Object.assign({}, this.defaultOption, this.classOption) } , moveSwitch () { //判断传入的初始滚动值和data的length来控制是否滚动 return this.data.length < this.options.limitMoveNum } }, methods: { enter () { if (!this.options.hoverStop || this.moveSwitch) return cancelAnimationFrame(this.reqFrame) }, leave () { if (!this.options.hoverStop || this.moveSwitch) return this._move() }, _move () { //滚动 this.reqFrame = requestAnimationFrame( () => { let h = this.$refs.wrapper.offsetHeight / 2 let direction = this.options.direction if (direction === 1) { if (Math.abs(this.yPos) >= h) this.yPos = 0 } else { if (this.yPos >= 0) this.yPos = h * -1 } if (direction === 1) { this.yPos -= this.options.step } else { this.yPos += this.options.step } this._move() } ) }, _initMove () { if (this.moveSwitch) { cancelAnimationFrame(this.reqFrame) this.yPos = 0 } else { this.$emit('copyData') //须要copy复制一份 emit到父元素 后期版本这里已经优化 if (this.options.direction !== 1) { setTimeout(() => { this.yPos = this.$refs.wrapper.offsetHeight / 2 * -1 }, 20) } this._move() } } }, mounted () { this._initMove() }, watch: { //监听data的变化 data (newData, oldData) { if (!arrayEqual(newData, oldData.concat(oldData))) { cancelAnimationFrame(this.reqFrame) this._initMove() } } } } </script>
有兴趣能够看本次commit记录 myClass.vue的更改github
commit记录api
commit记录数组
//本来组件调用 <my-class :data="listData" :class-option="classOption" @copy-data="listData = listData.concat(listData)"> //简化后组件调用 <my-class :data="listData" :class-option="classOption" class="warp">
用js的来复制一份innerHtml来代替以前的作法简化使用 //this.$emit('copyData') timer = setTimeout(() => { //20ms延迟 做用保证能取到最新的html this.copyHtml = this.$refs.slotList.innerHTML }, 20) // template <template> <div @mouseenter="enter" @mouseleave="leave" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd"> <div ref="wrap" :style="pos"> <div ref="slotList" :style="float"> <slot></slot> </div> <div v-html="copyHtml" :style="float"></div> </div> </div> </template>
commit记录app
这个问题的缘由查了比较久最后发现是当时没有加return没有取到定时器idless
相似上下能够查看commit
import vueMyCLass from './components/myClass.vue' let myScroll const defaultComponentName = 'vue-seamless-scroll' // expose component to global scope if (typeof window !== 'undefined' && window.Vue) { Vue.component('vue-seamless-scroll', vueMyCLass) } else { myScroll = { install: function (Vue, options = {}) { Vue.component(options.componentName || defaultComponentName, vueMyCLass) } } } export default myScroll
//1.封装屡次调用的取消动画方法
_cancle: function _cancle() { cancelAnimationFrame(this.reqFrame || ''); },
//2.touchMove频繁快速操做致使滚动错乱bug
_move () { this._cancle() //进入move当即先清除动画 防止频繁touchMove致使多动画同时进行 }
//3.生命周期结束前取消动画
beforeDestroy () { this._cancle() }
//4.修复不传参数报警告的bug
props: { data: { type: Array, default: () => { return [] } }, classOption: { type: Object, default: () => { return {} } } }
//5.Fixing a bug. add a overflow:hidden on the child element
部分人喜欢用margin-top若是没有overflow等限制会致使我里面计算高度和实际有些许差距致使最后效果到临界位置有轻微抖动
//默认加上了overflow: 'hidden'
computed: { float () { return this.options.direction > 1 ? {float: 'left', overflow: 'hidden'} : {overflow: 'hidden'} }, pos () { return { transform: `translate(${this.xPos}px,${this.yPos}px)`, transition: `all ease-in ${this.delay}ms`, overflow: 'hidden' } } }
//6.新增单步滚动也能hover中止的功能
以前由于单步滚动内置了延迟执行this._move()默认单步限制了鼠标悬停中止无缝滚动,后来经过给this._move()加上开关达到效果。
若是对原生js实现相似的无缝滚动有兴趣能够留言,我抽空也能够写下seamless-scroll
vue-seamless-scroll发现bug或者有什么不足望指点,感受不错点个star吧。