【问题标题】:Need Help! Angular 2 File/Image upload via API需要帮忙!通过 API 上传 Angular 2 文件/图像
【发布时间】:2017-03-31 08:23:38
【问题描述】:

我正在使用 Angular2 上传图像/文件。我不喜欢添加任何插件来上传 angular2 中的文件。是否有任何简单的方法可以通过 API 使用 Angular2 上传图片而无需任何第三方扩展?

注意:我使用 laravel 作为服务器

【问题讨论】:

    标签: angular file-upload laravel-5.3 angular-file-upload


    【解决方案1】:

    以下是从 Angular 2 将图像(或文件)上传到服务器时需要完成/考虑的事项。

    1. 使用以下元素创建图像上传组件。 模板:

    <div class="image-upload"
         fileDrop
         [accept]="['image/*']"
         (isFileOver)="fileOver($event)"
         (fileDrop)="fileChange($event)"
         [ngClass]="{'file-is-over': isFileOver}"
    >
      <div class="file-upload hr-inline-group">
        <label class="upload-button">
          <span>{{buttonCaption}}</span>
          <input
            type="file"
            accept="image/*"
            (change)="fileChange(input.files)"
            #input>
        </label>   
    
        <div class="drag-box-message">{{dropBoxMessage}}</div>
      </div>
        <div *ngIf="fileSizeExceeded" class="drag-box-message">
            <p>Please upload a file less than 2 MB.</p>
        </div>
    
      <div *ngIf="preview" class="image-container hr-inline-group">
        <div
          class="image"
          *ngFor="let file of files"
          [ngStyle]="{'background-image': 'url('+ file.src +')'}"
        >
          <div *ngIf="file.pending" class="loading-overlay">
            <div class="spinningCircle"></div>
          </div>
          <div *ngIf="!file.pending" class="x-mark" (click)="deleteFile(file)">
            <span class="close"></span>
          </div>
        </div>
      </div>
    </div>
    1. 您的组件类,需要导出。

    import { Component, Input, Output, EventEmitter } from '@angular/core';
    import { ImageService, Header } from "../../../services/content/image.service";
    
    export class FileHolder {
        public serverResponse: any;
        public pending: boolean = false;
        constructor(public src: string, public file: File) { }
    }
    
    @Component({
        selector: 'image-upload',
        templateUrl: "app/components/controls/image-upload/image-upload.component.html",
        styles: [
            `
    .image-upload {
      --common-radius: 3px;
      --active-color: #33CC99;
      position: relative;
      border-radius: var(--common-radius);
      border: #d0d0d0 dashed 1px;
      font-family: sans-serif;
    }
    
    .file-is-over {
      border-color: var(--active-color);
      border-style: solid;
    }
    
    .hr-inline-group:after {
      display: table;
      clear: both;
      content: "";
    }
    
    .file-upload {
      padding: 16px;
      background-color: #f8f8f8;
    }
    
    .drag-box-message {
      float: left;
      display: inline-block;
      margin-left: 12px;
      padding-top: 14px;
      color: #9b9b9b;
      font-weight: 600;
    }
    
    label.upload-button input[type=file] {
      display: none;
      position: fixed;
      top: -99999px;
    }
    
    .upload-button {
      cursor: pointer;
      background-color: var(--active-color);
      padding: 10px;
      color: white;
      font-size: 1.25em;
      font-weight: 500;
      text-transform: uppercase;
      display: inline-block;
      float: left;
      
      -webkit-box-shadow: 2px 2px 4px 0px rgba(148,148,148,0.6);
      -moz-box-shadow: 2px 2px 4px 0px rgba(148,148,148,0.6);
      box-shadow: 2px 2px 4px 0px rgba(148,148,148,0.6);
    }
    
    .upload-button:active span{
      position: relative;
      display: block;
      top: 1px;
    }
    
    .image-container {
      background-color: #fdfdfd;
      padding: 0 10px 0 10px;
    }
    
    .image {
      float: left;
      display: inline-block;
      margin: 6px;
      width: 86px;
      height: 86px;
      background: center center no-repeat;
      background-size: contain;
      position: relative;
    }
    
    .x-mark {
      width: 20px;
      height: 20px;
      text-align: center;
      cursor: pointer;
      border-radius: 2px;
      float: right;
      background-color: black;
      opacity: .7;
      color: white;
      margin: 2px;
    }
    
    .close {
      width: 20px;
      height: 20px;
      opacity: .7;
      position: relative;
      padding-right: 3px;
    }
    .x-mark:hover .close {
      opacity: 1;
    }
    .close:before, .close:after {
      border-radius: 2px;
      position: absolute;
      content: '';
      height: 16px;
      width: 2px;
      top: 2px;
      background-color: #FFFFFF;
    }
    
    .close:before {
      transform: rotate(45deg);
    }
    
    .close:after {
      transform: rotate(-45deg);
    }
    
    .loading-overlay {
      position: absolute;
      top: 0; left: 0; bottom: 0; right: 0;
      background-color: black;
      opacity: .7;
    }
    
    .spinningCircle {
      height: 30px;
      width: 30px;
      margin: auto;
      position: absolute;
      top: 0; left: 0; bottom: 0; right: 0;
      border-radius: 50%;
      border: 3px solid rgba(255, 255, 255, 0);
      border-top: 3px solid white;
      border-right: 3px solid white;
      -webkit-animation: spinner 2s infinite cubic-bezier(0.085, 0.625, 0.855, 0.360);
      animation: spinner 2s infinite cubic-bezier(0.085, 0.625, 0.855, 0.360);
    }
    
    @-webkit-keyframes spinner {
      0% {
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
      }
      100% {
        -webkit-transform: rotate(360deg);
        transform: rotate(360deg);
      }
    }
    
    @keyframes spinner {
      0% {
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
      }
      100% {
        -webkit-transform: rotate(360deg);
        transform: rotate(360deg);
    
      }
    }
    `
        ]
    })
    export class ImageUploadComponent {
        @Input() max: number = 100;
        @Input() url: string;
        @Input() headers: Header[];
        @Input() preview: boolean = true;
    
        @Output()
        isPending: EventEmitter<boolean> = new EventEmitter<boolean>();
        @Output()
        onFileUploadFinish: EventEmitter<FileHolder> = new EventEmitter<FileHolder>();
        @Output()
        onRemove: EventEmitter<FileHolder> = new EventEmitter<FileHolder>();
    
        private files: FileHolder[] = [];
    
        private fileCounter: number = 0;
        private pendingFilesCounter: number = 0;
        private fileSizeExceeded: boolean = false;
    
        private isFileOver: boolean = false;
    
        @Input()
        buttonCaption: string = "Select Images";
        @Input()
        dropBoxMessage: string = "Drop your images here!";
    
        constructor(private imageService: ImageService) { }
    
        ngOnInit() {
            this.imageService.setUrl(this.url);
        }
    
        fileChange(files) {
            let remainingSlots = this.countRemainingSlots();
            let filesToUploadNum = files.length > remainingSlots ? remainingSlots : files.length;
    
            if (this.url && filesToUploadNum != 0) {
                this.isPending.emit(true);
            }
    
            this.fileCounter += filesToUploadNum;
    
            this.uploadFiles(files, filesToUploadNum);
        }
    
        private uploadFiles(files, filesToUploadNum) {
            for (let i = 0; i < filesToUploadNum; i++) {
                let file = files[i];
    
                console.log('FILE SIZE: ', file.size);
    
                if (file.size > 3000000) {
                    this.fileSizeExceeded = true;
                    return;
                }
    
                let img = document.createElement('img');
                img.src = window.URL.createObjectURL(file);
    
                let reader = new FileReader();
                reader.addEventListener('load', (event: any) => {
                    let fileHolder: FileHolder = new FileHolder(event.target.result, file);
    
                    fileHolder.serverResponse = `good boy: ${i}`;
    
                    this.uploadSingleFile(fileHolder);
    
                    this.files.push(fileHolder);
    
                }, false);
    
    
                reader.readAsDataURL(file);
            }
        }
    
        private uploadSingleFile(fileHolder: FileHolder) {
            if (this.url) {
                this.pendingFilesCounter++;
                fileHolder.pending = true;
    
                this.imageService.postImage(fileHolder.file, this.headers).subscribe(response => {
                    fileHolder.serverResponse = response;
                    this.onFileUploadFinish.emit(fileHolder);
                    fileHolder.pending = false;
                    if (--this.pendingFilesCounter == 0) {
                        this.isPending.emit(false);
                    }
                });
    
            } else {
                this.onFileUploadFinish.emit(fileHolder);
            }
        }
    
        private deleteFile(file: FileHolder): void {
            let index = this.files.indexOf(file);
            this.files.splice(index, 1);
            this.fileCounter--;
    
            this.onRemove.emit(file);
        }
    
        fileOver(isOver) {
            this.isFileOver = isOver;
        }
    
        private countRemainingSlots() {
            return this.max - this.fileCounter;
        }
    }
    1. 将其导入您的 App 模块,并将其作为声明的一部分。

    2. 现在这个组件可以在任何地方使用来上传图片。

    3. 该组件负责添加可以包含服务器将使用的身份验证令牌的请求标头。

    希望对您有所帮助。

    【讨论】:

      【解决方案2】:
      1. 模板

      <input type="file" (change)="fileChangeEvent($event)" placeholder="Upload file..." />
      <button type="button" (click)="upload()">Upload</button>
      1. 服务

      export class FileUpload{
      /* This method will worked for single file upload, if you need multipule file upload then replace formData.append("uploads", files[i], files[i].name); to formData.append("uploads[]", files[i], files[i].name);
      */
      makeFileRequest(url: string, params: Array<string>, files: Array<File>) {
              return new Promise((resolve, reject) => {
                  var formData: any = new FormData();
                  var xhr = new XMLHttpRequest();
                  for(var i = 0; i < files.length; i++) {
                      formData.append("uploads", files[i], files[i].name);
                  }
                  xhr.onreadystatechange = function () {
                      if (xhr.readyState == 4) {
                          if (xhr.status == 200) {
                              resolve(JSON.parse(xhr.response));
                          } else {
                              reject(xhr.response);
                          }
                      }
                  }
                  xhr.open("POST", url, true);
                  xhr.send(formData);
              });
          }
      }
      1. 组件

      export class AppComponent {
        filesToUpload: Array<File>;
      
        constructor(private _fileUpload:FileUpload) {
              this.filesToUpload = [];
        }
      
        upload() {
              this._fileUpload.makeFileRequest("/api/admin/upload-slider-image", [], this.filesToUpload).then((result) => {
                  console.log(result);
              }, (error) => {
                  console.error(error);
              });
          }
      
          fileChangeEvent(fileInput: any){
              this.filesToUpload = <Array<File>> fileInput.target.files;
          }
       }

      【讨论】:

        猜你喜欢
        • 2011-08-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-04
        • 1970-01-01
        • 2011-10-21
        相关资源
        最近更新 更多