taro 主题切换_taro scroll tabs 滚动标签 切换

本文介绍如何在Taro中开发一个可以滚动的Tab组件,利用`window.requestAnimationFrame`实现平滑滚动效果,并处理触摸事件进行惯性滑动。通过监听touchstart, touchmove, touchend事件,计算移动速度和加速度,实现触屏滑动时的流畅切换。" 114406082,10716960,Python自动化测试:pytest插件详解,"['Python', '测试框架', 'pytest插件', '自动化测试', '测试工具']
摘要由CSDN通过智能技术生成

taro scroll tabs

滚动标签 切换

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 &&

scrollIntoView={`tab-${active >= 2 ? (active - 2) : 0}`}

>

{

tabs.map((item, index) => {

return (

'tab-item',

{

active: active === index,

},

])} onClick={this.onSelectTab.bind(this, index)} key={index} id={`tab-` + index}

>

{item.name}

)

})

}

)

}

}

TabList.defaultProps = {

tabs: [],

current: 0,

tabItemStyle: 'height:78rpx',

scrollWithAnimation: process.env.TARO_ENV === 'weapp',

}

scroll tab 组件

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

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 发布文章使用:只允许注册用户才可以访问!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值