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.xhr
和req.accepts
。如果是AJAX请求(XHR是XML HTTP请求的简称,AJAX依赖于XHR),req.xhr
值为true
。req.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请求时设置dataType
和accepts
属性。
文件上传###
一般,文件上传可以使用Connect的内置中间件multipart
来处理。但是,这个中间件已经从Connect中移除了,一旦Express更新了对Connect的依赖项,它也将从Express中消失,所以我强烈建议你不要使用这个中间件。
对于复合表单处理,目前有两种流行而健壮的选择:Busboy和
Formidable。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.js
、js/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>' +
' ' + file.originalName + '</div>'));
});
}
});
});
</script>
{{/section}}
- 为上传按钮添加CSS动态样式:
.btn-file {
position: relative;
overflow: hidden;
}
.btn-file input[type=file] {
position: absolute;
top: 0;
right: 0;
min-width: 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文档网页找到你想要的资源。
express-11 表单处理(2)的更多相关文章
- ddms(基于 Express 的表单管理系统)源码学习
ddms是基于express的一个表单管理系统,今天抽时间看了下它的代码,其实算不上源码学习,只是对它其中一些小的开发技巧做一些记录,希望以后在项目开发中能够实践下. 数据层封装 模块只对外暴露mod ...
- iOS开发笔记11:表单键盘遮挡、浮点数价格格式化显示、省市区选择器、View Debugging
1.表单键盘遮挡 应用场景为一个collectionView上有多个textfield.textView供用户填写信息. 之前输入项较少时,采取的方法比较粗暴,didSelectItemAtIndex ...
- Express ~ 获取表单 get 和 post 提交方式传送参数的对比
一,获取 get 提交的参数 var id = req.query.id || '' 二,获取 post 提交的参数 var name = req.body.name || ''
- html_表单
一.表单框架简介 表单是提供让读者在网页上输入,勾选和选取数据,以便提交给服务器数据库的工具.(用于将信息提交给服务器) <form>...</form>标记 作用:用于创建一 ...
- from表单实现无跳转上传文件,接收页面后台数据。
本文基于我刚写的http://www.cnblogs.com/iwang5566/p/6287529.html进行了简单的扩展,实现页面无跳转表单数据提交,并接收后台返回的数据. 下载好,上一篇文章d ...
- js02--对象、函数、switch、for、异常、表单验证
现在我们接着来继续学习有关js的一些基础. 1.undefined与null undefined:当变量声明但尚未赋值时,它的类型就是undefined null:表示一个不存在的对象,它 ...
- bootstrap基础学习【表单含按钮】(二)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- HTML表单学习
HTML表单学习 前言 HTML基础学习会由HTML基础标签学习.HTML表单学习和一张思维导图总结HTML基础三篇文章构成,文章中博主会提取出重点常用的知识和经常出现的bug,提高学习的效率,后续会 ...
- SpringMVC学习系列(11) 之 表单标签
本篇我们来学习Spring MVC表单标签的使用,借助于Spring MVC提供的表单标签可以让我们在视图上展示WebModel中的数据更加轻松. 一.首先我们先做一个简单了例子来对Spring MV ...
随机推荐
- Android 中沉浸式状态栏实现
Android 中沉浸式状态栏实现方式如下 计算状态栏高度及调用沉浸式状态栏的相关API方法 package com.example.status; import android.annotation ...
- 【Git】参与github上其他人的项目
来源:廖雪峰 访问感兴趣的项目主页.,点“Fork”就在自己的账号下克隆了该项目仓库,然后,从自己的账号下clone到本地,就可以工作啦~ 以bootstrap项目为例,这个关系如下图所示: 一定要从 ...
- iOS开发MAC下配置Svn和Git
如果你对iOS开发中的版本控制还不了解那么你可以先看看这篇(大致看一遍就ok) http://www.cnblogs.com/iCocos/p/4767692.html 关于版本控制使用起来并不难 ...
- php dirname($path) 中文路径不对问题
将$path中的\改为/ $dir=__FILE__;$dir = str_replace("\\","/", $dir);$dir=dirname($dir) ...
- 兼容iOS 10:配置获取隐私数据权限声明
原文链接 iOS 10的一大变化是更强的隐私数据保护.在文档中是这么描述的: You must statically declare your app’s intended use of protec ...
- Android ArrayAdapter使用
1. 可以直接使用getContext()获取Context对象 2. 可以在构造方法中传入context, 数据对象的列表, super(context, 0, object);完成Adapter的 ...
- The Triangle
针对如下形式的ACM试题,大多出自南阳理工学院的在线ACM试题(网址: 南阳理工在线评测系统),在此非常感谢,同时也非常感谢作者的分享! 时间限制:1000 ms | 内存限制:65535 KB ...
- 三、jQuery--jQuery基础--jQuery基础课程--第8章 jQuery 实现Ajax应用
1.使用load()方法异步请求数据 使用load()方法通过Ajax请求加载服务器中的数据,并把返回的数据放置到指定的元素中,它的调用格式为:load(url,[data],[callback]) ...
- mysql 5.6.33 重置密码后报错
[root@ Desktop]# mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with ; o ...
- 数据结构和算法 – 10.集合
集合: 联合.交叉.差异.子集 using System; using System.Collections; using System.Collections.Generic; using Syst ...