1. animate

  1. // 匀速动画:
  2. // 1. 获取动画运动的总时长 duration
  3. // 2. 求终点坐标(目标值,如 opacity 的最终值是1)
  4. // 3. 求起点坐标(起点初始值)
  5. // 4. 求路程:终点坐标 - 起点坐标
  6. // 5. 设置计时 curT,记录从开始运动经过的时间
  7. // 6. 设置定时器,累加 curT,计算经过 curT 时间后元素所处的位置,并且把这个位置设置给元素;
  8. // 7. 做过界判断
  9. // 封装一个动画库:匀速动画
  10. // 效果
  11. const { css } = window.utils;
  12. const Effects = {
  13. // linear: function (...) {....}, 箭头函数还需乖乖的写
  14. getName: (a, b) => {console.log(a, b)}, // 箭头函数要写全
  15. linear (curT, begin, change, duration = 2000) {
  16. return (change / duration) * curT + begin;
  17. } // 对象的简洁语法,linear 是 Effects 对象的一个属性,liner 不是变量
  18. };
  19. function animate({ ele, target = {}, duration = 2000, after }) {
  20. // 从实参解构 ele, target, duration, after
  21. // 1. 做参数合法性校验,如果不合法抛出异常
  22. if (typeof ele !== 'object') {
  23. throw TypeError('ele is not a DOM-Element');
  24. }
  25. // 2. 求动画需要的参数: target 和 duration 以及通过参数的形式传进来了,不用单独求
  26. // 2.1 求起始位置和路程
  27. let begin = {}; // 设置空对象用来装 target 里面对应的属性的初始值
  28. let change = {}; // 因为 target 不止一个属性,每一个属性都有一个路程,所以我们需要一个对象遍历 target 把 target 中的属性取出来
  29. for (let attr in target) {
  30. if (target.hasOwnProperty(attr)) {
  31. begin[attr] = css(ele, attr); // 把 target 中属性的初始值计算出来,并且保存到begin对象中
  32. change[attr] = target[attr] - begin[attr]; // 根据终点和起点的值计算该属性路程
  33. }
  34. }
  35. // // 2.2 求路程:终点 - 起点
  36. // let change = {}; // 因为target不止一个属性,每一个属性都有一个路程,所以我们需要一个对象
  37. // for (let key in target) {
  38. // if (target.hasOwnProperty(key)) {
  39. // change[key] = target[key] - begin[key];
  40. // }
  41. // }
  42. // 2.3 设置计时器变量
  43. let curT = 0;
  44. // 3. 利用定时器启动动画:通过元素对象自定义属性记录定时器id
  45. if (ele.timerID) clearInterval(ele.timerID); // 开启下一次动画之前把前面的动画清除掉,防止出现动画累加
  46. ele.timerID = setInterval(() => {
  47. // 3.1 累加时间
  48. curT += 10;
  49. // 3.2 过界判断
  50. if (curT >= duration) {
  51. clearInterval(ele.timerID); // 清定时器停止动画
  52. css(ele, target); // 批量设置元素到终点
  53. /*if (typeof after === 'function') {
  54. after.call(ele); // 把钩子函数中的this处理成元素对象
  55. }*/
  56. typeof after === 'function' && after.call(ele); // 等效于上面的if语句
  57. return;
  58. }
  59. // 3.3 求经过 curT 时间后元素各个属性所处的位置
  60. let curState = {}; // 因为 target 中有多个属性,所以需要把所有的属性经过 curT 时间后的走过的路程计算出来
  61. for (let prop in target) {
  62. if (target.hasOwnProperty(prop)) {
  63. curState[prop] = Effects.linear(curT, begin[prop], change[prop], duration);
  64. }
  65. }
  66. // 3.4 把上一步求出来的位置设置给元素
  67. css(ele, curState);
  68. }, 10)
  69. }
  70. let box = document.getElementById('box');
  71. let box2 = document.getElementById('box2');
  72. animate({
  73. ele: box, // 元素对象
  74. target: { // 多方向终点位置坐标集合
  75. left: 850,
  76. top: 400
  77. },
  78. duration: 2000, // 过渡时间
  79. after: function () { // 动画执行结束后执行的函数(现在不执行,未来某个时刻会执行的函数叫做 钩子
  80. hook 】)
  81. console.log('终于执行完了');
  82. this.style.color = 'red'; // 一般把钩子中 this 处理成元素对象
  83. }
  84. });
  85. animate({
  86. ele: box2, // 元素对象
  87. target: { // 多方向终点位置坐标集合
  88. left: 350,
  89. top: 200
  90. },
  91. duration: 2000, // 过渡时间
  92. after: function () { // 动画执行结束后执行的函数(现在不执行,未来某个时刻会执行的函数叫做 钩子
  93. hook 】)
  94. console.log('终于执行完了');
  95. }
  96. });

2. animate最终版

  1. ~function () {
  2. const { css } = window._utils
  3. // Effect 运动方式
  4. const Effect = {
  5. // Linear: function() {}
  6. /**
  7. * 匀速运动公式
  8. * @param t 当前时间
  9. * @param b 起始值
  10. * @param c 改变值(目标值 - 起始值)
  11. * @param d 过渡时间
  12. */
  13. linear(t, b, c, d) {
  14. return t * (c / d) + b
  15. },
  16. easeIn(t, b, c, d) {
  17. return c - Effect.easeOut(d - t, 0, c, d) + b
  18. },
  19. easeOut(t, b, c, d) {
  20. if ((t /= d) < 1 / 2.75) {
  21. return c * (7.5625 * t * t) + b
  22. } else if (t < 2 / 2.75) {
  23. return c * (7.5625 * (t -= 1.5 / 2.75) * t + 0.75) + b
  24. } else if (t < 2.5 / 2.75) {
  25. return c * (7.5625 * (t -= 2.25 / 2.75) * t + 0.9375) + b
  26. } else {
  27. return c * (7.5625 * (t -= 2.625 / 2.75) * t + 0.984375) + b
  28. }
  29. },
  30. easeInOut(t, b, c, d) {
  31. if (t < d / 2) {
  32. return Effect.easeIn(t * 2, 0, c, d) * 0.5 + b
  33. }
  34. return Effect.easeOut(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b
  35. }
  36. }
  37. /**
  38. *
  39. * @param [object] ele 当前动画元素
  40. * @param [object] target 目标值对象
  41. * @param [number] duration 过渡时间
  42. * @param [function] after 动画结束钩子函数
  43. */
  44. function animate({ ele, target = {}, duration = 2000, after, before, run, effect = 'linear' }) {
  45. // 参数判断处理
  46. if (!ele || ele.nodeType !== 1) {
  47. return console.error('缺少元素对象ele~')
  48. }
  49. // 动画开始之前的 钩子函数
  50. ;(typeof before === 'function') && before.call(ele)
  51. // 收集参数 begin change
  52. let begin = {}
  53. let change = {}
  54. for (let k in target) {
  55. if (target.hasOwnProperty(k)) {
  56. begin[k] = css(ele, k)
  57. change[k] = target[k] - begin[k]
  58. }
  59. }
  60. // 记录当前时间
  61. let time = 0
  62. // 定时器间隔时间
  63. const interval = 10
  64. // 动画累积
  65. ele.timer && clearInterval(ele.timer)
  66. // 创建动画定时器
  67. ele.timer = setInterval(() => {
  68. // 动画执行过程中的 钩子函数
  69. ;(typeof run === 'function') && run.call(ele)
  70. // 记录当前动画时间
  71. time += interval
  72. if (time >= duration) {
  73. // 修正元素动画目标值
  74. css(ele, target)
  75. clearInterval(ele.timer)
  76. // 动画结束后的 钩子函数
  77. ;(typeof after === 'function') && after.call(ele)
  78. return
  79. }
  80. // 根据当前时间 计算当前状态
  81. let curState = {}
  82. for (let k in target) {
  83. if (target.hasOwnProperty(k)) {
  84. curState[k] = Effect[effect](time, begin[k], change[k], duration)
  85. }
  86. }
  87. // 将当前状态 设置给当前元素
  88. css(ele, curState)
  89. }, interval)
  90. }
  91. // 过载到全局
  92. window.$animate = animate
  93. }()

3. 动画运动公式

  1. var animationEffect = {
  2. Linear: function (t, b, c, d) {
  3. return c * t / d + b;
  4. },
  5. Bounce: {
  6. easeIn: function (t, b, c, d) {
  7. return c - animationEffect.Bounce.easeOut(d - t, 0, c, d) + b;
  8. },
  9. easeOut: function (t, b, c, d) {
  10. if ((t /= d) < (1 / 2.75)) {
  11. return c * (7.5625 * t * t) + b;
  12. } else if (t < (2 / 2.75)) {
  13. return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
  14. } else if (t < (2.5 / 2.75)) {
  15. return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
  16. } else {
  17. return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
  18. }
  19. },
  20. easeInOut: function (t, b, c, d) {
  21. if (t < d / 2) {
  22. return animationEffect.Bounce.easeIn(t * 2, 0, c, d) * .5 + b;
  23. }
  24. return animationEffect.Bounce.easeOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
  25. }
  26. },
  27. Quad: {
  28. easeIn: function (t, b, c, d) {
  29. return c * (t /= d) * t + b;
  30. },
  31. easeOut: function (t, b, c, d) {
  32. return -c * (t /= d) * (t - 2) + b;
  33. },
  34. easeInOut: function (t, b, c, d) {
  35. if ((t /= d / 2) < 1) {
  36. return c / 2 * t * t + b;
  37. }
  38. return -c / 2 * ((--t) * (t - 2) - 1) + b;
  39. }
  40. },
  41. Cubic: {
  42. easeIn: function (t, b, c, d) {
  43. return c * (t /= d) * t * t + b;
  44. },
  45. easeOut: function (t, b, c, d) {
  46. return c * ((t = t / d - 1) * t * t + 1) + b;
  47. },
  48. easeInOut: function (t, b, c, d) {
  49. if ((t /= d / 2) < 1) {
  50. return c / 2 * t * t * t + b;
  51. }
  52. return c / 2 * ((t -= 2) * t * t + 2) + b;
  53. }
  54. },
  55. Quart: {
  56. easeIn: function (t, b, c, d) {
  57. return c * (t /= d) * t * t * t + b;
  58. },
  59. easeOut: function (t, b, c, d) {
  60. return -c * ((t = t / d - 1) * t * t * t - 1) + b;
  61. },
  62. easeInOut: function (t, b, c, d) {
  63. if ((t /= d / 2) < 1) {
  64. return c / 2 * t * t * t * t + b;
  65. }
  66. return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
  67. }
  68. },
  69. Quint: {
  70. easeIn: function (t, b, c, d) {
  71. return c * (t /= d) * t * t * t * t + b;
  72. },
  73. easeOut: function (t, b, c, d) {
  74. return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
  75. },
  76. easeInOut: function (t, b, c, d) {
  77. if ((t /= d / 2) < 1) {
  78. return c / 2 * t * t * t * t * t + b;
  79. }
  80. return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
  81. }
  82. },
  83. Sine: {
  84. easeIn: function (t, b, c, d) {
  85. return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
  86. },
  87. easeOut: function (t, b, c, d) {
  88. return c * Math.sin(t / d * (Math.PI / 2)) + b;
  89. },
  90. easeInOut: function (t, b, c, d) {
  91. return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
  92. }
  93. },
  94. Expo: {
  95. easeIn: function (t, b, c, d) {
  96. return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
  97. },
  98. easeOut: function (t, b, c, d) {
  99. return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
  100. },
  101. easeInOut: function (t, b, c, d) {
  102. if (t == 0) return b;
  103. if (t == d) return b + c;
  104. if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
  105. return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
  106. }
  107. },
  108. Circ: {
  109. easeIn: function (t, b, c, d) {
  110. return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
  111. },
  112. easeOut: function (t, b, c, d) {
  113. return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
  114. },
  115. easeInOut: function (t, b, c, d) {
  116. if ((t /= d / 2) < 1) {
  117. return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
  118. }
  119. return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
  120. }
  121. },
  122. Back: {
  123. easeIn: function (t, b, c, d, s) {
  124. if (s == undefined) s = 1.70158;
  125. return c * (t /= d) * t * ((s + 1) * t - s) + b;
  126. },
  127. easeOut: function (t, b, c, d, s) {
  128. if (s == undefined) s = 1.70158;
  129. return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
  130. },
  131. easeInOut: function (t, b, c, d, s) {
  132. if (s == undefined) s = 1.70158;
  133. if ((t /= d / 2) < 1) {
  134. return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
  135. }
  136. return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
  137. }
  138. },
  139. Elastic: {
  140. easeIn: function (t, b, c, d, a, p) {
  141. if (t == 0) return b;
  142. if ((t /= d) == 1) return b + c;
  143. if (!p) p = d * .3;
  144. var s;
  145. !a || a < Math.abs(c) ? (a = c, s = p / 4) : s = p / (2 * Math.PI) * Math.asin(c / a);
  146. return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
  147. },
  148. easeOut: function (t, b, c, d, a, p) {
  149. if (t == 0) return b;
  150. if ((t /= d) == 1) return b + c;
  151. if (!p) p = d * .3;
  152. var s;
  153. !a || a < Math.abs(c) ? (a = c, s = p / 4) : s = p / (2 * Math.PI) * Math.asin(c / a);
  154. return (a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b);
  155. },
  156. easeInOut: function (t, b, c, d, a, p) {
  157. if (t == 0) return b;
  158. if ((t /= d / 2) == 2) return b + c;
  159. if (!p) p = d * (.3 * 1.5);
  160. var s;
  161. !a || a < Math.abs(c) ? (a = c, s = p / 4) : s = p / (2 * Math.PI) * Math.asin(c / a);
  162. if (t < 1) return -.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
  163. return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
  164. }
  165. }
  166. };