Maison interface Web js tutoriel Partagez un exemple de tutoriel sur le principe d'implémentation du composant de téléchargement d'images (React + Node)

Partagez un exemple de tutoriel sur le principe d'implémentation du composant de téléchargement d'images (React + Node)

May 11, 2017 pm 01:37 PM
react

Cet article présente principalement l'exemple de code d'implémentation du composant Reactpictureupload basé sur Node, qui est d'une grande valeur pratique. Les amis qui en ont besoin peuvent s'y référer. à cela

est écrit devant

Si le drapeau rouge ne tombe pas, je m'engage à exécuter JavaScript jusqu'au bout ! Aujourd'hui, je vais vous présenter les principes d'implémentation front-end et back-end (React + Node) du composant de téléchargement d'images dans mon projet open source Royal. Cela m'a pris du temps et j'espère que cela vous sera utile.

Implémentation front-end

Suite à l'idée de la composantisation React, j'ai fait télécharger l'image d'un composant indépendant (non autre dépendance), importez-le simplement directement.

import React, { Component } from 'react'
import Upload from '../../components/FormControls/Upload/'

//......

render() {
  return (
    <p><Upload uri={&#39;http://jafeney.com:9999/upload&#39;} /></p>
  )
}
Copier après la connexion

Le paramètre uri doit être transmis, qui est l'adresse de l'interface du backend pour le téléchargement de l'image. La façon d'écrire l'interface sera discutée ci-dessous.

Page de rendu

La partie rendu du composant doit refléter trois fonctions :

  1. Sélection d'image ( fenêtre de dialogue)

  2. Fonction pouvant être glissée (conteneur de déplacement)

  3. Prévisualisable (liste d'aperçu)

  4. Télécharger bouton (bouton)

  5. Télécharger l'adresse et le lien de l'image terminée (liste d'informations)

Principal renderFonction

render() {
  return (
    <form action={this.state.uri} method="post" encType="multipart/form-data">
      <p className="ry-upload-box">
        <p className="upload-main">
          <p className="upload-choose">
            <input
              onChange={(v)=>this.handleChange(v)}
              type="file"
              size={this.state.size}
              name="fileSelect"
              accept="image/*"
              multiple={this.state.multiple} />
            <span ref="dragBox"
              onDragOver={(e)=>this.handleDragHover(e)}
              onDragLeave={(e)=>this.handleDragHover(e)}
              onDrop={(e)=>this.handleDrop(e)}
              className="upload-drag-area">
              或者将图片拖到此处
            </span>
          </p>
          <p className={this.state.files.length?
             "upload-preview":"upload-preview ry-hidden"}>
            { this._renderPreview();  // 渲染图片预览列表 }
          </p>
        </p>
        <p className={this.state.files.length?
           "upload-submit":"upload-submit ry-hidden"}>
           <button type="button"
             onClick={()=>this.handleUpload()}
             class="upload-submit-btn">
             确认上传图片
           </button>
        </p>
        <p className="upload-info">
          { this._renderUploadInfos();  // 渲染图片上传信息 }
        </p>
      </p>
    </form>
  )
}
Copier après la connexion

Liste d'aperçu des images rendues

_renderPreview() {
  if (this.state.files) {
    return this.state.files.map((item, idx) => {
      return (
        <p className="upload-append-list">
          <p>
            <strong>{item.name}</strong>
            <a href="javascript:void(0)" rel="external nofollow" 
              className="upload-delete"
              title="删除" index={idx}></a>
            <br/>
            <img src={item.thumb} className="upload-image" />
           </p>
           <span className={this.state.progress[idx]?
             "upload-progress":
             "upload-progress ry-hidden"}>
             {this.state.progress[idx]}
           </span>
         </p>
      )
    })
  } else {
    return null
  }
}
Copier après la connexion

Liste d'informations de téléchargement des images rendues

_renderUploadInfos() {
  if (this.state.uploadHistory) {
    return this.state.uploadHistory.map((item, idx) => {
      return (
        <p>
          <span>上传成功,图片地址是:</span>
          <input type="text" class="upload-url" value={item.relPath}/>
          <a href={item.relPath} target="_blank">查看</a>
         </p>
      );
    })
  } else {
    return null;
  }
}
Copier après la connexion

Téléchargement de fichiers

Le principe du téléchargement d'images sur le front-end est de construire l'objet FormData, d'append() l'objet fichier à l'objet, puis de le monter en XMLSend() sur l'objet HttpRequest vers le serveur.

Obtenir l'objet fichier

Pour obtenir l'objet fichier, vous devez utiliser l'événement change de la zone de saisie pour obtenir le handle paramètre e

onChange={(e)=>this.handleChange(e)}
Copier après la connexion

Ensuite, effectuez le traitement suivant :

e.preventDefault()
let target = event.target
let files = target.files
let count = this.state.multiple ? files.length : 1
for (let i = 0; i < count; i++) {
  files[i].thumb = URL.createObjectURL(files[i])
}
// 转换为真正的数组
files = Array.prototype.slice.call(files, 0)
// 过滤非图片类型的文件
files = files.filter(function (file) {
  return /image/i.test(file.type)
})
Copier après la connexion

À ce stade, les fichiers sont un tableau d'objets fichiers dont nous avons besoin et le concatérons dans les fichiers d'origine.

this.setState({files: this.state.files.concat(files)})
Copier après la connexion

De cette façon, l'opération suivante peut obtenir le fichier image actuellement sélectionné via this.state.files.

Utilisez Promise pour gérer le téléchargement asynchrone

Le téléchargement de fichiers est asynchrone par rapport au navigateur Afin de gérer le téléchargement multi-images ultérieur, Promise est introduit ici pour gérer l'asynchrone. Fonctionnement :

upload(file, idx) {
  return new Promise((resolve, reject) => {
    let xhr = new XMLHttpRequest()
    if (xhr.upload) {
      // 上传中
      xhr.upload.addEventListener("progress", (e) => {
        // 处理上传进度
        this.handleProgress(file, e.loaded, e.total, idx);
      }, false)
      // 文件上传成功或是失败
      xhr.onreadystatechange = (e) => {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
          // 上传成功操作
          this.handleSuccess(file, xhr.responseText)
          // 把该文件从上传队列中删除
          this.handleDeleteFile(file)
          resolve(xhr.responseText);
         } else {
          // 上传出错处理 
          this.handleFailure(file, xhr.responseText)
          reject(xhr.responseText);
         }
      }
    }
    // 开始上传
    xhr.open("POST", this.state.uri, true)
    let form = new FormData()
    form.append("filedata", file)
    xhr.send(form)
  })
}
Copier après la connexion

Calcul de la progression du téléchargement

L'avantage d'utiliser l'objet XMLHttpRequest pour envoyer des requêtes asynchrones est qu'il peut calculer la progression du traitement des requêtes, qui récupère n'a pas.

Nous pouvons ajouter une surveillance d'événement pour l'événement de progression de l'objet xhr.upload :

xhr.upload.addEventListener("progress", (e) => {
  // 处理上传进度
  this.handleProgress(file, e.loaded, e.total, i);
}, false)
Copier après la connexion

Explication : Le paramètre idx est le index qui enregistre la file d'attente de téléchargement multi-images

handleProgress(file, loaded, total, idx) {
  let percent = (loaded / total * 100).toFixed(2) + &#39;%&#39;;
  let _progress = this.state.progress;
  _progress[idx] = percent;
  this.setState({ progress: _progress }) // 反馈到DOM里显示
}
Copier après la connexion

Téléchargement par glisser-déposer

Le glisser-déposer de fichiers est en fait très simple pour HTML5 car il vient avec plusieurs écouteurs d'événements Le mécanisme peut effectuer ce type de traitement directement. Les trois suivants sont principalement utilisés :

onDragOver={(e)=>this.handleDragHover(e)}
onDragLeave={(e)=>this.handleDragHover(e)}
onDrop={(e)=>this.handleDrop(e)}
Copier après la connexion

Comportement du navigateur lors de l'annulation du glisser-déposer :

handleDragHover(e) {
  e.stopPropagation()
  e.preventDefault()
}
Copier après la connexion

Traitement des fichiers glissés :

handleDrop(e) {
  this.setState({progress:[]})
  this.handleDragHover(e)
  // 获取文件列表对象
  let files = e.target.files || e.dataTransfer.files
  let count = this.state.multiple ? files.length : 1
  for (let i = 0; i < count; i++) {
    files[i].thumb = URL.createObjectURL(files[i])
  }
  // 转换为真正的数组 
  files = Array.prototype.slice.call(files, 0)
  // 过滤非图片类型的文件
  files = files.filter(function (file) {
    return /image/i.test(file.type)
  })
  this.setState({files: this.state.files.concat(files)})
}
Copier après la connexion

Télécharger plusieurs images en même temps

Prend en charge plusieurs téléchargements d'images. Nous devons définir l'attribut au point d'appel du composant :

multiple = { true } // 开启多图上传 
size = { 50 }    // 一次最大上传数量(虽没有上限,为保证服务端正常,建议50以下)
Copier après la connexion

Ensuite. nous pouvons utiliser Promise.all() pour gérer la file d'attente des opérations asynchrones :

handleUpload() {
  let _promises = this.state.files.map((file, idx) => this.upload(file, idx))
  Promise.all(_promises).then( (res) => {
    // 全部上传完成 
    this.handleComplete()
  }).catch( (err) => { console.log(err) })
}
Copier après la connexion

D'accord, le travail frontal est terminé et la prochaine étape est le travail de Node.

Implémentation du backend

Pour plus de commodité, le backend utilise le framework express pour créer rapidement des services et un routage HTTP. Pour des projets spécifiques, voir mon github node-image-upload. Bien que la logique soit simple, il y a quand même plusieurs points remarquables :

Appel cross-domain

Le backend de ce projet utilise express, on peut utiliser res .header( ) définit la "source autorisée" de la requête pour autoriser les appels inter-domaines :

res.header(&#39;Access-Control-Allow-Origin&#39;, &#39;*&#39;);
Copier après la connexion

est défini sur * pour autoriser toute source d'accès, qui est moins sécurisée. Il est recommandé de le définir sur le nom de domaine de deuxième niveau dont vous avez besoin, tel que jafeney.com.

En plus de « Autoriser la source », d'autres incluent « Autoriser l'en-tête », « Autoriser le domaine », « Autoriser la méthode », « Type de texte », etc. Les paramètres couramment utilisés sont les suivants :

function allowCross(res) {
  res.header(&#39;Access-Control-Allow-Origin&#39;, &#39;*&#39;);  
  res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
  res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
  res.header("X-Powered-By",' 3.2.1')
  res.header("Content-Type", "application/json;charset=utf-8");
}
Copier après la connexion

Requête Ajax sous ES6

La requête Ajax sous ES6 est différente de celle d'ES5 et sera réinitialisée avant la demande formelle est émis. Envoyez d'abord une requête de type OPTIONS à titre de test. Ce n'est que lorsque la requête est réussie que la requête formelle peut être envoyée au serveur.

所以服务端路由 我们还需要 处理这样一个 请求:

router.options('*', function (req, res, next) {
  res.header(&#39;Access-Control-Allow-Origin&#39;, &#39;*&#39;);
  res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
  res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
  res.header("X-Powered-By",' 3.2.1')
  res.header("Content-Type", "application/json;charset=utf-8");
  next();
});
Copier après la connexion

注意:该请求同样需要设置跨域。

处理上传

处理上传的图片引人了multiparty模块,用法很简单:

/*使用multiparty处理上传的图片*/
router.post(&#39;/upload&#39;, function(req, res, next) { 
  // 生成multiparty对象,并配置上传目标路径
  var form = new multiparty.Form({uploadDir: &#39;./public/file/&#39;});
  // 上传完成后处理
  form.parse(req, function(err, fields, files) {
    var filesTmp = JSON.stringify(files, null, 2);
    var relPath = &#39;&#39;;
    if (err) {
      // 保存失败 
      console.log(&#39;Parse error: &#39; + err);
    } else {
      // 图片保存成功!
      console.log(&#39;Parse Files: &#39; + filesTmp);
      // 图片处理
      processImg(files);
    }
  });
});
Copier après la connexion

图片处理

Node处理图片需要引入 gm 模块,它需要用 npm 来安装

npm install gm --save
Copier après la connexion

BUG说明

注意:node的图形操作gm模块前使用必须 先安装 imagemagick 和 graphicsmagick,Linux (ubuntu)上使用apt-get 安装:

sudo apt-get install imagemagick
sudo apt-get install graphicsmagick --with-webp // 支持webp格式的图片
Copier après la connexion

MacOS上可以用 Homebrew 直接安装:

  brew install imagemagick
  brew install graphicsmagick --with-webp  // 支持webp格式的图片
Copier après la connexion

预设尺寸

有些时候除了原图,我们可能需要把原图等比例缩小作为预览图或者缩略图。这个异步操作还是用Promise来实现:

function reSizeImage(paths, dstPath, size) {
  return new Promise(function(resolve, reject) {
    gm(dstPath)
    .noProfile()
    .resizeExact(size)
    .write(&#39;.&#39; + paths[1] + &#39;@&#39; + size + &#39;00.&#39; + paths[2], function (err) {
      if (!err) {
        console.log(&#39;resize as &#39; + size + &#39; ok!&#39;)
        resolve()
      }
      else {
        reject(err)
      };
    });
  });
}
Copier après la connexion

重命名图片

为了方便排序和管理图片,我们按照 “年月日 + 时间戳 + 尺寸” 来命名图片:

var _dateSymbol = new Date().toLocaleDateString().split(&#39;-&#39;).join(&#39;&#39;);
var _timeSymbol = new Date().getTime().toString();
Copier après la connexion

至于图片尺寸 使用 gm的 size() 方法来获取,处理方式如下:

gm(uploadedPath).size(function(err, size) {
  var dstPath = &#39;./public/file/&#39; + _dateSymbol + _timeSymbol 
    + &#39;_&#39; + size.width + &#39;x&#39; + size.height + &#39;.&#39; 
    + _img.originalFilename.split(&#39;.&#39;)[1];
  var _port = process.env.PORT || &#39;9999&#39;;
    relPath = &#39;http://&#39; + req.hostname + ( _port!==80 ? &#39;:&#39; + _port : &#39;&#39; ) 
    + &#39;/file/&#39; + _dateSymbol + _timeSymbol + &#39;_&#39; + size.width + &#39;x&#39; 
    + size.height + &#39;.&#39; + _img.originalFilename.split(&#39;.&#39;)[1];
  // 重命名
  fs.rename(uploadedPath, dstPath, function(err) {
    if (err) {
      reject(err)
    } else {
      console.log(&#39;rename ok!&#39;);
    }
  });
});
Copier après la connexion

总结

对于大前端的工作,理解图片上传的前后端原理仅仅是浅层的。我们的口号是 “把JavaScript进行到底!”,现在无论是 ReactNative的移动端开发,还是NodeJS的后端开发,前端工程师可以做的工作早已不仅仅是局限于web页面,它已经渗透到了互联网应用层面的方方面面,或许,叫 全栈工程师 更为贴切吧。

【相关推荐】

1. 免费js在线视频教程

2. JavaScript中文参考手册

3. php.cn独孤九贱(3)-JavaScript视频教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment créer une application de chat en temps réel avec React et WebSocket Comment créer une application de chat en temps réel avec React et WebSocket Sep 26, 2023 pm 07:46 PM

Comment créer une application de chat en temps réel à l'aide de React et WebSocket Introduction : Avec le développement rapide d'Internet, la communication en temps réel a attiré de plus en plus d'attention. Les applications de chat en direct font désormais partie intégrante de la vie sociale et professionnelle moderne. Cet article expliquera comment créer une application simple de chat en temps réel à l'aide de React et WebSocket, et fournira des exemples de code spécifiques. 1. Préparation technique Avant de commencer à créer une application de chat en temps réel, nous devons préparer les technologies et outils suivants : React : un pour la construction

Guide pour la séparation du front-end et du back-end de React : Comment réaliser le découplage et le déploiement indépendant du front-end et du back-end Guide pour la séparation du front-end et du back-end de React : Comment réaliser le découplage et le déploiement indépendant du front-end et du back-end Sep 28, 2023 am 10:48 AM

Guide de séparation front-end et back-end de React : Comment réaliser un découplage front-end et back-end et un déploiement indépendant, des exemples de code spécifiques sont nécessaires Dans l'environnement de développement Web actuel, la séparation front-end et back-end est devenue une tendance. En séparant le code front-end et back-end, le travail de développement peut être rendu plus flexible, plus efficace et faciliter la collaboration en équipe. Cet article expliquera comment utiliser React pour réaliser une séparation front-end et back-end, atteignant ainsi les objectifs de découplage et de déploiement indépendant. Tout d’abord, nous devons comprendre ce qu’est la séparation front-end et back-end. Dans le modèle de développement Web traditionnel, le front-end et le back-end sont couplés

Comment créer des applications Web simples et faciles à utiliser avec React et Flask Comment créer des applications Web simples et faciles à utiliser avec React et Flask Sep 27, 2023 am 11:09 AM

Comment utiliser React et Flask pour créer des applications Web simples et faciles à utiliser Introduction : Avec le développement d'Internet, les besoins des applications Web deviennent de plus en plus diversifiés et complexes. Afin de répondre aux exigences des utilisateurs en matière de facilité d'utilisation et de performances, il devient de plus en plus important d'utiliser des piles technologiques modernes pour créer des applications réseau. React et Flask sont deux frameworks très populaires pour le développement front-end et back-end, et ils fonctionnent bien ensemble pour créer des applications Web simples et faciles à utiliser. Cet article détaillera comment exploiter React et Flask

Comment créer une application de messagerie fiable avec React et RabbitMQ Comment créer une application de messagerie fiable avec React et RabbitMQ Sep 28, 2023 pm 08:24 PM

Comment créer une application de messagerie fiable avec React et RabbitMQ Introduction : Les applications modernes doivent prendre en charge une messagerie fiable pour obtenir des fonctionnalités telles que les mises à jour en temps réel et la synchronisation des données. React est une bibliothèque JavaScript populaire pour créer des interfaces utilisateur, tandis que RabbitMQ est un middleware de messagerie fiable. Cet article explique comment combiner React et RabbitMQ pour créer une application de messagerie fiable et fournit des exemples de code spécifiques. Présentation de RabbitMQ :

Guide de l'utilisateur de React Router : Comment implémenter le contrôle de routage frontal Guide de l'utilisateur de React Router : Comment implémenter le contrôle de routage frontal Sep 29, 2023 pm 05:45 PM

Guide de l'utilisateur de ReactRouter : Comment implémenter le contrôle du routage frontal Avec la popularité des applications monopage, le routage frontal est devenu un élément important qui ne peut être ignoré. En tant que bibliothèque de routage la plus populaire de l'écosystème React, ReactRouter fournit des fonctions riches et des API faciles à utiliser, rendant la mise en œuvre du routage frontal très simple et flexible. Cet article expliquera comment utiliser ReactRouter et fournira quelques exemples de code spécifiques. Pour installer ReactRouter en premier, nous avons besoin

Comment créer des applications de traitement de données en temps réel à l'aide de React et Apache Kafka Comment créer des applications de traitement de données en temps réel à l'aide de React et Apache Kafka Sep 27, 2023 pm 02:25 PM

Comment utiliser React et Apache Kafka pour créer des applications de traitement de données en temps réel Introduction : Avec l'essor du Big Data et du traitement de données en temps réel, la création d'applications de traitement de données en temps réel est devenue la priorité de nombreux développeurs. La combinaison de React, un framework front-end populaire, et d'Apache Kafka, un système de messagerie distribué hautes performances, peut nous aider à créer des applications de traitement de données en temps réel. Cet article expliquera comment utiliser React et Apache Kafka pour créer des applications de traitement de données en temps réel, et

L'applet WeChat implémente la fonction de téléchargement d'images L'applet WeChat implémente la fonction de téléchargement d'images Nov 21, 2023 am 09:08 AM

L'applet WeChat implémente la fonction de téléchargement d'images Avec le développement de l'Internet mobile, l'applet WeChat est devenue un élément indispensable dans la vie des gens. Les mini-programmes WeChat fournissent non seulement une multitude de scénarios d'application, mais prennent également en charge les fonctions définies par les développeurs, notamment les fonctions de téléchargement d'images. Cet article présentera comment implémenter la fonction de téléchargement d'images dans l'applet WeChat et fournira des exemples de code spécifiques. 1. Travaux préparatoires Avant de commencer à écrire du code, nous devons télécharger et installer les outils de développement WeChat et nous inscrire en tant que développeur WeChat. En même temps, vous devez également comprendre WeChat

Enseignement du nœud PI: Qu'est-ce qu'un nœud PI? Comment installer et configurer le nœud PI? Enseignement du nœud PI: Qu'est-ce qu'un nœud PI? Comment installer et configurer le nœud PI? Mar 05, 2025 pm 05:57 PM

Explication détaillée et guide d'installation pour les nœuds de pignon Cet article introduira l'écosystème de pignon en détail - nœuds PI, un rôle clé dans l'écosystème de pignon et fournir des étapes complètes pour l'installation et la configuration. Après le lancement du réseau de test de la blockchain pèse, les nœuds PI sont devenus une partie importante de nombreux pionniers participant activement aux tests, se préparant à la prochaine version du réseau principal. Si vous ne connaissez pas encore Pinetwork, veuillez vous référer à ce qu'est Picoin? Quel est le prix de l'inscription? PI Utilisation, exploitation minière et sécurité. Qu'est-ce que Pinetwork? Le projet Pinetwork a commencé en 2019 et possède sa pièce exclusive de crypto-monnaie PI. Le projet vise à en créer un que tout le monde peut participer

See all articles