xgqfrms™, xgqfrms® : xgqfrms's offical website of cnblogs! xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!

taro scroll tabs 滚动标签 切换

taro scroll tabs

滚动标签 切换

https://www.cnblogs.com/lml-lml/p/10954069.html

https://developers.weixin.qq.com/community/develop/doc/000cc0b94ac5f8dcf4e7666475b804

https://blog.csdn.net/weixin_42860683/article/details/83817925

https://juejin.im/post/5d563b5e6fb9a06b317b5d20

taro


import Taro, {
  Component,
} from '@tarojs/taro'
import {
  View,
  Text,
  ScrollView,
} from '@tarojs/components'

import classnames from 'classnames'
import './TabList.scss'

export default class TabList extends Component {
  state = {
    active: 0,
  }

  componentWillMount() {
    this.setState({
      active: this.props.current || 0,
    })
  }

  componentDidMount() {

  }

  componentWillReceiveProps(nextProps) {
    const { current } = nextProps
    if (current !== this.props.current) {
      this.setState({
        active: current,
      })
    }
  }

  onSelectTab(index) {
    this.setState({
      active: index,
    })
    this.props.onSelected && this.props.onSelected(index)
  }

  render() {
    let { tabs, tabItemStyle, scrollWithAnimation } = this.props
    let { active } = this.state
    return (
      tabs.length && <ScrollView className="tab-list" scrollX scrollWithAnimation={scrollWithAnimation}
        scrollIntoView={`tab-${active >= 2 ? (active - 2) : 0}`}
      >
        <View className="tab-list__container">
          {
            tabs.map((item, index) => {
              return (
                <View style={tabItemStyle} className={classnames([
                  'tab-item',
                  {
                    active: active === index,
                  },
                ])} onClick={this.onSelectTab.bind(this, index)} key={index} id={`tab-` + index}
                >
                  <Text>{item.name}</Text>
                  <View className="tab-line"></View>
                </View>
              )
            })
          }
        </View>

      </ScrollView>
    )
  }
}
TabList.defaultProps = {
  tabs: [],
  current: 0,
  tabItemStyle: 'height:78rpx',
  scrollWithAnimation: process.env.TARO_ENV === 'weapp',
}



scroll tab 组件

开发一个可以滚动的tab组件

https://github.com/ScoutYin/ly-tab#readme

https://github.com/ScoutYin/ly-tab/tree/master/src

https://www.cnblogs.com/lml-lml/p/10954069.html

window.requestAnimationFrame

animation


export function windowInit () {
  var lastTime = 0
  var vendors = ['webkit', 'moz']
  for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']
    window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || // name has changed in Webkit
                                  window[vendors[x] + 'CancelRequestAnimationFrame']
  }

  if (!window.requestAnimationFrame) {
    window.requestAnimationFrame = function (callback, element) {
      var currTime = new Date().getTime()
      var timeToCall = Math.max(0, 16.7 - (currTime - lastTime))
      var interval = currTime - lastTime
      var id = window.setTimeout(function () {
        callback(interval)
      }, timeToCall)
      lastTime = currTime + timeToCall
      return id
    }
  }
  if (!window.cancelAnimationFrame) {
    window.cancelAnimationFrame = function (id) {
      clearTimeout(id)
    }
  }
}

touch event


  methods: {
    // start
    handleTouchStart (event) {
      event.stopPropagation()
      cancelAnimationFrame(this.inertiaFrame)
      this.lastX = event.touches[0].clientX
    },
    // move
    handleTouchMove (event) {
      if (this.listWidth <= 0) return
      event.preventDefault()
      event.stopPropagation()
      this.touching = true
      this.startMoveTime = this.endMoveTime
      this.startX = this.lastX
      this.currentX = event.touches[0].clientX
      this.moveFollowTouch()
      this.endMoveTime = event.timeStamp // 每次触发touchmove事件的时间戳;
    },
    // end
    handleTouchEnd (event) {
      this.touching = false
      if (this.checkReboundX()) {
        cancelAnimationFrame(this.inertiaFrame)
      } else {
        let silenceTime = event.timeStamp - this.endMoveTime
        let timeStamp = this.endMoveTime - this.startMoveTime
        timeStamp = timeStamp > 0 ? timeStamp : 8
        if (silenceTime > 100) return  // 停顿时间超过100ms不产生惯性滑动;
        this.speed = (this.lastX - this.startX) / timeStamp
        this.acceleration = this.speed / this.sensitivity
        this.frameStartTime = new Date().getTime()
        this.inertiaFrame = requestAnimationFrame(this.moveByInertia)
      }
    },
    // 如果需要回弹则进行回弹操作并返回true;
    checkReboundX () {
      this.reBounding = false
      if (this.translateX > 0) {
        this.reBounding = true
        this.translateX = 0
      } else if (this.translateX < -this.listWidth) {
        this.reBounding = true
        this.translateX = -this.listWidth
      }
      return this.translateX === 0 || this.translateX === -this.listWidth
    },
    bindEvent () {
      this.$el.addEventListener('touchstart', this.handleTouchStart, false)
      this.$el.addEventListener('touchmove', this.handleTouchMove, false)
      this.$el.addEventListener('touchend', this.handleTouchEnd, false)
    },
    removeEvent () {
      this.$el.removeEventListener('touchstart', this.handleTouchStart)
      this.$el.removeEventListener('touchmove', this.handleTouchMove)
      this.$el.removeEventListener('touchend', this.handleTouchEnd)
    },
    // touch拖动
    moveFollowTouch () {
      if (this.isMoveLeft) { // 向左拖动
        if (this.translateX <= 0 && this.translateX + this.listWidth > 0 || this.translateX > 0) {
          this.translateX += this.currentX - this.lastX
        } else if (this.translateX + this.listWidth <= 0) {
          this.translateX += this.additionalX * (this.currentX - this.lastX)
                             / (this.viewAreaWidth + Math.abs(this.translateX + this.listWidth))
        }
      } else { // 向右拖动
        if (this.translateX >= 0) {
          this.translateX += this.additionalX * (this.currentX - this.lastX)
                             / (this.viewAreaWidth + this.translateX)
        } else if ((this.translateX <= 0 && this.translateX + this.listWidth >= 0) ||
          this.translateX + this.listWidth <= 0) {
            this.translateX += this.currentX - this.lastX
        }
      }
      this.lastX = this.currentX
    },
    // 惯性滑动
    moveByInertia () {
      this.frameEndTime = new Date().getTime()
      this.frameTime = this.frameEndTime - this.frameStartTime
      if (this.isMoveLeft) { // 向左惯性滑动;
        if (this.translateX <= -this.listWidth) { // 超出边界的过程;
          // 加速度指数变化;
          this.acceleration *= (this.reBoundExponent +
                               Math.abs(this.translateX + this.listWidth)) /
                               this.reBoundExponent
          this.speed = Math.min(this.speed - this.acceleration, 0) // 为避免减速过程过短,此处加速度没有乘上frameTime;
        } else {
          this.speed = Math.min(this.speed - this.acceleration * this.frameTime, 0)
        }
      } else if (this.isMoveRight) { // 向右惯性滑动;
        if (this.translateX >= 0) {
          this.acceleration *= (this.reBoundExponent + this.translateX) / this.reBoundExponent
          this.speed = Math.max(this.speed - this.acceleration, 0)
        } else {
          this.speed = Math.max(this.speed - this.acceleration * this.frameTime, 0)
        }
      }
      this.translateX += this.speed * this.frameTime / 2
      if (Math.abs(this.speed) <= this.zeroSpeed) {
        this.checkReboundX()
        return
      }
      this.frameStartTime = this.frameEndTime
      this.inertiaFrame = requestAnimationFrame(this.moveByInertia)
    },
    // 计算activeBar的translateX
    calcBarPosX () {
      if (this.fixBottom || !this.$children.length) return
      if (this.$children.length <= this.value) return
      const item = this.$children[this.value].$el
      const itemWidth = item.offsetWidth
      const itemLeft = item.offsetLeft
      this.activeBarWidth = Math.max(itemWidth * 0.6, 14)
      this.activeBarX = itemLeft + (itemWidth - this.activeBarWidth) / 2
    },
    // 点击切换item时,调整位置使当前item尽可能往中间显示
    checkPosition () {
      if (this.fixBottom || !this.$children.length) return
      if (this.$children.length <= this.value) return
      const activeItem = this.$children[this.value].$el
      const offsetLeft = activeItem.offsetLeft
      const half = (this.viewAreaWidth - activeItem.offsetWidth) / 2
      let changeX = 0
      const absTransX = Math.abs(this.translateX)
      if (offsetLeft <= absTransX + half) { // item偏左,需要往右移
        let pageX = offsetLeft + this.translateX
        changeX = half - pageX
      } else { // item偏右,需要往左移
        changeX = -(offsetLeft - absTransX - half)
      }
      let lastX = changeX + this.translateX
      // 两种边界情况
      lastX > 0 && (lastX = 0)
      lastX < -this.listWidth && (lastX = -this.listWidth)
      this.reBounding = true
      this.translateX = lastX
    }
  }


©xgqfrms 2012-2020

www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!


posted @ 2020-03-27 16:37  xgqfrms  阅读(1443)  评论(5编辑  收藏  举报