使用backbone.js、node.js和express实现AJAX图片上传

4
我已经在网上搜寻了一整天,试图找到一个上传图片的完整示例,包括如何从backbone模型中创建一个普通的POST请求。初步调查后,我发现HTML5中的FileReader API可以实现这个功能。通过测试,我已经成功地在backbone之外通过创建XMLHttpRequest()来实现了这一点。
我现在要解决的问题是如何让backbone将FILES数据与POST请求一起发送,就像在常规多部分表单工作流程中那样。我对backbone还比较陌生,所以请原谅任何明显的错误。这是我目前的代码:
define(                                                                                                                                                
    [                                                                                                                                                  
        'backbone'                                                                                                                                     
    ],                                                                                                                                                 

    function (Backbone) {                                                                                                                              
        var Mock = Backbone.Model.extend({                                                                                                             
            url: '/api/v1/mocks',                                                                                                                      
            idAttribute: '_id',                                                                                                                        

            readFile: function(file){                                                                                                                  
                var reader = new FileReader();                                                                                                         
                self = this;                                                                                                                           

                reader.onload = (function(mockFile){                                                                                                   
                    return function(e){                                                                                                                
                        self.set({filename: mockFile.name, data: e.target.result});                                                                    
                    };                                                                                                                                 
                })(file);                                                                                                                              

                reader.readAsDataURL(file);                                                                                                            
            }                                                                                                                                          
        });                                                                                                                                            

        return Mock;                                                                                                                                   
    }                                                                                                                                                  
);

视图

define(
    [
        'jquery',
        'backbone',
        'underscore',
        'text!../templates/create_mock-template.html',
        'models/mock',
        'collections/mocks'
    ],

    function ($, Backbone, _, createMockTemplate, Mock, mocksCollection) {
        var CreateMockView = Backbone.View.extend({
            template: _.template(createMockTemplate),

            events: {
                'submit form': 'onFormSubmit',
                'click #upload-link': 'process',
                'change #upload': 'displayUploads'
            },

            initialize: function () {
                this.render();
                return this;
            },

            render: function () {
                this.$el.html(this.template);
            },

                        process: function(e){
                                var input = $('#upload');
                                if(input){
                                        input.click();
                                }
                                e.preventDefault();
                        },

                        displayUploads: function(e){
                                // Once a user selects some files the 'change' event is triggered (and this listener function is executed)
                                // We can access selected files via 'this.files' property object.

                                var formdata = new FormData();
                                var img, reader, file;
                                var self = this;

                                for (var i = 0, len = e.target.files.length; i < len; i++) {
                                        file = e.target.files[i];

                                        if (!!file.type.match(/image.*/)) {
                                                if (window.FileReader) {
                                                        reader = new FileReader();
                                                        reader.onloadend = function (e) { 
                                                                self.createImage(e.target.result, e);
                                                        };
                                                        self.file = file;
                                                        reader.readAsDataURL(file);
                                                }
                                        }   
                                }
                        },

                        createImage: function(source, fileobj) {
                                var image = '<img src="'+source+'" class="thumbnail" width="200" height="200" />'
                                this.$el.append(image);
                        },

            onFormSubmit: function (e) {
                e.preventDefault();

                // loop through form elements
                var fields = $(e.target).find('input[type=text], textarea');
                var data = {};

                // add names and vlaues to data object
                $(fields).each(function(i, f) {
                    data[$(f).attr('name')] = $(f).attr('value');
                }); 

                // create new model from data
                var mock = new Mock(data);

                // this should set the filename and data attributes on the model???
                mock.readFile(this.file);

                // save to the server
                mock.save(null, {
                    wait: true,
                    error: function(model, response) {
                        console.log(model)
                    },
                    success: function(model, response) {
                        mocksCollection.add(model);
                        console.log(model, response);
                    }
                });
            },
        });

        return CreateMockView;
    }
);

我完全理解这可能有些模糊不清,它更多是一个概念验证而不是其他任何东西,并且也是学习backbone的好机会。因此,我的问题的关键是:

  • 当backbone向api发送请求时,为什么我在向node / express服务器发送请求时没有看到数据和文件名属性?
  • 我正在尝试做的事情是否可行,基本上我认为我应该能够读取数据attr并在服务器上创建图像?
  • 是否有一种方法可以重写Mock model上的sync方法,并创建一个正确设置POST和FILES的请求。

我相信这是可能的,但我似乎找不到需要继续工作并使其正常工作的信息!

希望有人能帮助!

谢谢

编辑

只想提供更多信息,因为根据我的理解和与文档云IRC频道上的一些简短聊天,这应该有效。 因此,当我调用时

mock.readFile(this.file)

fileName和data属性似乎没有被设置。实际上,这里的控制台日志甚至似乎都没有触发,所以我猜这可能是问题所在。如果基于数据和文件名的值在节点端构建图像,我会对这种方法感到满意。那么为什么这些属性没有被设置并在post请求中传递到api呢?

2个回答

3
我已经解决了这种情况,将模型创建分为两个步骤:
  1. 基本信息
  2. 资产
例如,如果我的模型是电影,则显示一个创建表单,只包括标题和简介。此信息发送到服务器并创建模型。在下一步中,可以显示更新表单,现在非常容易使用文件上传插件,例如: 您还可以查看它们的源代码以获取参考,尝试实现一步式Backbone模型与文件创建解决方案。

嘿@fguillen,感谢您的回复。您看到我关于数据和文件名未设置在模型上,因此未在POST请求中传递给API的编辑了吗?我认为从readAsDataUrl数据构建图像是足够好的解决方案...这让我发疯了。我不知道为什么它不起作用!我确定这是在视图中调用的模拟模型上的readFile方法出了问题。 - Mike Waites
@MikeWaites 为了解决这个问题,我需要在一个可工作的代码中重新创建这个问题,但这可能对我来说是太多的工作。如果你能在jsFiddle或其他地方提供一个可工作的代码,我可以尝试查看它。如果你成功了,请在这里通知我。 - fguillen

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接