0

我正在构建一个基于 XHR 的 JavaScript 文件上传器。(实际上是 Ajax,因为我使用 jQuery)我使用一些 HTML5 功能作为 Drag&Drop API,以及 - 目前 - FileReader API。

我对这个过程有一些疑问,因为理论上有些东西我不明白。

由于某些原因,我自愿选择不使用现有且设计良好的插件/独立上传器之一:

  • 我有一些特定的需求,例如为项目添加标题和描述(如在 facebook 中)
  • 我会自己实现它作为 HTML5 API 的尝试。

我已经阅读了使用 Ajax 上传文件的教程,但我发现使用 FileReader API 最终将图像附加到 FormData API 很奇怪。

更重要的是,我真的不想有一个表单,我只是将图像放在一个放置区域,使用 FileReader API 获取文件内容,然后通过 AJAX 请求将其发送到我的服务器。

我只是想知道是否有人有更好的流程想法,因为目前:

  1. 我得到删除的文件并读取它的内容(异步,但需要一些时间......)
  2. 我将此内容与 AJAX 请求一起发送到服务器
  3. 我将内容写入服务器上的物理文件(再花一些时间)

我不知道如何优化/更快,但是看到大图的时间是愚蠢的,我只是不想通过示例来想象视频......是否可以通过示例仅使用 Ajax 发送文件的引用,并直接管理上传,而不是获取文件内容然后等待用户单击发送按钮发送它?

例如,facebook 上传器是如何工作的,他们似乎解决了问题/使用了一些东西来解决它?

(如果有人有兴趣得到它或看看,这里是我目前所做的一个小样本)

/* HTML */
<div id='drop-area'>
    <h3 class='placeholder'>Drop your files there!</h3>
</div>

/* CSS */
#drop-area {
    position: relative;
    width: 100%;
    height: 400px;
    border: 1px dashed grey;
    border-radius: 10px;
}
#drop-area.drag-over {
    border: 1px solid cyan;
}
#drop-area .placeholder {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 235px;
    height: 25px;
    margin: -12px 0 0 -117px;
    line-height: 25px;
    text-transform: uppercase;
}

/* JavaScript - jQuery way */
// This code is NOT AT ALL full-browser compatible !!
$(document).ready(function () {
    var i,
        $dropArea = $('drop-area'),
        fileReader,
        file,
        result,
        sendRequest = function () {
            $.ajax({
                url: 'upload.php',
                type: 'post',
                data: {
                    title: $('#title').val(),
                    description: $('#description').val(),
                    data: result, // base64 encoded data
                    type: file.type
                },
                processData: false, // No query string
                contentType: false // No data formatting
            }).fail(function (error, status) {
                console.log(error, status);
                alert('Fail...');
            }).done(function (response, output) {
                console.log(response, output);
                alert('Uploaded!');
            }).always(function () {
                $('#file-form-container').empty().detach();
            });
        },
        onFileFormSubmit = function (e) {
            e.preventDefault();
            sendRequest();
            return false;
        },
        displayForm = function (data) {
            $('body').append($('<div/>', {
                'id': 'file-form-container'
            }).append($('<form/>', {
                'action': '#',
                'id': 'file-form'
            }).append($('<img/>', {
                'src': data,
                'alt': 'File',
                'width': 100px
            })).append($('<input/>', {
                'id': 'title',
                'type': 'text',
                'name': 'title'
            })).append($('<textarea/>', {
                'id': 'description',
                'class': 'description',
                'name': 'description'
            })).append($('<input/>', {
                'type': 'submit',
                'name': 'submit',
                'value': 'Send!'
            }))));
        },
        onProgress = function (e) {
            console.log('progress', e);
            // Update a <progress> element...
        },
        onLoadEnd = function (e) {
            console.log('load end', e);
            result = e.target.result;
            displayForm(result);
        },
        onError = function (e) {
            console.log('error', e);
            // Display a message...
        }
        readFile = function (file) {
            fileReader = new FileReader();
            fileReader.onprogress = onProgress;
            fileReader.onerror = onError;
            fileReader.onloadend = onLoadEnd;
            fileReader.readAsDataURL(file);
        };

    $dropArea.on('dragenter', function (e) {
        $(this).addClass('drag-over');
    }).on('dragover', function (e) {
        e.preventDefault();
        e.originalEvent.dataTransfer.dropEffect = 'copy'; // Check the browser support if you want to fix the compatibility
    }).on('dragleave', function (e) {
        e.preventDefault();
        $(this).removeClass('drag-over');
    }).on('dragend', function (e) {
        e.preventDefault();
        $(this).removeClass('drag-over');
    }).on('drop', function (e) {
        // e || e.originalEvent ?
        e.preventDefault();
        e.stopPropagation();
        $(this).removeClass('drag-over');

        if (e.originalEvent.dataTransfer.files) {
            for (i = 0, i < e.originalEvent.dataTransfer.files.length; i++) {
                // Work with arrays to manage multiple files
                file = e.originalEvent.dataTransfer.files[i];
                readFile(file); // Read the file content then process the upload (callbacks)
            }
        }
    })
});

/* PHP - Symfony2 */
<?php

// Symfony 2 Controller Context

$em = $this->getDoctrine()->getEntityManager();

// get params
$request = $this->getRequest();

// Check for types, sizes, errors etc.
if ($request->get('data') && [...]) {
    [...]
}

// write the decoded data into a file
// fwrite(base64_decode(...));
// By the way, is there any OOP - MVC way to do that with Symfony2 ?
$path = ''; // define the file path


// Save the entity
$entity = new Picture();
$entity->setTitle($request->get('title'));
$entity->setDescription($request->get('description'));
$entity->setPath($path);
$em->persist($entity);
$em->flush();

return new JsonResponse(array($entity), 202);

?>
4

0 回答 0