下列 JavaScript 特效均来源于网络,由笔者整理,仅用于学习参考。

一、动画特效

带刺的花

带刺的花.gif

  1. <canvas id="barbedFlowers"></canvas>
  1. // 函数主体
  2. function barbedFlowers(el, width, height) {
  3. var createClass = function () {
  4. function defineProperties(target, props) {
  5. for (var i = 0; i < props.length; i++) {
  6. var descriptor = props[i];
  7. descriptor.enumerable = descriptor.enumerable || false;
  8. descriptor.configurable = true;
  9. if ('value' in descriptor) descriptor.writable = true;
  10. Object.defineProperty(target, descriptor.key, descriptor);
  11. };
  12. };
  13. return function (Constructor, protoProps, staticProps) {
  14. if (protoProps) defineProperties(Constructor.prototype, protoProps);
  15. if (staticProps) defineProperties(Constructor, staticProps);
  16. return Constructor;
  17. };
  18. }();
  19. function _classCallCheck(instance, Constructor) {
  20. if (!(instance instanceof Constructor)) {
  21. throw new TypeError('Cannot call a class as a function');
  22. }
  23. };
  24. var Scene = function () {
  25. function Scene() {
  26. var _this = this;
  27. _classCallCheck(this, Scene);
  28. this.PI = Math.PI;
  29. this.TAU = this.PI * 2;
  30. this.GOLDEN = (Math.sqrt(5) + 1) / 2;
  31. this.canvas = document.querySelector(el);
  32. this.ctx = this.canvas.getContext('2d');
  33. this.dpr = window.devicePixelRatio;
  34. this.reset();
  35. window.addEventListener('resize', function () {
  36. return _this.reset();
  37. });
  38. this.loop();
  39. };
  40. createClass(Scene,
  41. [
  42. {
  43. key: 'reset',
  44. value: function reset() {
  45. this.width = width || window.innerWidth;
  46. this.height = height || window.innerHeight;
  47. this.hwidth = this.width * 0.5;
  48. this.hheight = this.height * 0.5;
  49. this.canvas.width = this.width * this.dpr;
  50. this.canvas.height = this.height * this.dpr;
  51. this.ctx.scale(this.dpr, this.dpr);
  52. this.ctx.translate(~~this.hwidth, ~~this.hheight);
  53. this.ctx.globalCompositeOperation = 'lighter';
  54. this.tick = 320;
  55. }
  56. },
  57. {
  58. key: 'loop',
  59. value: function loop() {
  60. var _this2 = this;
  61. requestAnimationFrame(function () {
  62. return _this2.loop();
  63. });
  64. this.tick++;
  65. this.ctx.clearRect(-this.hwidth, -this.hheight, this.width, this.height);
  66. var count = 150;
  67. var angle = this.tick * -0.001;
  68. var amp = 0;
  69. for (var i = 0; i < count; i++) {
  70. angle += this.GOLDEN * this.TAU + Math.sin(this.tick * 0.03) * 0.001;
  71. amp += (i - count / 2) * 0.01 + Math.cos(this.tick * 0.015) * 1;
  72. var x = Math.cos(angle) * amp + Math.cos(this.tick * 0.0075) * (count - i) *
  73. 0.3;
  74. var y = Math.sin(angle) * amp + Math.sin(this.tick * 0.0075) * (count - i) *
  75. 0.3;
  76. var radius = 0.1 + i * 0.02;
  77. var scale = 0.1 + amp * 0.1;
  78. var hue = this.tick + angle / this.TAU * 0.4 + 60;
  79. var saturation = 90;
  80. var lightness = 60;
  81. var alpha = 0.7 + Math.cos(this.tick * 0.03 + i) * 0.3;
  82. this.ctx.save();
  83. this.ctx.translate(x, y);
  84. this.ctx.rotate(angle);
  85. this.ctx.scale(scale, 1);
  86. this.ctx.rotate(this.PI * 0.25);
  87. this.ctx.fillStyle = 'hsla(' + hue + ', ' + saturation + '%, ' + lightness +
  88. '%, ' + alpha + ')';
  89. this.ctx.fillRect(-radius, -radius, radius * 2, radius * 2);
  90. this.ctx.restore();
  91. this.ctx.beginPath();
  92. this.ctx.arc(x, y, radius * 12, 0, this.TAU);
  93. this.ctx.fillStyle = 'hsla(' + hue + ', ' + saturation + '%, ' + lightness +
  94. '%, ' + alpha * 0.05 + ')';
  95. this.ctx.fill();
  96. }
  97. }
  98. }
  99. ]);
  100. return Scene;
  101. }();
  102. var scene = new Scene();
  103. };
  104. // 调用函数
  105. barbedFlowers('#barbedFlowers', 500, 500);

矩阵

矩阵.gif

  1. <canvas id="matrix"></canvas>
  1. // 函数主体
  2. function matrix(el, width, height) {
  3. var canvas,
  4. ctx,
  5. width,
  6. height,
  7. size,
  8. lines,
  9. tick;
  10. function line() {
  11. this.path = [];
  12. this.speed = rand(10, 20);
  13. this.count = randInt(10, 30);
  14. this.x = width / 2, +1;
  15. this.y = height / 2 + 1;
  16. this.target = {
  17. x: width / 2,
  18. y: height / 2
  19. };
  20. this.dist = 0;
  21. this.angle = 0;
  22. this.hue = tick / 5;
  23. this.life = 1;
  24. this.updateAngle();
  25. this.updateDist();
  26. };
  27. line.prototype.step = function (i) {
  28. this.x += Math.cos(this.angle) * this.speed;
  29. this.y += Math.sin(this.angle) * this.speed;
  30. this.updateDist();
  31. if (this.dist < this.speed) {
  32. this.x = this.target.x;
  33. this.y = this.target.y;
  34. this.changeTarget();
  35. }
  36. this.path.push({
  37. x: this.x,
  38. y: this.y
  39. });
  40. if (this.path.length > this.count) {
  41. this.path.shift();
  42. }
  43. this.life -= 0.001;
  44. if (this.life <= 0) {
  45. this.path = null;
  46. lines.splice(i, 1);
  47. }
  48. };
  49. line.prototype.updateDist = function () {
  50. var dx = this.target.x - this.x,
  51. dy = this.target.y - this.y;
  52. this.dist = Math.sqrt(dx * dx + dy * dy);
  53. };
  54. line.prototype.updateAngle = function () {
  55. var dx = this.target.x - this.x,
  56. dy = this.target.y - this.y;
  57. this.angle = Math.atan2(dy, dx);
  58. };
  59. line.prototype.changeTarget = function () {
  60. var randStart = randInt(0, 3);
  61. switch (randStart) {
  62. case 0: // up
  63. this.target.y = this.y - size;
  64. break;
  65. case 1: // right
  66. this.target.x = this.x + size;
  67. break;
  68. case 2: // down
  69. this.target.y = this.y + size;
  70. break;
  71. case 3: // left
  72. this.target.x = this.x - size;
  73. }
  74. this.updateAngle();
  75. };
  76. line.prototype.draw = function (i) {
  77. ctx.beginPath();
  78. var rando = rand(0, 10);
  79. for (var j = 0, length = this.path.length; j < length; j++) {
  80. ctx[(j === 0) ? 'moveTo' : 'lineTo'](this.path[j].x + rand(-rando, rando), this.path[j].y + rand(-rando, rando));
  81. }
  82. ctx.strokeStyle = 'hsla(' + rand(this.hue, this.hue + 30) + ', 80%, 55%, ' + (this.life / 3) + ')';
  83. ctx.lineWidth = rand(0.1, 2);
  84. ctx.stroke();
  85. };
  86. function rand(min, max) {
  87. return Math.random() * (max - min) + min;
  88. };
  89. function randInt(min, max) {
  90. return Math.floor(min + Math.random() * (max - min + 1));
  91. };
  92. function init() {
  93. canvas = document.querySelector(el);
  94. ctx = canvas.getContext('2d');
  95. size = 30;
  96. lines = [];
  97. reset();
  98. loop();
  99. };
  100. function reset() {
  101. canvas.width = Math.ceil((width || window.innerWidth) / 2) * 2;
  102. canvas.height = Math.ceil((height || window.innerHeight) / 2) * 2;
  103. lines.length = 0;
  104. tick = 0;
  105. };
  106. function create() {
  107. if (tick % 10 === 0) {
  108. lines.push(new line());
  109. }
  110. };
  111. function step() {
  112. var i = lines.length;
  113. while (i--) {
  114. lines[i].step(i);
  115. };
  116. };
  117. function clear() {
  118. ctx.globalCompositeOperation = 'destination-out';
  119. ctx.fillStyle = 'hsla(0, 0%, 0%, 0.1';
  120. ctx.fillRect(0, 0, width, height);
  121. ctx.globalCompositeOperation = 'lighter';
  122. };
  123. function draw() {
  124. ctx.save();
  125. ctx.translate(width / 2, height / 2);
  126. ctx.rotate(tick * 0.001);
  127. var scale = 0.8 + Math.cos(tick * 0.02) * 0.2;
  128. ctx.scale(scale, scale);
  129. ctx.translate(-width / 2, -height / 2);
  130. var i = lines.length;
  131. while (i--) {
  132. lines[i].draw(i);
  133. }
  134. ctx.restore();
  135. };
  136. function loop() {
  137. requestAnimationFrame(loop);
  138. create();
  139. step();
  140. clear();
  141. draw();
  142. tick++;
  143. };
  144. function onresize() {
  145. reset();
  146. };
  147. window.addEventListener('resize', onresize);
  148. init();
  149. };
  150. // 调用函数
  151. matrix('#matrix', 500, 500);

粒子漩涡

粒子漩涡.gif

  1. <canvas id="particleVortex"></canvas>
  1. // 函数主体
  2. function particleVortex(el, width, height) {
  3. function project3D(x, y, z, vars) {
  4. var p, d;
  5. x -= vars.camX;
  6. y -= vars.camY - 8;
  7. z -= vars.camZ;
  8. p = Math.atan2(x, z);
  9. d = Math.sqrt(x * x + z * z);
  10. x = Math.sin(p - vars.yaw) * d;
  11. z = Math.cos(p - vars.yaw) * d;
  12. p = Math.atan2(y, z);
  13. d = Math.sqrt(y * y + z * z);
  14. y = Math.sin(p - vars.pitch) * d;
  15. z = Math.cos(p - vars.pitch) * d;
  16. var rx1 = -1000;
  17. var ry1 = 1;
  18. var rx2 = 1000;
  19. var ry2 = 1;
  20. var rx3 = 0;
  21. var ry3 = 0;
  22. var rx4 = x;
  23. var ry4 = z;
  24. var uc = (ry4 - ry3) * (rx2 - rx1) - (rx4 - rx3) * (ry2 - ry1);
  25. var ua = ((rx4 - rx3) * (ry1 - ry3) - (ry4 - ry3) * (rx1 - rx3)) / uc;
  26. var ub = ((rx2 - rx1) * (ry1 - ry3) - (ry2 - ry1) * (rx1 - rx3)) / uc;
  27. if (!z) z = 0.000000001;
  28. if (ua > 0 && ua < 1 && ub > 0 && ub < 1) {
  29. return {
  30. x: vars.cx + (rx1 + ua * (rx2 - rx1)) * vars.scale,
  31. y: vars.cy + y / z * vars.scale,
  32. d: (x * x + y * y + z * z)
  33. };
  34. } else {
  35. return {
  36. d: -1
  37. };
  38. }
  39. };
  40. function elevation(x, y, z) {
  41. var dist = Math.sqrt(x * x + y * y + z * z);
  42. if (dist && z / dist >= -1 && z / dist <= 1) return Math.acos(z / dist);
  43. return 0.00000001;
  44. };
  45. function rgb(col) {
  46. col += 0.000001;
  47. var r = parseInt((0.5 + Math.sin(col) * 0.5) * 16);
  48. var g = parseInt((0.5 + Math.cos(col) * 0.5) * 16);
  49. var b = parseInt((0.5 - Math.sin(col) * 0.5) * 16);
  50. return '#' + r.toString(16) + g.toString(16) + b.toString(16);
  51. };
  52. function interpolateColors(RGB1, RGB2, degree) {
  53. var w2 = degree;
  54. var w1 = 1 - w2;
  55. return [w1 * RGB1[0] + w2 * RGB2[0], w1 * RGB1[1] + w2 * RGB2[1], w1 * RGB1[2] + w2 * RGB2[2]];
  56. };
  57. function rgbArray(col) {
  58. col += 0.000001;
  59. var r = parseInt((0.5 + Math.sin(col) * 0.5) * 256);
  60. var g = parseInt((0.5 + Math.cos(col) * 0.5) * 256);
  61. var b = parseInt((0.5 - Math.sin(col) * 0.5) * 256);
  62. return [r, g, b];
  63. };
  64. function colorString(arr) {
  65. var r = parseInt(arr[0]);
  66. var g = parseInt(arr[1]);
  67. var b = parseInt(arr[2]);
  68. return '#' + ('0' + r.toString(16)).slice(-2) + ('0' + g.toString(16)).slice(-2) + ('0' + b.toString(16)).slice(-2);
  69. };
  70. function process(vars) {
  71. if (vars.points.length < vars.initParticles)
  72. for (var i = 0; i < 5; ++i) spawnParticle(vars);
  73. var p, d, t;
  74. p = Math.atan2(vars.camX, vars.camZ);
  75. d = Math.sqrt(vars.camX * vars.camX + vars.camZ * vars.camZ);
  76. d -= Math.sin(vars.frameNo / 80) / 25;
  77. t = Math.cos(vars.frameNo / 300) / 165;
  78. vars.camX = Math.sin(p + t) * d;
  79. vars.camZ = Math.cos(p + t) * d;
  80. vars.camY = -Math.sin(vars.frameNo / 220) * 15;
  81. vars.yaw = Math.PI + p + t;
  82. vars.pitch = elevation(vars.camX, vars.camZ, vars.camY) - Math.PI / 2;
  83. var t;
  84. for (var i = 0; i < vars.points.length; ++i) {
  85. x = vars.points[i].x;
  86. y = vars.points[i].y;
  87. z = vars.points[i].z;
  88. d = Math.sqrt(x * x + z * z) / 1.0075;
  89. t = .1 / (1 + d * d / 5);
  90. p = Math.atan2(x, z) + t;
  91. vars.points[i].x = Math.sin(p) * d;
  92. vars.points[i].z = Math.cos(p) * d;
  93. vars.points[i].y += vars.points[i].vy * t * ((Math.sqrt(vars.distributionRadius) - d) * 2);
  94. if (vars.points[i].y > vars.vortexHeight / 2 || d < .25) {
  95. vars.points.splice(i, 1);
  96. spawnParticle(vars);
  97. }
  98. };
  99. };
  100. function drawFloor(vars) {
  101. var x, y, z, d, point, a;
  102. for (var i = -25; i <= 25; i += 1) {
  103. for (var j = -25; j <= 25; j += 1) {
  104. x = i * 2;
  105. z = j * 2;
  106. y = vars.floor;
  107. d = Math.sqrt(x * x + z * z);
  108. point = project3D(x, y - d * d / 85, z, vars);
  109. if (point.d != -1) {
  110. size = 1 + 15000 / (1 + point.d);
  111. a = 0.15 - Math.pow(d / 50, 4) * 0.15;
  112. if (a > 0) {
  113. vars.ctx.fillStyle = colorString(interpolateColors(rgbArray(d / 26 - vars.frameNo / 40), [0, 128, 32], .5 +
  114. Math.sin(d / 6 - vars.frameNo / 8) / 2));
  115. vars.ctx.globalAlpha = a;
  116. vars.ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size);
  117. }
  118. }
  119. }
  120. };
  121. vars.ctx.fillStyle = '#82f';
  122. for (var i = -25; i <= 25; i += 1) {
  123. for (var j = -25; j <= 25; j += 1) {
  124. x = i * 2;
  125. z = j * 2;
  126. y = -vars.floor;
  127. d = Math.sqrt(x * x + z * z);
  128. point = project3D(x, y + d * d / 85, z, vars);
  129. if (point.d != -1) {
  130. size = 1 + 15000 / (1 + point.d);
  131. a = 0.15 - Math.pow(d / 50, 4) * 0.15;
  132. if (a > 0) {
  133. vars.ctx.fillStyle = colorString(interpolateColors(rgbArray(-d / 26 - vars.frameNo / 40), [32, 0, 128], .5 +
  134. Math.sin(-d / 6 - vars.frameNo / 8) / 2));
  135. vars.ctx.globalAlpha = a;
  136. vars.ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size);
  137. }
  138. }
  139. }
  140. };
  141. };
  142. function sortFunction(a, b) {
  143. return b.dist - a.dist;
  144. };
  145. function draw(vars) {
  146. vars.ctx.globalAlpha = .15;
  147. vars.ctx.fillStyle = '#000';
  148. vars.ctx.fillRect(0, 0, vars.canvas.width, vars.canvas.height);
  149. drawFloor(vars);
  150. var point, x, y, z, a;
  151. for (var i = 0; i < vars.points.length; ++i) {
  152. x = vars.points[i].x;
  153. y = vars.points[i].y;
  154. z = vars.points[i].z;
  155. point = project3D(x, y, z, vars);
  156. if (point.d != -1) {
  157. vars.points[i].dist = point.d;
  158. size = 1 + vars.points[i].radius / (1 + point.d);
  159. d = Math.abs(vars.points[i].y);
  160. a = .8 - Math.pow(d / (vars.vortexHeight / 2), 1000) * .8;
  161. vars.ctx.globalAlpha = a >= 0 && a <= 1 ? a : 0;
  162. vars.ctx.fillStyle = rgb(vars.points[i].color);
  163. if (point.x > -1 && point.x < vars.canvas.width && point.y > -1 && point.y < vars.canvas.height)
  164. vars.ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size);
  165. }
  166. };
  167. vars.points.sort(sortFunction);
  168. };
  169. function spawnParticle(vars) {
  170. var p, ls;
  171. pt = {};
  172. p = Math.PI * 2 * Math.random();
  173. ls = Math.sqrt(Math.random() * vars.distributionRadius);
  174. pt.x = Math.sin(p) * ls;
  175. pt.y = -vars.vortexHeight / 2;
  176. pt.vy = vars.initV / 20 + Math.random() * vars.initV;
  177. pt.z = Math.cos(p) * ls;
  178. pt.radius = 200 + 800 * Math.random();
  179. pt.color = pt.radius / 1000 + vars.frameNo / 250;
  180. vars.points.push(pt);
  181. };
  182. function frame(vars) {
  183. if (vars === undefined) {
  184. var vars = {};
  185. vars.canvas = document.querySelector(el);
  186. vars.ctx = vars.canvas.getContext('2d');
  187. vars.canvas.width = width || document.documentElement.clientWidth;
  188. vars.canvas.height = height || document.documentElement.clientHeight;
  189. window.addEventListener('resize', function () {
  190. vars.canvas.width = width || document.documentElement.clientWidth;
  191. vars.canvas.height = height || document.documentElement.clientHeight;
  192. vars.cx = vars.canvas.width / 2;
  193. vars.cy = vars.canvas.height / 2;
  194. }, true);
  195. vars.frameNo = 0;
  196. vars.camX = 0;
  197. vars.camY = 0;
  198. vars.camZ = -14;
  199. vars.pitch = elevation(vars.camX, vars.camZ, vars.camY) - Math.PI / 2;
  200. vars.yaw = 0;
  201. vars.cx = vars.canvas.width / 2;
  202. vars.cy = vars.canvas.height / 2;
  203. vars.bounding = 10;
  204. vars.scale = 500;
  205. vars.floor = 26.5;
  206. vars.points = [];
  207. vars.initParticles = 700;
  208. vars.initV = .01;
  209. vars.distributionRadius = 800;
  210. vars.vortexHeight = 25;
  211. }
  212. vars.frameNo++;
  213. requestAnimationFrame(function () {
  214. frame(vars);
  215. });
  216. process(vars);
  217. draw(vars);
  218. };
  219. frame();
  220. };
  221. // 调用函数
  222. particleVortex('#particleVortex', 500, 500);

二、点击特效

点击出现爱心

鼠标点击出现爱心.gif

  1. (function (win, doc) {
  2. let hearts = [];
  3. let heartStyle =
  4. `.heart{position:fixed;width:10px;height:10px;background-color:#fff;transform:rotate(45deg);z-index:9}.heart::before,.heart::after{position:absolute;width:inherit;height:inherit;content:'';background-color:inherit;border-radius:50%}.heart::before{top:-5px}.heart::after{left:-5px}`;
  5. // 定义不同浏览器下的requestAnimationFrame函数实现,若都没有则用setTimeout实现
  6. window.requestAnimationFrame = (function () {
  7. return win.requestAnimationFrame ||
  8. win.webkitRequestAnimationFrame ||
  9. win.mozCancelAnimationFrame ||
  10. win.oRequestAnimationFrame ||
  11. win.msCancelRequestAnimationFrame ||
  12. function (callback) {
  13. setTimeout(callback, 1000 / 60);
  14. };
  15. })();
  16. // 生成随机颜色
  17. function randomColor() {
  18. return `rgb(${~~(Math.random() * 255)},${~~(Math.random() * 255)},${~~(Math.random() * 255)})`;
  19. };
  20. // 生成样式
  21. function css(css) {
  22. let style = doc.createElement('style');
  23. style.type = 'text/css';
  24. try {
  25. style.appendChild(doc.createTextNode(css));
  26. } catch (err) {
  27. style.stylesheet.cssText = css;
  28. }
  29. doc.getElementsByTagName('head')[0].appendChild(style);
  30. };
  31. // 创建爱心
  32. function createHeart(event) {
  33. let div = doc.createElement('div');
  34. div.className = 'heart';
  35. // 给hearts数组添加heart对象
  36. hearts.push({
  37. el: div,
  38. x: event.clientX - 5, // 鼠标当前位置x轴 - 5
  39. y: event.clientY - 5, // 鼠标当前位置y轴 - 5
  40. scale: 1, // 缩放
  41. alpha: 1, // 透明度
  42. color: randomColor() // 颜色(随机颜色)
  43. });
  44. doc.body.appendChild(div);
  45. };
  46. // 移除已生成爱心
  47. function removeHeart() {
  48. for (let i = 0; i < hearts.length; i++) {
  49. if (hearts[i].alpha <= 0) { // 若当前heart对象的透明度小于等于0
  50. doc.body.removeChild(hearts[i].el); // 从body中移除当前heart对象
  51. hearts.splice(i, 1); // 从heart数组中移除当前heart对象
  52. continue;
  53. }
  54. hearts[i].y--;
  55. hearts[i].scale += 0.004;
  56. hearts[i].alpha -= 0.013;
  57. hearts[i].el.style.cssText =
  58. `top:${hearts[i].y}px;left:${hearts[i].x}px;background-color:${hearts[i].color};opacity:${hearts[i].alpha};transform:scale(${hearts[i].scale},${hearts[i].scale}) rotate(45deg)`;
  59. }
  60. requestAnimationFrame(removeHeart);
  61. };
  62. // 点击事件
  63. function clickEvent() {
  64. let click = typeof win.onclick === 'function' && win.onclick;
  65. win.onclick = function (event) {
  66. click && click();
  67. createHeart(event);
  68. };
  69. };
  70. // 初始化
  71. function init() {
  72. css(heartStyle); // 添加爱心样式
  73. clickEvent(); // 添加点击事件(生成爱心)
  74. removeHeart(); // 移除已生成爱心
  75. };
  76. init();
  77. })(window, document);