加入购物车抛小球和购物车晃动

抛出小球加到地方对应元素晃动(加入购物车动画)

/*
* 添加到购物车动画 脚本,涉及到键盘弹出时,动画需要延迟100ms执行,以保证键盘已经弹回去,页面元素位置不变
* */

/** *
 * 动画轨迹控制
 * @param addBtnDom 增加按钮的dom元素或者选择器
 * @param shopCarDom 购物车的dom元素或选择器
 */
export default function controllPath(addBtn, shopCar, shopImg) {
  let addBtnDom = null
  let shopCarDom = null
  if (typeof addBtn === 'string') {
    addBtnDom = document.querySelector(addBtn)
  } else if (addBtn instanceof HTMLElement) {
    addBtnDom = addBtn
  } else {
    console.error('加入购物车动画传入的参数错误: 第一个参数应为增加按钮的dom元素或该元素的选择器。')
    return
  }

  if (typeof shopCar === 'string') {
    shopCarDom = document.querySelector(shopCar)
  } else if (shopCar instanceof HTMLElement) {
    shopCarDom = shopCar
  } else {
    console.error('加入购物车动画传入的参数错误: 第二个参数应为增加按钮的dom元素或该元素的选择器。')
    return
  }

  // 获取两个dom的位置
  const addBtnposition = addBtnDom.getBoundingClientRect()
  const shopCarPosition = shopCarDom.getBoundingClientRect()
  const addBtnCenterX = (addBtnposition.left + addBtnposition.right) / 2
  const addBtnCenterY = (addBtnposition.top + addBtnposition.bottom) / 2
  const shopCarCenterX = (shopCarPosition.left + shopCarPosition.right) / 2
  // const shopCarCenterY = (shopCarPosition.top + shopCarPosition.bottom) / 2
  // 计算增加按钮 是在 相对于购物车的 左边还是右边(用于控制后面的移动方向)
  const relativePosition = addBtnCenterX > shopCarCenterX ? -1 : 1

  // 获取连个dom之间的距离
  const xDistance = Math.abs(addBtnCenterX - shopCarCenterX)
  // const yDistance = Math.abs(addBtnCenterY - shopCarCenterY)

  // 绘制小球并设置其位置
  const ballDom = drawBall()
  ballDom.style.top = addBtnCenterY + 'px'
  ballDom.style.left = addBtnCenterX + 'px'
  document.body.appendChild(ballDom)
  /*
     * 根据一元二次方程的轨迹求出对象的系数 y = ax^2 + bx + c
     *  let coefficientC = 0;
     *  let coefficientB = 0;
     *  let coefficientA = yDistance / Math.pow(xDistance, 2);
     */
  // 小球的横竖坐标
  let xAbscissa = 0; let yAbscissa = 0

  const addCount = xDistance / 10 // 计算变化次数
  let curCount = 0 // 当前变化次数
  const onceY = 40 / (addCount / 2) // 每次Y轴移动大小
  // 设置移动路径
  const ballTimer = setInterval(function() {
    curCount += 1
    // 每次重新坐标
    xAbscissa += 10 * relativePosition
    // if ()
    // yAbscissa = (yDistance / Math.pow(xDistance, 2)) * Math.pow(xAbscissa, 2)
    if (curCount <= addCount / 1.5) {
      yAbscissa -= onceY
    } else {
      yAbscissa += onceY
    }
    ballDom.style.top = addBtnCenterY + yAbscissa + 'px'
    ballDom.style.left = addBtnCenterX + xAbscissa + 'px'
    // 检查是否到达终点
    const surplusDistance = parseInt(ballDom.style.left) - shopCarCenterX
    // const surplusDistanceY = parseInt(ballDom.style.top) - shopCarCenterY
    if (Math.abs(surplusDistance) <= 10) {
      clearInterval(ballTimer)
      document.body.removeChild(ballDom)
      
      let shopImgDom = null // 购物车图片
      if (typeof shopImg === 'string') {
        shopImgDom = document.querySelector(shopImg)
      } else if (shopImg instanceof HTMLElement) {
        shopImgDom = shopImg
      } else {
        console.error('加入购物车动画传入的参数错误: 第三个参数应为增加按钮的dom元素或该元素的选择器。')
        return
      }
      let rotateCount = 4 // 购物车图片左右晃动次数
      let rotateVal = 0 // 晃动角度
      const rotateInterval = setInterval(() => {
        if (rotateCount < 0) clearInterval(rotateInterval)
        else rotateCount--
        if (rotateCount === -1) rotateVal = 0 // 结束时摆正
        else rotateVal = 10 * Math.pow(-1, rotateCount) // 晃动角度10,一正一负
        shopImgDom.style.transform = 'rotate(' + rotateVal + 'deg)' // 设置css样式
      }, 100)
    }
  }, 50)
}

/*
* 绘制小球
* */
function drawBall() {
  const ballDom = document.createElement('div')
  ballDom.style.width = '20px'
  ballDom.style.height = '20px'
  ballDom.style.border = '1px solid #ccc'
  ballDom.style.background = '#fa5151'
  ballDom.style.borderRadius = '50%'
  ballDom.style.position = 'absolute'
  ballDom.style.zIndex = 99999
  return ballDom
}

/** *
 * 动画轨迹控制
 * @param addBtnDom 增加按钮的dom元素或者选择器
 * @param shopCarDom 购物车的dom元素或选择器
 */
export const controllGiftPath = (addBtn, shopCar, shopImg, scrollT) => {
  let addBtnDom = null
  let shopCarDom = null
  if (typeof addBtn === 'string') {
    addBtnDom = document.querySelector(addBtn)
  } else if (addBtn instanceof HTMLElement) {
    addBtnDom = addBtn
  } else {
    console.error('加入购物车动画传入的参数错误: 第一个参数应为增加按钮的dom元素或该元素的选择器。')
    return
  }

  if (typeof shopCar === 'string') {
    shopCarDom = document.querySelector(shopCar)
  } else if (shopCar instanceof HTMLElement) {
    shopCarDom = shopCar
  } else {
    console.error('加入购物车动画传入的参数错误: 第二个参数应为增加按钮的dom元素或该元素的选择器。')
    return
  }

  // 获取两个dom的位置
  const addBtnposition = addBtnDom.getBoundingClientRect()
  const shopCarPosition = shopCarDom.getBoundingClientRect()
  const addBtnCenterX = (addBtnposition.left + addBtnposition.right) / 2
  const addBtnCenterY = (addBtnposition.top + addBtnposition.bottom) / 2 + scrollT
  const shopCarCenterX = (shopCarPosition.left + shopCarPosition.right) / 2
  const shopCarCenterY = (shopCarPosition.top + shopCarPosition.bottom) / 2
  // 计算增加按钮 是在 相对于购物车的 左边还是右边(用于控制后面的移动方向)
  const relativePosition = addBtnCenterX > shopCarCenterX ? -1 : 1
  const relativePositionY = addBtnCenterY > shopCarCenterY ? -1 : 1

  // 获取连个dom之间的距离
  const xDistance = Math.abs(addBtnCenterX - shopCarCenterX)
  const yDistance = Math.abs(addBtnCenterY - shopCarCenterY)

  // 绘制小球并设置其位置
  const ballDom = drawBall2()
  ballDom.style.top = addBtnCenterY - 10 * relativePosition + 'px'
  ballDom.style.left = addBtnCenterX - 10 * relativePositionY + 'px'
  document.body.appendChild(ballDom)
  /*
     * 根据一元二次方程的轨迹求出对象的系数 y = ax^2 + bx + c
     *  let coefficientC = 0;
     *  let coefficientB = 0;
     *  let coefficientA = yDistance / Math.pow(xDistance, 2);
     */
  // 小球的横竖坐标
  let xAbscissa = 0; let yAbscissa = 0
  const allTime = 600
  const stepTime = 50
  const moveCount = allTime / stepTime
  const onceX = xDistance / moveCount
  const onceY = yDistance / moveCount
  // const step = 25
  // const addCount = xDistance / step // 计算变化次数
  // const onceY = yDistance / addCount // 每次Y轴移动大小
  // 设置移动路径
  const ballTimer = setInterval(function() {
    // 每次重新坐标
    xAbscissa += onceX * relativePosition
    yAbscissa += onceY * relativePositionY
    
    ballDom.style.top = addBtnCenterY + yAbscissa + 'px'
    ballDom.style.left = addBtnCenterX + xAbscissa + 'px'
    // 检查是否到达终点
    const surplusDistance = parseInt(ballDom.style.left) - shopCarCenterX
    // const surplusDistanceY = parseInt(ballDom.style.top) - shopCarCenterY
    if (Math.abs(surplusDistance) <= 10) {
      clearInterval(ballTimer)
      document.body.removeChild(ballDom)
      
      let shopImgDom = null // 购物车图片
      if (typeof shopImg === 'string') {
        shopImgDom = document.querySelector(shopImg)
      } else if (shopImg instanceof HTMLElement) {
        shopImgDom = shopImg
      } else {
        console.error('加入购物车动画传入的参数错误: 第三个参数应为增加按钮的dom元素或该元素的选择器。')
        return
      }
      let rotateCount = 4 // 购物车图片左右晃动次数
      let rotateVal = 0 // 晃动角度
      const rotateInterval = setInterval(() => {
        if (rotateCount < 0) clearInterval(rotateInterval)
        else rotateCount--
        if (rotateCount === -1) rotateVal = 0 // 结束时摆正
        else rotateVal = 10 * Math.pow(-1, rotateCount) // 晃动角度10,一正一负
        shopImgDom.style.transform = 'rotate(' + rotateVal + 'deg)' // 设置css样式
      }, 100)
    }
  }, stepTime)
}
/*
* 绘制小球
* */
function drawBall2() {
  const ballDom = document.createElement('div')
  ballDom.style.width = '16px'
  ballDom.style.height = '16px'
  ballDom.style.background = '#fa5151'
  ballDom.style.borderRadius = '50%'
  ballDom.style.position = 'absolute'
  ballDom.style.zIndex = 99999
  return ballDom
}

/** *
 * 动画轨迹控制
 * 抛物线:利用抛物线方程 y = ax^2 + bx + c   传入3点坐标(x1, y1)(x2, y2)(x3, y3)求解出参数 a, b, c
           a: (y3 - y1 + (y2 - y1) * (x1 - x3) / (x2 - x1)) / (x3 * x3 - x1 * x1 - (x3 - x1) * (x1 + x2))
           b: (y2 - y1 + a * x1 * x1 - a * x2 * x2) / (x2 - x1)
           c: y1 - a * x1 * x1 - b * x1
从起点到终点, x匀速增加, 将x 带入方程得到y值,(x, y)即为动画每一帧的坐标位置
 * @param addBtnDom 增加按钮的dom元素或者选择器
 * @param shopCarDom 购物车的dom元素或选择器
 */
export const controllGiftPath2 = (addBtn, shopCar, shopImg, scrollT) => {
  let addBtnDom = null
  let shopCarDom = null
  if (typeof addBtn === 'string') {
    addBtnDom = document.querySelector(addBtn)
  } else if (addBtn instanceof HTMLElement) {
    addBtnDom = addBtn
  } else {
    console.error('加入购物车动画传入的参数错误: 第一个参数应为增加按钮的dom元素或该元素的选择器。')
    return
  }

  if (typeof shopCar === 'string') {
    shopCarDom = document.querySelector(shopCar)
  } else if (shopCar instanceof HTMLElement) {
    shopCarDom = shopCar
  } else {
    console.error('加入购物车动画传入的参数错误: 第二个参数应为增加按钮的dom元素或该元素的选择器。')
    return
  }

  // 获取两个dom的位置
  const addBtnposition = addBtnDom.getBoundingClientRect()
  const shopCarPosition = shopCarDom.getBoundingClientRect()
  // const addBtnCenterX = (addBtnposition.left + addBtnposition.right) / 2
  // const addBtnCenterY = (addBtnposition.top + addBtnposition.bottom) / 2 + scrollT
  // const shopCarCenterX = (shopCarPosition.left + shopCarPosition.right) / 2
  // const shopCarCenterY = (shopCarPosition.top + shopCarPosition.bottom) / 2
  const addBtnCenterX = addBtnposition.left
  const addBtnCenterY = addBtnposition.top
  const shopCarCenterX = (shopCarPosition.left + shopCarPosition.right) / 2
  const shopCarCenterY = shopCarPosition.top
  // 计算增加按钮 是在 相对于购物车的 左边还是右边(用于控制后面的移动方向)
  const [x1, x2, y1, y2] = [parseInt(addBtnCenterX), parseInt(shopCarCenterX), parseInt(addBtnCenterY), parseInt(shopCarCenterY)]
  // console.log('x1: ', x1, 'x2: ', x2, 'y1: ', y1, 'y2: ', y2)-
  const x3 = (x1 + x2) * 4 / 3
  const y3 = y2 - 100
  const allTime = 300
  const stepTime = 30
  const speedX = (x2 - x1) * stepTime / allTime
  let times = 0
  const a = (y3 - y1 + (y2 - y1) * (x1 - x3) / (x2 - x1)) / (x3 * x3 - x1 * x1 - (x3 - x1) * (x1 + x2))
  const b = (y2 - y1 + a * x1 * x1 - a * x2 * x2) / (x2 - x1)
  const c = y1 - a * x1 * x1 - b * x1
  // console.log('a: ', a, 'b: ', b, 'c: ', c)

  // const relativePosition = addBtnCenterX > shopCarCenterX ? -1 : 1
  // const relativePositionY = addBtnCenterY > shopCarCenterY ? -1 : 1

  // // 获取连个dom之间的距离
  // const xDistance = Math.abs(addBtnCenterX - shopCarCenterX)
  // const yDistance = Math.abs(addBtnCenterY - shopCarCenterY)

  // 绘制小球并设置其位置
  const ballDom = drawBall2()
  ballDom.style.top = y1 + 'px'
  ballDom.style.left = x1 + 'px'
  document.body.appendChild(ballDom)

  const timer = setInterval(() => {
    times += 1
    const x = x1 + speedX * times
    const y = a * x * x + b * x + c
    if (times * stepTime > allTime) {
      clearInterval(timer)
      document.body.removeChild(ballDom)
      let shopImgDom = null // 购物车图片
      if (typeof shopImg === 'string') {
        shopImgDom = document.querySelector(shopImg)
      } else if (shopImg instanceof HTMLElement) {
        shopImgDom = shopImg
      } else {
        console.error('加入购物车动画传入的参数错误: 第三个参数应为增加按钮的dom元素或该元素的选择器。')
        return
      }
      let rotateCount = 4 // 购物车图片左右晃动次数
      let rotateVal = 0 // 晃动角度
      const rotateInterval = setInterval(() => {
        if (rotateCount < 0) clearInterval(rotateInterval)
        else rotateCount--
        if (rotateCount === -1) rotateVal = 0 // 结束时摆正
        else rotateVal = 10 * Math.pow(-1, rotateCount) // 晃动角度10,一正一负
        shopImgDom.style.transform = 'rotate(' + rotateVal + 'deg)' // 设置css样式
      }, 100)
    } else {
      // console.log('x: ', x, 'y: ', y)
      ballDom.style.left = `${x}px`
      ballDom.style.top = `${y}px`
    }
  }, stepTime)
}

  • 传入的dom参数的样式需要自己先写好,抛出的路线和晃动次数与角度可以自己调整
posted @ 2022-09-05 20:55  jiazq  阅读(52)  评论(0)    收藏  举报