博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用JavaScript和Canvas开发广告素材上载互动
阅读量:2510 次
发布时间:2019-05-11

本文共 17052 字,大约阅读时间需要 56 分钟。

How nice or fun can we do the interactions on a website or web application? The truth is that most could be better than we do today. For example, who would not want to use an application like this?

我们可以在网站或Web应用程序上进行互动有多有趣? 事实是,大多数情况可能会比今天更好。 例如,谁不想使用这样的应用程序?

Dribble Shot by Jakub Antalík

I would upload things there, again and again, just to have the pleasure of watching the animation :)

我会一遍又一遍地上传东西,只是为了欣赏动画而感到高兴:)

Well in this tutorial we will see how to implement a creative component to upload files, using as inspiration the previous by Jakub Antalík. The Idea is to bring better visual feedback around what happens with the file after is dropped.

在本教程中,我们将看到如何实现创意组件,并以JakubAntalík的上一个为灵感。 这个想法是关于删除文件后如何处理带来更好的视觉反馈。

We will be focusing only on implementing the drag and drop interactions and some animations, without actually implementing all the necessary logic to actually upload the files to the server and use the component in production.

我们将只注重实现dragdrop的相互作用和一些动画,而无需实际执行所有必要的逻辑实际的文件上传到服务器,并在生产中使用的组件。

This is what our component will look like:

这是我们的组件的外观:

Creative Upload Interaction

You can see the or play with the . But if you also want to know how it works, just keep reading :)

您可以观看或玩 。 但是,如果您还想知道其工作原理,请继续阅读:)

During the tutorial we will be seeing two main aspects:

在本教程中,我们将看到两个主要方面:

  • We will learn how to implement a simple particle system using Javascript and Canvas.

    我们将学习如何使用Javascript和Canvas实现简单的粒子系统。
  • We will implement everything necessary to handle drag and drop events to upload files.

    我们将实施一切必要措施来处理dragdrop事件来上传文件。

In addition to the usual technologies (HTML, CSS, Javascript), to code our component we will use the lightweight animation library .

除了常用的技术(HTML,CSS,Javascript)之外,我们还将使用轻量级动画库来编码我们的组件。

So without further ado, let's start!

因此,事不宜迟,让我们开始吧!

( )

In this case our HTML structure will be quite simple:

在这种情况下,我们HTML结构将非常简单:

As you can see, we only need a form element and a file type input to allow the upload of files to the server. In our component we also need a canvas element to draw the particles and an SVG icon.

如您所见,我们只需要一个form元素和一个file类型input即可将文件上传到服务器。 在我们的组件中,我们还需要一个canvas元素来绘制粒子和一个SVG图标。

Keep in mind that to use a component like this in production, you must fill in the action attribute in the form, perhaps add a label element for the input, etc.

请记住,要在生产中使用这样的组件,必须在表单中填写action属性,也许为输入添加一个label元素,等等。

( )

We will be using SCSS as the CSS preprocessor, but the styles we are using are very close to being plain CSS and they are quite simple.

我们将使用SCSS作为CSS预处理程序,但是我们使用的样式非常接近纯CSS,而且非常简单。

Let's start by positioning the form and canvas elements, among other basic styles:

让我们从canvas formcanvas元素以及其他基本样式开始:

// Position `form` and `canvas` full width and height.upload, .upload__canvas {
position: absolute; left: 0; top: 0; width: 100%; height: 100%;}// Position the `canvas` behind all other elements.upload__canvas {
z-index: -1;}// Hide the file `input`.upload__input {
display: none;}

Now let's see the styles needed for our form, both for the initial state (hidden) and for when it is active (the user is dragging files to upload). The code has been commented exhaustively for a better understanding:

现在,让我们看一下form所需的样式,包括初始状态(隐藏)和活动状态(用户拖动文件进行上传)所需的样式。 该代码已被详尽注释以更好地理解:

// Styles for the upload `form`.upload {
z-index: 1; // should be the higher `z-index` // Styles for the `background` background-color: rgba(4, 72, 59, 0.8); background-image: radial-gradient(ellipse at 50% 120%, rgba(4, 72, 59, 1) 10%, rgba(4, 72, 59, 0) 40%); background-position: 0 300px; background-repeat: no-repeat; // Hide it by default opacity: 0; visibility: hidden; // Transition transition: 0.5s; // Upload overlay, that prevent the event `drag-leave` to be triggered while dragging over inner elements &:after {
position: absolute; content: ''; left: 0; top: 0; width: 100%; height: 100%; }}// Styles applied while files are being dragging over the screen.upload--active {
// Translate the `radial-gradient` background-position: 0 0; // Show the upload component opacity: 1; visibility: visible; // Only transition `opacity`, preventing issues with `visibility` transition-property: opacity;}

Finally, let's look at the simple styles that we have applied to the upload icon:

最后,让我们看一下已应用于上传图标的简单样式:

// Styles for the icon.upload__icon {
position: relative; left: calc(50% - 40px); top: calc(50% - 40px); width: 80px; height: 80px; padding: 15px; border-radius: 100%; background-color: #EBF2EA; path {
fill: rgba(4, 72, 59, 0.8); }}

Now our component looks like we want, so we're ready to add interactivity with Javascript.

现在我们的组件看起来像我们想要的,因此我们准备添加与Javascript的交互性。

( )

Before implementing the drag and drop functionality, let's see how we can implement a simple particle system.

实施之前dragdrop功能,让我们看看如何可以实现一个简单的粒子系统。

In our particle system, each particle will be a simple Javascript Object with basic parameters to define how the particle should behave. And all the particles will be stored in an Array, which in our code is particles.

在我们的粒子系统中,每个粒子将是一个具有基本参数的简单Javascript Object ,用于定义粒子的行为。 并且所有粒子都将存储在Array ,在我们的代码中是particles

Then, adding a new particle to our system is as simple as creating a new Javascrit Object and adding it to the particles array. Check the comments so you understand the purpose of each property:

然后,将新粒子添加到我们的系统就像创建一个新的Javascrit Object并将其添加到particles数组一样简单。 检查注释,以便您了解每个属性的用途:

// Create a new particlefunction createParticle(options) {
var o = options || {
}; particles.push({
'x': o.x, // particle position in the `x` axis 'y': o.y, // particle position in the `y` axis 'vx': o.vx, // in every update (animation frame) the particle will be translated this amount of pixels in `x` axis 'vy': o.vy, // in every update (animation frame) the particle will be translated this amount of pixels in `y` axis 'life': 0, // in every update (animation frame) the life will increase 'death': o.death || Math.random() * 200, // consider the particle dead when the `life` reach this value 'size': o.size || Math.floor((Math.random() * 2) + 1) // size of the particle });}

Now that we have defined the basic structure of our particle system, we need a loop function, which allows us to add new particles, update them and draw them on the canvas in each animation frame. Something simple like this:

现在,我们已经定义了粒子系统的基本结构,我们需要一个循环函数,该函数允许我们添加新的粒子,更新它们并将其绘制在每个动画帧中的canvas上。 像这样简单的东西:

// Loop to redraw the particles on every framefunction loop() {
addIconParticles(); // add new particles for the upload icon updateParticles(); // update all particles renderParticles(); // clear `canvas` and draw all particles iconAnimationFrame = requestAnimationFrame(loop); // loop}

Now let's see how we have defined all the functions that we call inside the loop. As always, pay attention to the comments:

现在,让我们看看如何定义在循环中调用的所有函数。 与往常一样,请注意以下注释:

// Add new particles for the upload iconfunction addIconParticles() {
iconRect = uploadIcon.getBoundingClientRect(); // get icon dimensions var i = iconParticlesCount; // how many particles we should add? while (i--) {
// Add a new particle createParticle({
x: iconRect.left + iconRect.width / 2 + rand(iconRect.width - 10), // position the particle along the icon width in the `x` axis y: iconRect.top + iconRect.height / 2, // position the particle centered in the `y` axis vx: 0, // the particle will not be moved in the `x` axis vy: Math.random() * 2 * iconParticlesCount // value to move the particle in the `y` axis, greater is faster }); }}// Update the particles, removing the dead onesfunction updateParticles() {
for (var i = 0; i < particles.length; i++) {
if (particles[i].life > particles[i].death) {
particles.splice(i, 1); } else {
particles[i].x += particles[i].vx; particles[i].y += particles[i].vy; particles[i].life++; } }}// Clear the `canvas` and redraw every particle (rect)function renderParticles() {
ctx.clearRect(0, 0, canvasWidth, canvasHeight); for (var i = 0; i < particles.length; i++) {
ctx.fillStyle = 'rgba(255, 255, 255, ' + (1 - particles[i].life / particles[i].death) + ')'; ctx.fillRect(particles[i].x, particles[i].y, particles[i].size, particles[i].size); }}

And we have our simple particle system ready, where we can add new particles defining the options we want, and the loop will be responsible for performing the animation.

我们已经准备好了简单的粒子系统,可以在其中添加新的粒子来定义所需的选项,而循环将负责执行动画。

( )

Now let's see how we prepare the upload icon to be animated:

现在,让我们看一下如何准备要上载动画的上载图标:

// Add 100 particles for the icon (without render), so the animation will not look empty at firstfunction initIconParticles() {
var iconParticlesInitialLoop = 100; while (iconParticlesInitialLoop--) {
addIconParticles(); updateParticles(); }}initIconParticles();// Alternating animation for the icon to translate in the `y` axisfunction initIconAnimation() {
iconAnimation = anime({
targets: uploadIcon, translateY: -10, duration: 800, easing: 'easeInOutQuad', direction: 'alternate', loop: true, autoplay: false // don't execute the animation yet, only on `drag` events (see later) });}initIconAnimation();

With the previous code, we only need a couple of other functions to pause or resume the animation of the upload icon, as appropriate:

使用前面的代码,我们仅需要适当的几个其他函数即可暂停或恢复上传图标的动画:

// Play the icon animation (`translateY` and particles)function playIconAnimation() {
if (!playingIconAnimation) {
playingIconAnimation = true; iconAnimation.play(); iconAnimationFrame = requestAnimationFrame(loop); }}// Pause the icon animation (`translateY` and particles)function pauseIconAnimation() {
if (playingIconAnimation) {
playingIconAnimation = false; iconAnimation.pause(); cancelAnimationFrame(iconAnimationFrame); }}

( )

Then we can start adding the drag and drop functionality to upload the files. Let's start by preventing unwanted behaviors for each related event:

然后我们就可以开始添加dragdrop功能,上传的文件。 让我们从防止每个相关事件的不良行为开始:

// Preventing the unwanted behaviours['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop'].forEach(function (event) {
document.addEventListener(event, function (e) {
e.preventDefault(); e.stopPropagation(); });});

Now we will handle the events of type drag, where we will activate the form so that it is shown, and we will play the animations for the upload icon:

现在,我们将处理类型为drag的事件,在该事件中,我们将激活form以使其显示,并为上载图标播放动画:

// Show the upload component on `dragover` and `dragenter` events['dragover', 'dragenter'].forEach(function (event) {
document.addEventListener(event, function () {
if (!animatingUpload) {
uploadForm.classList.add('upload--active'); playIconAnimation(); } });});

In case the user leaves the drop zone, we simply hide the form again and pause the animations for the upload icon:

如果用户离开drop区,我们只需再次隐藏form并暂停上载图标的动画即可:

// Hide the upload component on `dragleave` and `dragend` events['dragleave', 'dragend'].forEach(function (event) {
document.addEventListener(event, function () {
if (!animatingUpload) {
uploadForm.classList.remove('upload--active'); pauseIconAnimation(); } });});

And finally the most important event that we must handle is the drop event, because it will be where we will obtain the files that the user has dropped, we will execute the corresponding animations, and if this were a fully functional component we would upload the files to the server through AJAX.

最后,我们必须处理的最重要的事件是drop事件,因为它将是获取用户放置的文件的位置,我们将执行相应的动画,如果这是功能齐全的组件,我们将上载文件通过AJAX发送到服务器。

// Handle the `drop` eventdocument.addEventListener('drop', function (e) {
if (!animatingUpload) {
// If no animation in progress droppedFiles = e.dataTransfer.files; // the files that were dropped filesCount = droppedFiles.length > 3 ? 3 : droppedFiles.length; // the number of files (1-3) to perform the animations if (filesCount) {
animatingUpload = true; // Add particles for every file loaded (max 3), also staggered (increasing delay) var i = filesCount; while (i--) {
addParticlesOnDrop(e.pageX + (i ? rand(100) : 0), e.pageY + (i ? rand(100) : 0), 200 * i); } // Hide the upload component after the animation setTimeout(function () {
uploadForm.classList.remove('upload--active'); }, 1500 + filesCount * 150); // Here is the right place to call something like: // triggerFormSubmit(); // A function to actually upload the files to the server } else {
// If no files where dropped, just hide the upload component uploadForm.classList.remove('upload--active'); pauseIconAnimation(); } }});

In the previous code snippet we saw that the function addParticlesOnDrop is called, which is in charge of executing the particle animation from where the files were dropped. Let's see how we can implement this function:

在前面的代码片段中,我们看到调用了addParticlesOnDrop函数,该函数负责执行放置文件的粒子动画。 让我们看看如何实现此功能:

// Create a new particles on `drop` eventfunction addParticlesOnDrop(x, y, delay) {
// Add a few particles when the `drop` event is triggered var i = delay ? 0 : 20; // Only add extra particles for the first item dropped (no `delay`) while (i--) {
createParticle({
x: x + rand(30), y: y + rand(30), vx: rand(2), vy: rand(2), death: 60 }); } // Now add particles along the way where the user `drop` the files to the icon position // Learn more about this kind of animation in the `anime.js` documentation anime({
targets: {
x: x, y: y}, x: iconRect.left + iconRect.width / 2, y: iconRect.top + iconRect.height / 2, duration: 500, delay: delay || 0, easing: 'easeInQuad', run: function (anim) {
var target = anim.animatables[0].target; var i = 10; while (i--) {
createParticle({
x: target.x + rand(30), y: target.y + rand(30), vx: rand(2), vy: rand(2), death: 60 }); } }, complete: uploadIconAnimation // call the second part of the animation });}

Finally, when the particles reach the position of the icon, we must move the icon upwards, giving the impression that the files are being uploaded:

最后,当粒子到达图标的位置时,我们必须向上移动图标,给人的印象是正在上传文件:

// Translate and scale the upload iconfunction uploadIconAnimation() {
iconParticlesCount += 2; // add more particles per frame, to get a speed up feeling anime.remove(uploadIcon); // stop current animations // Animate the icon using `translateY` and `scale` iconAnimation = anime({
targets: uploadIcon, translateY: {
value: -canvasHeight / 2 - iconRect.height, duration: 1000, easing: 'easeInBack' }, scale: {
value: '+=0.1', duration: 2000, elasticity: 800 }, complete: function () {
// reset the icon and all animation variables to its initial state setTimeout(resetAll, 0); } });}

To finish, we must implement the resetAll function, which resets the icon and all the variables to its initial state. We must also update the canvas size and reset the component on resize event. But in order not to make the tutorial longer and heavier, we have not included these and other minor details, although you can check the complete code in the .

最后,我们必须实现resetAll函数,该函数将图标和所有变量重置为其初始状态。 我们还必须更新canvas大小,并在发生resize事件时重置组件。 但是为了不使本教程变得更长而又繁重,尽管您可以在检查完整的代码,但我们并未包含这些细节和其他次要细节。

( )

And finally our component is complete! Let's take a look:

最后,我们的组件完成了! 让我们来看看:

Creative Upload Interaction

You can check the , play with the , or get the .

您可以查看 , 使用 ,或获取 。

Throughout the tutorial we saw how to create a simple particle system, as well as handle drag and drop events to implement an eye-catching file upload component.

在本教程中,我们看到了如何创建一个简单的粒子系统,以及手柄dragdrop事件来实现一个醒目的文件上传组件。

Remember that this component is not ready to be used in production. In case you want to complete the implementation to make it fully functional, I recommend checking this .

请记住,该组件尚未准备好在生产中使用。 如果您想完成实现以使其完全发挥作用,我建议您检查该 。

We hope you liked the final result, and that this tutorial has been useful!

我们希望您喜欢最终结果,并且本教程对您有所帮助!

翻译自:

转载地址:http://dguwd.baihongyu.com/

你可能感兴趣的文章
C#中ref和out的使用小结
查看>>
Powershell-远程操作
查看>>
Java基础学习笔记二十一 多线程
查看>>
使用Java Low Level REST Client操作elasticsearch
查看>>
css3 抖动
查看>>
移动端手势
查看>>
[Linked List]Insertion Sort List
查看>>
Product of Array Except Self
查看>>
[Tree]Binary Tree Inorder Traversal
查看>>
Response.Redirect和Server.Transfer比较
查看>>
European software vendors ranking 2012 (zz)
查看>>
甘油三酯 (zz)
查看>>
Publish的时候某些需要用到的文件没deploy上去
查看>>
五班二组白盒测试实践进度(4)
查看>>
html/css基础篇——关于浏览器window、document、html、body高度的探究
查看>>
tomcat部署项目的三种方式
查看>>
POJ 2015 Permutation Code
查看>>
BZOJ3153 : Sone1
查看>>
[Shell]做一个自己的rm命令来替换系统自带的,以免误删除之后恢复不了
查看>>
记一次服务器被植入挖矿木马cpu飙升200%解决过程
查看>>