使用Taro实现红包摇一摇的效果

299 阅读1分钟

对于使用Taro实现红包摇一摇的效果

在 Taro 中实现红包摇一摇的效果可以按照以下步骤操作:

  1. 通过 Taro.startAccelerometer() 打开手机的加速计功能。
  2. 在页面渲染完成后,监听手机加速计数值的变化,当手机在三个方向(x、y、z)上的加速度偏差较大时,认为手机进行了震动或摇晃的动作。
  3. 根据触发条件,触发摇一摇红包雨的效果。这里可以使用 Taro 自带的动画组件以及 setTimeout 定时器来实现一个简单的红包雨下落效果。
  4. 在摇一摇过程中可以通过 Taro.stopAccelerometer() 方法来关闭加速计功能。

实现红包摇一摇的代码如下所示:

import Taro, { Component } from '@tarojs/taro'
import { View, Image, Text, Button } from '@tarojs/components'
import './index.less'class Shake extends Component {
  config = {
    navigationBarTitleText: '摇一摇',
    backgroundColor: '#ffffff'
  }
​
  state = {
    shaking: false,
    redEnvelopeList: []
  }
​
  shakeRedEnvelope = () => {
    const { shaking, redEnvelopeList } = this.state
    if (shaking || redEnvelopeList.length > 0) return
​
    let x, y, z, lastX, lastY, lastZ, diff // 定义加速度数据变量
    let waitTime = 0 // 定义等待时间变量,用于控制重力感应采集频率
    const INTERVAL = 200 // 重力感应数据采集频率,单位毫秒
    const SHAKE_THRESHOLD = 700 // 触发摇一摇的加速度差值阈值
​
    Taro.startAccelerometer() // 开启手机加速计数据监听
​
    let shakeInterval = setInterval(() => {
      waitTime += INTERVAL
      if (waitTime < 2000) return // 等待两秒后才开始检测摇一摇事件,避免误操作
​
      Taro.onAccelerometerChange(({ x, y, z }) => {
        if (!lastX) {
          lastX = x
          lastY = y
          lastZ = z
          return
        }
​
        diff = Math.abs(x + y + z - lastX - lastY - lastZ)
​
        if (diff >= SHAKE_THRESHOLD) {
          this.triggerRedEnvelopeRain()
        }
​
        lastX = x
        lastY = y
        lastZ = z
      })
    }, INTERVAL)
    this.setState({ shaking: true, shakeInterval })
​
    setTimeout(() => {
      clearInterval(shakeInterval)
      Taro.stopAccelerometer()
      this.setState({ shaking: false })
    }, 5000)
  }
​
  triggerRedEnvelopeRain = () => {
    const redEnvelopeList = []
​
    for (let i = 0; i < 10; i++) {
      redEnvelopeList.push({
        id: Date.now().toString() + Math.random(),
        left: Math.floor(Math.random() * 250),
        top: -50,
        scale: Math.random() * 2 + 1
      })
    }
​
    this.setState({ redEnvelopeList }, () => {
      setTimeout(() => {
        this.setState({ redEnvelopeList: [] })
      }, 3000)
    })
  }
​
  render() {
    const { shaking, redEnvelopeList } = this.state
​
    const redEnvelopeRain = redEnvelopeList.map(redEnvelope => {
      return (
        <View
          key={redEnvelope.id}
          className='red-envelope-item'
          style={{ left: `${redEnvelope.left}px`, top: `${redEnvelope.top}px` }}
          animation={[
            {
              className: 'move',
              duration: 2000,
              timingFunction: 'linear',
              delay: 0
            },
            {
              className: 'fall',
              duration: 1500,
              timingFunction: 'ease-in-out',
              delay: 500
            }
          ]}
        >
          <Image src='https://cdn.jsdelivr.net/gh/lin-xin/wxapp/red-envelope.png' mode='widthFix' style={{ width: `${36 * redEnvelope.scale}px` }} />
        </View>
      )
    })
​
    return (
      <View className='shake'>
        <View className='tishi-text'>{shaking ? '红包可下雨!' : '摇一摇获取红包'}</View>
        <View className='shake-content'>
          <Button className='shake-btn' onClick={this.shakeRedEnvelope}>摇一摇</Button>
          <View className='shake-image-container' animation={shaking ? 'ani-shake' : ''}>
            <Image className='shake-image' src='https://cdn.jsdelivr.net/gh/lin-xin/wxapp/shake.png' mode='widthFix' />
          </View>
        </View>
        {redEnvelopeRain}
      </View>
    )
  }
}
export default Shake