zoukankan      html  css  js  c++  java
  • express-11 表单处理(2)

    处理AJAX表单###

    用Express处理AJAX表单非常简单;甚至可以使用相同的处理程序来处理AJAX请求和常规的浏览器回退。

    • HTML文件 (/views/newsletter.handlebars)
    <div class="formContainer">
       <form class="form-horizontal newsletterForm" role="form"
               action="/process?form=newsletter" method="POST">
             <input type="hidden" name="_csrf" value="{{csrf}}">
             <div class="form-group">
                   <label for="fieldName" class="col-sm-2 control-label">Name</label>
                   <div class="col-sm-4">
                       <input type="text" class="form-control" id="fieldName" name="name">
                    </div>
             </div>
             <div class="form-group">
                   <label for="fieldEmail" class="col-sm-2 control-label">Email</label>
                   <div class="col-sm-4">
                       <input type="email" class="form-control" required id="fieldName" name="email">
                   </div>
             </div>
             <div class="form-group">
                   <div class="col-sm-offset-2 col-sm-4">
                       <button type="submit" class="btn btn-default">Register</button>
                   </div>
             </div>
        </form>
    </div>
    {{#section 'jquery'}}
        <script>
            $(document).ready(function(){
                  $('.newsletterForm').on('submit', function(evt){
                       evt.preventDefault();
                       var action = $(this).attr('action');
                       var $container = $(this).closest('.formContainer');
                       $.ajax({
                           url: action,
                           type: 'POST',
                           success: function(data){
                               if(data.success){
                                    $container.html('<h2>Thank you!</h2>');
                               } else {
                                    $container.html('There was a problem.');
                               }
                           },
                           error: function(){
                                    $container.html('There was a problem.');
                           }
                        });
                     });
                  });
         </script>
    {{/section}}
    
    • 应用程序文件
    app.post('/process', function(req, res){
         if(req.xhr || req.accepts('json,html')==='json'){
             // 如果发生错误,应该发送 { error: 'error description' }
             res.send({ success: true });
          } else {
             // 如果发生错误,应该重定向到错误页面
             res.redirect(303, '/thank-you');
          }
    });
    

    Express提供了两个方便的属性:req.xhrreq.accepts。如果是AJAX请求(XHR是XML HTTP请求的简称,AJAX依赖于XHR),req.xhr值为truereq.accepts试图确定返回的最合适的响应类型。在此例中,req.accepts('json,html')询问最佳返回格式是JSON还是HTML:这可以根据Accepts HTTP头信息推断出来,它是浏览器提供的可读的、有序的响应类型列表。如果是一个AJAX请求,或者User-Agent明确要求JSON优先于HTML,那么就会返回合适的JSON数据;否则,返回一个重定向。

    在这个函数里可以做任何处理:通常会将数据保存到数据库。如果出现问题,则返回一个err属性(而不是success)的JSON对象,或者重定向到一个错误页面(如果不是AJAX请求)。

    在此例中,假设所有AJAX请求的是JSON数据,但是并没有要求AJAX通信必须使用JSON(事实上,“X”在AJAX中代表XML)。这个方法是jQuery友好的,因为通常jQuery假定所有数据都是JSON格式的。如果想让AJAX处理程序通用,或者知道AJAX请求使用JSON之外的东西,你应该根据Accepts头信息(可以根据req.accepts辅助方法轻松访问)返回一个适当的响应。如果响应完全基于Accepts头信息,你或许想看看c,这是一个可以根据客户端预期轻松做出适当响应的简便方法。如果这样做,必须保证用jQuery发起AJAX请求时设置dataTypeaccepts属性。

    文件上传###

    一般,文件上传可以使用Connect的内置中间件multipart来处理。但是,这个中间件已经从Connect中移除了,一旦Express更新了对Connect的依赖项,它也将从Express中消失,所以我强烈建议你不要使用这个中间件。

    对于复合表单处理,目前有两种流行而健壮的选择:BusboyFormidable。Formidable要稍微简单一些,因为它有一个方便的回调方法,能够提供包含字段和文件信息的对象。对于Busboy而言,必须对每一个字段和文件事件进行监听。

    • (views/contest/vacation-photo.handlebars)
    <form class="form-horizontal" role="form"
              enctype="multipart/form-data" method="POST"
              action="/contest/vacation-photo/{year}/{month}">
            <div class="form-group">
                 <label for="fieldName" class="col-sm-2 control-label">Name</label>
                 <div class="col-sm-4">
                      <input type="text" class="form-control"
                       id="fieldName" name="name">
                 </div>
            </div>
            <div class="form-group">
                <label for="fieldEmail" class="col-sm-2 control-label">Email</label>
                <div class="col-sm-4">
                      <input type="email" class="form-control" required
                          id="fieldName" name="email">
                </div>
            </div>
            <div class="form-group">
                 <label for="fieldPhoto" class="col-sm-2 control-label">Vacation photo
                 </label>
                 <div class="col-sm-4">
                      <input type="file" class="form-control" required accept="image/*" id="fieldPhoto" name="photo">
                 </div>
            </div>
            <div class="form-group">
                 <div class="col-sm-offset-2 col-sm-4">
                      <button type="submit" class="btn btn-primary">Submit</button>
                 </div>
            </div>
    </form>
    

    注意,我们必须指定enctype="multipart/form-data"来启用文件上传。我们也可以通过accept属性来限制上传文件的类型(这是可选的)。

    • 安装Formidable(npm install --save formidable)并创建一下路由处理程序:
    var formidable = require('formidable');
    
    app.get('/contest/vacation-photo',function(req,res){
        var now = new Date();
        res.render('contest/vacation-photo',{
            year: now.getFullYear(),month: now.getMont()
        });
    });
    
    app.post('/contest/vacation-photo/:year/:month', function(req, res){
        var form = new formidable.IncomingForm();
        form.parse(req, function(err, fields, files){
            if(err) return res.redirect(303, '/error');
            console.log('received fields:');
            console.log(fields);
            console.log('received files:');
            console.log(files);
            res.redirect(303, '/thank-you');
        });
    });
    

    (year和month被指定为路由参数)。继续运行,检查控制台日志。你会发现表单字段如你预期的那样:是一个有字段名称属性的对象。文件对象包含更多的数据,但这是相对简单的。对于每一个上传的文件,你会看到属性有文件大小、上传路径(通常是在临时目录中的一个随机名字),还有用户上传此文件的原始名字(文件名,而不是整个路径,出于安全隐私考虑)。

    接下来如何处理这个文件就取决于你了:可以将它保存到数据库,将其复制到更持久的位置,或者上传到云端文件存储系统。记住,如果你基于本地存储保存文件,应用程序不能很好地扩展,基于云端存储是一个更好的选择。

    jQuery文件上传###

    如果想为用户提供真正别出心裁的文件上传,可拖拽,可以看到上传文件缩略图,并查看进度条,那推荐 Sebastian Tschan的jQuery File Upload

    要显示文件缩略图,jquery-file-upload-middleware使用[ImageMagick](http://www.imagemagick.org

    在Ubuntu和Debian系统中,可以使用apt-get install imagemagick安装ImageMagick;在OS X中,你可以使用brew install imagemagick来安装。对于其他操作系统,请参考[ImageMagick文档](http://www.imagemagick.org/script/binary-releases.php)。

    • 首先,安装jquery-file-upload-middleware包(npm install --save jquery-file-upload-middleware),然后在你的应用文件中添加以下代码:
    var jqupload = require('jquery-file-upload-middleware');
    
    app.use('/upload', function(req, res, next){
        var now = Date.now();
        jqupload.fileHandler({
             uploadDir: function(){
                 return __dirname + '/public/uploads/' + now;
             },
             uploadUrl: function(){
                 return '/uploads/' + now;
             },
         })(req, res, next);
    });
    

    除非为所有访问者提供一个共用的文件上传区域,否则可能要将上传文件区分开来。简单的方法是创建一个时间戳目录来存储文件。更实际的做法是使用用户ID或其他唯一ID来创建子目录。

    请注意,我们将jQuery File Upload中间件挂载在/upload前缀上。你可以在这里使用任何前缀,但是确保该前缀不用于其他路由或中间件,不然会干扰文件上传操作。

    • 接下来是文件上传的视图,你可以直接复制演示上传代码:你可以在project's GitHub页面上传最新项目包。

    如果你只想要一个可构建的最小示例,需要如下脚本:

    js/vendor/jquery.ui.widget.jsjs/jquery.iframe-transport.js和js/jquery.fileupload.js。

    在这个最小实现中,我们将<input type="file">元素放在<span>中,还有一个<div>用来列出所有已上传文件:

    <span class="btn btn-default btn-file">
         Upload
         <input type="file" class="form-control" required accept="image/*"
             id="fieldPhoto" data-url="/upload" multiple name="photo">
    </span>
    <div id="uploads"></div>
    
    • 然后我们加上jQuery File Upload:
    {{#section 'jquery'}}
         <script src="/vendor/jqfu/js/vendor/jquery.ui.widget.js"></script>
         <script src="/vendor/jqfu/js/jquery.iframe-transport.js"></script>
         <script src="/vendor/jqfu/js/jquery.fileupload.js"></script>
         <script>
             $(document).ready(function(){
    
                  $('#fieldPhoto').fileupload({
                         dataType: 'json',
                         done: function(e, data){
                             $.each(data.result.files, function(index, file){
                                 $('#fileUploads').append($('<div class="upload">' +
                                       '<span class="glyphicon glyphicon-ok"></span>' +
                                       '&nbsp;' + file.originalName + '</div>'));
                             });
                         }
                  });
             });
         </script>
    {{/section}}
    
    • 为上传按钮添加CSS动态样式:
    .btn-file {
        position: relative;
        overflow: hidden;
    }
    .btn-file input[type=file] {
        position: absolute;
        top: 0;
        right: 0;
        min- 100%;
        min-height: 100%;
        font-size: 999px;
        text-align: right;
        filter: alpha(opacity=0);
        opacity: 0;
        outline: none;
        background: white;
        cursor: inherit;
        display: block;
    }
    

    注意,<input>标签里的data-url属性必须和用于中间件的路由前缀相匹配。在这个简单示例中,当一个文件上传完成后,一个<div class="upload">元素会附加到之前的<div id="uploads">下面。这个列表只显示文件名和大小,不提供删除、运行或者缩略图功能。但这是一个好的开始。定制jQuery File Upload演示程序会让人望而生畏,如果你的视角完全不同,从最小程序开始逐渐向上构建,而不是从演示和定制开始,可能会更简单。不管怎样,你会在jQuery File Upload文档网页找到你想要的资源。

  • 相关阅读:
    作业 20180918-2 每周例行报告
    将Python文件打包为exe文件,并在控制台运行之简易教程
    作业20181011-1 每周例行报告
    用WebView加载本地图片的方法
    ios webview自适应实际内容高度4种方法
    UIWebView加载本地网页与图片的方法
    nonatomic与atomic的区别与作用
    @dynamic与@synthesize的区别与用法
    xib与storyboard的区别
    iOS与H5的交互
  • 原文地址:https://www.cnblogs.com/jinkspeng/p/4281865.html
Copyright © 2011-2022 走看看