HTML

<div class="page page-thunder-to-text">
<input id="input" type="text" maxlength="24" placeholder="输入要打文字">
<canvas id="canvas">
</canvas>
</div>

CSS

.page-thunder-to-text {
position: relative;
overflow: hidden;
} .page-thunder-to-text canvas {
display: block;
} .page-thunder-to-text input {
position: absolute;
bottom: 50px;
left: 0;
right: 0;
display: block;
outline: none;
background-color: rgba(38, 50, 56, 0.2);
color: #ffffff;
border: none;
width: 50%;
min-width: 500px;
max-width: 100%;
margin: auto;
height: 60px;
line-height: 60px;
font-size: 40px;
padding: 0 20px;
} .page-thunder-to-text input:hover,
.page-thunder-to-text input:focus {
border: 1px solid rgba(38, 50, 56, 0.6);
} .page-thunder-to-text input::-webkit-input-placeholder {
color: rgba(255, 255, 255, 0.1);
}

JS

<script>
let canvas,
ctx,
w,
h,
thunder,
text,
particles,
input; function Thunder(options) {
options = options || {};
this.lifespan = options.lifespan || Math.round(Math.random() * 10 + 10);
this.maxlife = this.lifespan;
this.color = options.color || '#fefefe';
this.glow = options.glow || '#2323fe';
this.x = options.x || Math.random() * w;
this.y = options.y || Math.random() * h;
this.width = options.width || 2;
this.direct = options.direct || Math.random() * Math.PI * 2;
this.max = options.max || Math.round(Math.random() * 10 + 20);
this.segments = [...new Array(this.max)].map(() => {
return {
direct: this.direct + (Math.PI * Math.random() * 0.2 - 0.1),
length: Math.random() * 20 + 80,
change: Math.random() * 0.04 - 0.02
};
}); this.update = function(index, array) {
this.segments.forEach(s => { (s.direct += s.change) && Math.random() > 0.96 && (s.change *= -1)
}); (this.lifespan > 0 && this.lifespan--) || this.remove(index, array);
} this.render = function(ctx) {
if (this.lifespan <= 0) return;
ctx.beginPath();
ctx.globalAlpha = this.lifespan / this.maxlife;
ctx.strokeStyle = this.color;
ctx.lineWidth = this.width;
ctx.shadowBlur = 32;
ctx.shadowColor = this.glow;
ctx.moveTo(this.x, this.y);
let prev = {
x: this.x,
y: this.y
};
this.segments.forEach(s => {
const x = prev.x + Math.cos(s.direct) * s.length;
const y = prev.y + Math.sin(s.direct) * s.length;
prev = {
x: x,
y: y
};
ctx.lineTo(x, y);
});
ctx.stroke();
ctx.closePath();
ctx.shadowBlur = 0;
const strength = Math.random() * 80 + 40;
const light = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, strength);
light.addColorStop(0, 'rgba(250, 200, 50, 0.6)');
light.addColorStop(0.1, 'rgba(250, 200, 50, 0.2)');
light.addColorStop(0.4, 'rgba(250, 200, 50, 0.06)');
light.addColorStop(0.65, 'rgba(250, 200, 50, 0.01)');
light.addColorStop(0.8, 'rgba(250, 200, 50, 0)');
ctx.beginPath();
ctx.fillStyle = light;
ctx.arc(this.x, this.y, strength, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
} this.remove = function(index, array) {
array.splice(index, 1);
}
} function Spark(options) {
options = options || {};
this.x = options.x || w * 0.5;
this.y = options.y || h * 0.5;
this.v = options.v || {
direct: Math.random() * Math.PI * 2,
weight: Math.random() * 14 + 2,
friction: 0.88
};
this.a = options.a || {
change: Math.random() * 0.4 - 0.2,
min: this.v.direct - Math.PI * 0.4,
max: this.v.direct + Math.PI * 0.4
};
this.g = options.g || {
direct: Math.PI * 0.5 + (Math.random() * 0.4 - 0.2),
weight: Math.random() * 0.25 + 0.25
};
this.width = options.width || Math.random() * 3;
this.lifespan = options.lifespan || Math.round(Math.random() * 20 + 40);
this.maxlife = this.lifespan;
this.color = options.color || '#feca32';
this.prev = {
x: this.x,
y: this.y
}; this.update = function(index, array) {
this.prev = {
x: this.x,
y: this.y
};
this.x += Math.cos(this.v.direct) * this.v.weight;
this.x += Math.cos(this.g.direct) * this.g.weight;
this.y += Math.sin(this.v.direct) * this.v.weight;
this.y += Math.sin(this.g.direct) * this.g.weight;
this.v.weight > 0.2 && (this.v.weight *= this.v.friction);
this.v.direct += this.a.change; (this.v.direct > this.a.max || this.v.direct < this.a.min) && (this.a.change *= -1);
this.lifespan > 0 && this.lifespan--;
this.lifespan <= 0 && this.remove(index, array);
} this.render = function(ctx) {
if (this.lifespan <= 0) return;
ctx.beginPath();
ctx.globalAlpha = this.lifespan / this.maxlife;
ctx.strokeStyle = this.color;
ctx.lineWidth = this.width;
ctx.moveTo(this.x, this.y);
ctx.lineTo(this.prev.x, this.prev.y);
ctx.stroke();
ctx.closePath();
} this.remove = function(index, array) {
array.splice(index, 1);
}
} function Particles(options) {
options = options || {};
this.max = options.max || Math.round(Math.random() * 10 + 10);
this.sparks = [...new Array(this.max)].map(() => new Spark(options)); this.update = function() {
this.sparks.forEach((s, i) => s.update(i, this.sparks));
} this.render = function(ctx) {
this.sparks.forEach(s => s.render(ctx));
}
} function Text(options) {
options = options || {};
const pool = document.createElement('canvas');
const buffer = pool.getContext('2d');
pool.width = w;
buffer.fillStyle = '#000000';
buffer.fillRect(0, 0, pool.width, pool.height); this.size = options.size || 100;
this.copy = (options.copy || `Hello ! `) + ' ';
this.color = options.color || '#cd96fe';
this.delay = options.delay || 5;
this.basedelay = this.delay;
buffer.font = `${this.size}px Comic Sans MS`;
this.bound = buffer.measureText(this.copy);
this.bound.height = this.size * 1.5;
this.x = options.x || w * 0.5 - this.bound.width * 0.5;
this.y = options.y || h * 0.5 - this.size * 0.5; buffer.strokeStyle = this.color;
buffer.strokeText(this.copy, 0, this.bound.height * 0.8);
this.data = buffer.getImageData(0, 0, this.bound.width, this.bound.height);
this.index = 0; this.update = function() {
if (this.index >= this.bound.width) {
this.index = 0;
return;
}
const data = this.data.data;
for (let i = this.index * 4; i < data.length; i += (4 * this.data.width)) {
const bitmap = data[i] + data[i + 1] + data[i + 2] + data[i + 3];
if (bitmap > 255 && Math.random() > 0.96) {
const x = this.x + this.index;
const y = this.y + (i / this.bound.width / 4);
thunder.push(new Thunder({
x: x,
y: y
}));
Math.random() > 0.5 && particles.push(new Particles({
x: x,
y: y
}));
}
}
if (this.delay--<0) {
this.index++;
this.delay += this.basedelay;
}
} this.render = function(ctx) {
ctx.putImageData(this.data, this.x, this.y, 0, 0, this.index, this.bound.height);
}
} function loop() {
update();
render();
requestAnimationFrame(loop);
} function update() {
text.update();
thunder.forEach((l, i) => l.update(i, thunder));
particles.forEach(p => p.update());
} function render() {
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 1;
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, w, h);
//
ctx.globalCompositeOperation = 'screen';
text.render(ctx);
thunder.forEach(l => l.render(ctx));
particles.forEach(p => p.render(ctx));
} (function() {
//
canvas = document.getElementById('canvas');
input = document.getElementById('input');
ctx = canvas.getContext('2d');
w = window.innerWidth;
h = window.innerHeight;
canvas.width = w;
canvas.height = h;
thunder = [];
particles = [];
//
text = new Text({
copy: 'Alang)'
});
canvas.addEventListener('click', (e) => {
const x = e.clientX;
const y = e.clientY;
thunder.push(new Thunder({
x: x,
y: y
}));
particles.push(new Particles({
x: x,
y: y
}));
});
let cb = 0;
input.addEventListener('keyup', (e) => {
clearTimeout(cb);
cb = setTimeout(() => {
text = new Text({
copy: input.value
});
},
300);
});
//
loop();
})()
</script>

JS闪电打字特效的更多相关文章

  1. 案例:用JS实现放大镜特效

    案例:用JS实现放大镜特效 案例:用JS实现放大镜特效

  2. js页面载入特效如何实现

    js页面载入特效如何实现 一.总结 一句话总结:可以加选择器(里面的字符串)作为参数,这样函数就可以针对不同选择器,就很棒了. 1.特效的原理是什么? 都是通过标签的位置和样式来实现特效的. 二.js ...

  3. Vscode 打字特效插件Power Mode安装使用说明

     壹 ❀ 引 我记得在17年使用atom编辑器的时候,使用过一款打字特效的插件,只要我们输入代码,代码上方就会有与代码颜色对应的星星效果,今天脑抽突然想起了这个中二插件,搜索了一番成功安装,大致效果如 ...

  4. VSCode打字特效Power Mode插件

    由于最近比较频繁使用VSCode这个软件写代码,然后里面有一个非常炫酷的打字特效插件,平时写代码的时候不会感觉太枯燥(其实就是装一下逼吧)! 安装很简单,但是容易忘,所以这里整理一下具体的部署步骤. ...

  5. 前端小插件之手写js循环滚动特效

    很多前端都离不开滚动的特效,调用插件繁琐,后期更改麻烦,考虑到这些因素,自己写了一套无限循环滚动的小特效. 首先滚动特效很好写,用css就可以完成,下面写一个基础css向上循环滚动特效 html &l ...

  6. 原生js实现架子鼓特效

    这是代码完成的效果,按下abcd会出现对应的架子鼓音乐的效果. 简单的介绍下代码思路,html和css部分就不多说了. 重要的是js部分. 大致是这样的, 首先获取到所有的按钮为一个数组,然后遍历整个 ...

  7. Javascript学习记录——原生JS实现旋转木马特效

    昨天学习到了JS特效部分,然后老师讲了旋转木马特效的实现,如上图.不过只是讲了通过点击箭头实现图片的切换,对于点击图片本身以及二者联动却是没有讲解. 本着一颗追求完美的心,今天花费了一个中午终于将整个 ...

  8. 墙裂推荐4款js网页烟花特效

    以下是几款网页特效和一款软件: http://keleyi.com/keleyi/phtml/jstexiao/1.htm  http://keleyi.com/keleyi/phtml/jstexi ...

  9. HTML5/CSS3(PrefixFree.js) 3D文字特效

    之前在园子里看到一个HTML5/CSS3的文字特效(这里),觉得挺好玩的所以小小的研究了下,不过发现代码都是针对webkit以及FF的所以IE跪了. Runjs 我将示例中的代码进行了精简,后来发现C ...

随机推荐

  1. 提升布局性能____Re-using Layouts with <include/>

    可以再一个布局中通过"include"和"merge"元素进行复用其他的布局元素. 比如如下一个布局: <FrameLayout xmlns:androi ...

  2. 无法在<fastCGI>应用程序配置中找到<handler> scriptProcessor

    在打开php文件的时候发现iis7.5报错了 每次在切换php版本的时候不知道为什么会出现这个错误,有的时候就又不会报错直接可以正常使用,然而php版本确定已经下载好,才可能的打开这个页面,那么就是i ...

  3. linux svn 中文 https://my.oschina.net/VASKS/blog/659236

    https://my.oschina.net/VASKS/blog/659236 设置服务器: export LC_ALL=zh_CN.UTF-8长久之计, echo export LC_ALL=zh ...

  4. Android总结之打开手机相册获取图片

    上一篇,总结了如何打开照相机获取图片,详情请看>>>> 这篇将总结如何打开手机存储(相册)来获取手机上的图片. 打开相册 在需要这个功能的类中,我们可以自定义一个方法openA ...

  5. jmeter使用问题——将接口返回变量存储成csv文件

    在使用jmeter做接口测试时,一整个jmx测试计划中,存在多个线程,多个接口的测试 但是接口可以分类,比如业务接口.查询接口.更新接口等 考虑自动化接口测试一般都是一次性的,有完整的闭环链路,一般步 ...

  6. Java SE API 8

    百度云: 链接:http://pan.baidu.com/s/1pLMwiKz 密码:ep5f 官网网址:http://www.oracle.com/technetwork/java/javase/d ...

  7. Python小故事--------Tkinter的组件描述及解析

    概念 Tkinter: 是Tk图形用户界面工具包标准(ctl)的Python接口,作为一个轻量级的跨平台图形用户界面(GUI)开发工具 frame: 屏幕上的一块矩形区域,多是用来作为容器(conta ...

  8. 前端jQuery学习(一)

    把最近学习的前端框架jQuery整理一下.你可能听说过jQuery,因为他是JavaScript世界中使用最广泛的一个库. 江湖传言,全世界大约有80~90%的网站直接或间接地使用了jQuery.鉴于 ...

  9. LinkedList实现类

    List还有一个LinkedList的实现,它是一个基于链表实现的List类,对于顺序访问集合中的元素进行了优化,特别是当插入.删除元素时速度非常快.因为LinkedList即实现了List接口,也实 ...

  10. JavaScript-基本语法和数据类型

           前奏:在HTML中使用JavaScript 1_推荐src引用外部JavaScript文件,方便管理与维护,标签位置在页面最下面,使浏览器更优先加载页面内容. 2_HTML页面需要有标准 ...