Vue 自动滚动组件

日常代码备份。

最近朋友的项目需要一个简单的纵向滚动效果,同志圈没找到合适的,因而现写了一个,纯当熟悉下Vue开发。

export default {
  name:'AutoScroll',
  props:{
    targetDom:{
      default:null
    },
    target:{
      default:null
    },
    interval:{
      type:Number,
      default:1000
    },
    duration:{
      type:Number,
      default:300
    },
  },
  data:() => ({
    containerStyle:{},
    wrapStyle:{},
    index:0,
    distance:0,
    innerTarget:null,
    binded:false,
    nodeLength:0
  }),
  mounted(){
    this.containerStyle.transition = `transform ${this.duration/1000}s`
    let nodeInstance = this.$children[0]

    nodeInstance.$on('hook:updated' , (e) => {
      this.init()
    })

    //移除附加dom
    nodeInstance.$on('hook:beforeUpdate' , (e) => {
      this.stop()
      if( this.innerTarget ){
        let l = this.nodeLength
        let children = this.innerTarget.children
        for(let i = l - 1; i >= 0 ;i--){
          this.innerTarget.removeChild( children[l+i] )
        }
      }
    })

    function onTransitionEnd(e){
      if(e.target === e.currentTarget){
        console.log('transitionend')
        this.index++
        let l = this.nodeLength

        if( this.index == l ){
          this.distance = 0
          this.index = 0
          this.containerStyle = {
            transition:'none',
            transform:"translateY(0)"
          }
        }

        this.nextFrame()
      }
    }

    let endHandler = onTransitionEnd.bind(this)

    this.$on('hook:beforeDestroy' , () => {
      this.$el.firstElementChild.removeEventListener("transitionend", endHandler)

    })

    this.$el.firstElementChild.addEventListener("transitionend", endHandler)
  },

  methods:{
    searchTarget(node){
      let componentName = this.target
      let name = node.$options._componentTag
      if( name === this.target ){
        return node.$el
      }else{
        if( node.$children ){
          for(let i of node.$children){
            let hit = this.searchTarget(i)
            if( hit ) return hit.$el
          }
        }
      }
      return null
    },
    nextFrame(){
      if( this.handler ){
        clearTimeout(this.handler)
      }
      this.handler = setTimeout( () => {
        this.animate()
      },this.interval)

    },
    update(){
      this.init()
    },
    stop(){
      if( this.handler ){
        this.handler = null
        clearTimeout( this.handler )
      }
    },
    animate(){
      let node = this.innerTarget.children[this.index]
      let distance = this.distance + node.offsetHeight
      this.containerStyle = {
        transition : 'transform 0.3s',
        transform:'translateY(-'+distance+'px)'
      }

      this.distance = distance
    },

    init(){
      this.stop()
      this.index = 0
      this.distance = 0

      let target
      if( this.target ){
        target = this.searchTarget(this)
      }else if( this.targetDom ){
        target = this.$el.querySelector(this.targetDom)
      }

      if( !target ){
        target = this.$el.children[0]
      }

      this.innerTarget = target

      let height = this.$el.offsetHeight;
      let l = target.children.length
      this.nodeLength = l

      let fragment = document.createDocumentFragment()
      for(let i = 0; i<l; i++){
        fragment.appendChild(target.children[i].cloneNode(true))
      }
      target.appendChild(fragment)

      this.wrapStyle = {
        height : height + 'px',
        overflowY : 'hidden'
      }

      this.animate()
    }
  },
  render(){
    let vnode = this.$scopedSlots.default ? this.$scopedSlots.default() : null
    return <div style={this.wrapStyle}><div ref="container" style={this.containerStyle}>{vnode }</div></div>
  }
}
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注