jQuery插件实现-自定义Placeholder
HTML5中文本框的新属性placeholder
是个非常好用的属性,但是IE系列直至IE9都不支持这一属性,这就让大家在用这一属性的时候有些犹豫不决。自己曾经写过很多类似共的小控件,但是都不是很通用,这里分享一个渐进增强的自定义placeholder
的jQuery插件。有点是使用简单,大家也可以根据自己的需要进行改进。平常写jQuery插件比较少,考虑到用jQuery的同学比较多,这里就用jQuery插件的形式编写了。
在这里简单的介绍一下实现思路。
-
o
- 表现与
html5
原生的placeholder
尽量类似 - 渐进增强对于支持
placeholder
的浏览器不做处理
o
1.首先是几个工具方法:
-
o
supportProperty(nodeType, property)
,获取浏览器是否支持某一控件的某一属性getPositionInDoc(target, parent)
,获取对象在文档中的位置$c
,一个快速创建Dom对象的方法
o
o
这几个工具方法都是一些比较常见通用的方法,如果你有自己的或者更合适的可以自行替换。
2.主体,CustomPlaceholder
对象。这个对象主要是维护每一个文本框的信息,包括其位置,应该显示的提示信息等等,另外它还包含创建提示信息以及定位等方法以及对象的相应事件。
事件主要是在initEvents函数中进行的处理,这里特别要注意的是对提示信息事件的处理,当提示信息被点击时焦点应该被重新定位到文本框。而文本框要处理的则是focus
和blur
事件。
$(self.hint).bind( 'click', function(e){ oself.input.focus(); }); $(self.input).bind( 'focus', function(e){ oself.hint.style.display = 'none'; }); $(self.input).bind( 'blur', function(e){ oif(this.value == ''){ oself.hint.style.display = 'inline'; o} });
CustomPlacehodler对象的两个主要方法是createHintLabel(text, position)
和position()
。createHintLabel
是用于创建提示信息的DOM对象并对其进行定位,并返回这个对象。position方法用于强制对提示消息进行重新定位。主要用于页面大小改变的情况。这两个方法的功能和实现都比较简单。
3.插件的功能实现部分。jQuery插件实现方式就不多说了。这里首先进行了能力检测,如果原生支持placeholder则直接返回。
if(supportProperty('input', 'placeholder')){ oreturn; }
接下来是根据选择的input对象,生成相应的CustomPlaceholder对象,保存在数组中,并获取每个对象的提示信息的DOM对象,添加到容器中,最后将容器附加到body对象中。
var customPlaceholders = []; if(this.length > 0){ ovar box = $c('div', 'dk_placeholderfixed_box'); ofor(var i = 0, len = this.length; i < len; i++){ ovar input = this[i]; ocustomPlaceholders.push(new CustomPlaceholder(box, input, option)); o} odocument.body.appendChild(box); }
最后还有一件比较重要的事情,为window对象绑定resize事件,当window对象触发resize事件时对所有的customPlacehoder对象进行重新定位。
$(window).bind( 'resize', function(e){ ofor(var i = 0, len = customPlaceholders.length; i < len; i++){ ovar customPlaceholder = customPlaceholders[i]; ocustomPlaceholder.position(); o} });
这个简单的小插件到这里就写完了。
抛砖引玉,欢迎不吝赐教。
转载请注明原文出处《jQuery插件实现-自定义Placeholder》 如无特别声明,所有文章均遵守创作共用 署名-非商业-禁止演绎 3.0协议。
动手开发一个HTML5赛车小游戏
你是不是曾经也有自己做一个游戏的冲动呢?是不是因为事情太多,手头没空或者没有做过游戏的基础而屡屡放弃了呢?现在HTML5正如火如荼,让我们一起使用HTML5中的新功能做一个小游戏玩玩吧。
先来看看效果:
在线演示地址:点击查看
源代码GitHub:点击查看
麻雀虽小,五脏俱全。先来说一下这个小游戏有的内容:
-
o
- 一个开始画面,写了游戏的名字和一个开始按钮。
- 游戏的主体内容,一个可以自己控制的小汽车,还有很多打酱油的汽车,另外还有马路及马路旁边的龙套树木和自行车道…
- 一个结束游戏的画面。
o
o
好了这就是全部游戏的内容。游戏的玩法很简单,相信大家应该都玩过,就是一辆汽车在马路上跑,你要尽量躲避开其他汽车,不与他们相撞,否则游戏结束,游戏会以你跑过的旅程计算分数。
主要用的技术是HTML5中的画布元素Canvas和JavaScript。主要要做的工作就是实现Canvas的tween动画,一些简单的矢量,速度,位移等效果的处理。另外还有一些Sprint动画的处理。
具体的实现过程会在以后的文章中详细讲解。
目前本人正在进一步完善这个简单的JavaScript游戏引擎,以便使用这个游戏引擎实现一个SRPG游戏。新的游戏正在开发当中,如果您对此感兴趣欢迎联系我:dukai86@gmail.com
转载请注明原文出处《动手开发一个HTML5赛车小游戏》 如无特别声明,所有文章均遵守创作共用 署名-非商业-禁止演绎 3.0协议。
渐进增强的无刷新多图片上传控件(iFrame+HTML5)
目标:
实现一个无刷新的,多图片上传控件.(目前已在91美图网中使用)
特点:
采用渐进增强的设计思路,针对支持HTML5新特性比较好的现代浏览器,使用HTML5中的新特性,包括File
对象,XMLHttpRequest中的upload对象,File对象等新增的功能实现较为高级的多图片无刷新能够检测上传进度的上传控件.而对于不支持HTML5
特性的较老的浏览器则使用传统的隐藏iFrame
的形式来实现伪装的多图片上传功能.
优缺点分析:
对于支持HTML5的现代浏览器,可以通过原生的input
控件添加multiple属性实现文件的多选上传.这种方法可以使用XMLHttpReqeust
对象直接上传图片对象,使用较为方便,而且可以在本地获取图片上传的进度.但是目前占市场份额较多的IE浏览器包括IE9以及低于IE9版本的IE浏览器均不支持这项新内容.
所以对于不支持HTML5中的multiple
属性的input[type='file']
的浏览器这里采用了隐藏iframe,将待提交的表单的target设置为iframe
的name,以此来实现变通的无刷新图片上传.事实上,这种方法并不是没有刷新,而是把刷新的操作放到iframe中了而已.由于较旧的浏览器事实上并不支持上传控件的多选,所以这里只能通过多次选择,选中多个文件,操作较为复杂.而且本方法要想实现上传进度必须配合服务器端的查询,增加服务压力.
实现效果:
实现:
首先通过能力检查的方式判断浏览器是否支持HTML5中的新特性,如果支持的话选择HTML5的上传方式,不支持则使用传统的方式实现.
isSupportMultipleFile: window.File && window.FileReader && window.FileList && window.Blob,
在使用HTML5的新功能上传时用的主要内容有:1.<input type="file" />
控件的新属性multiple
,添加了此属性的控件支持同时选择多个文件,在选择完成后会自动生成一个File
对象的集合FileList
对象.这里我们就是通过监控input控件的onchange事件,来获取用户选中的文件.
File对象包括的主要属性:
-
o
- fileName-字符串,文件的名称
- fileSize-无符号的长整型,文件的大小的bytes
- name-字符串,文件名
- size-无符号长整型,File对象引用的文件的大小(bytes)
- type-字符串,File对象引用文件的类型(MIME type)
o
o
o
o
在获取到FileList之后根据每个File对象的内容生成界面中的待上传项目:
addUploadItem: function(guid, filename, percent){}
本方法主要是根据唯一编号,文件名称和当前进度生成一个待上传的条目,用于界面显示,主要操作为DOM操作,这里不再赘述.
接下来就是最主要的文件上传部分的内容了,主要的工作就是:当用户点击上传按钮时,将缓存起来的FileList遍历上传.
这里我采用了每次同时上传5个文件的策略,同时上传的文件太多会造成浏览器崩溃,以及服务器端阻塞超时的情况.具体同时上传文件数目可以根据实际情况决定.
这里要说明一下,使用XMLHttpReqeust对象上传File对象有两种方法:
-
o
- 直接使用XMLHttpRequest将File对象Post到服务器端,但是由于这样发送的内容没有有效的请求信息,只是将文件内容Post到服务器端,所以在服务器端无法通过正常的post获取文件内容,所以要自己读取服务器到的源内容来获取图片.
PHP
中可以通过$GLOBALS["HTTP_RAW_POST_DATA"]
来获取,ASP.NET中可以通过Request.BinaryRead(Request.TotalBytes)
来获取,其他语言您可以自行查找.当然文件的其他属性,比如大小,名称等等可以通过设置请求头的方式来实现,XMLHttpRequest.setReqeustHeader();
- 另外Mozilla Developer NetWork上提供了另外一种方法,即通过FileReader对象来获取File的二进制字符串,然后自己按照标准的结构构造一个请求,通过
XMLHttpReqeust.sendAsBinary
来以二进制流的形式上传,来实现后端服务器像普通模式一样获取内容.但是很遗憾,XMLHttpReqeust.sendAsBinary
这个方法是FireFox私有的方法,标准中没有,其他浏览器也并没有支持,所以经过测试能用后我果断放弃了这个方法.
o
需要了解的技术内容已经清晰了,下面就来看一下实现吧,我用伪代码+注释的形式来说明:
//获取缓存好的FileList对象 var allFiles = fileuploader.cache.files; //新建一个迭代游标用于控制当前同时上传的文件数目 var iterator = 0; //上传的主要方法 var upload = function(){ o//检查如果FileList对象的数目为0则直接退出 oif(allFiles.length == 0){ oreturn; o} o//如果FileList不为空,且当前的迭代游标小于5则执行上传 owhile(allFiles.length > 0 && iterator < 5){ o//弹出一个File ovar file = allFiles.shift(); o//游标加1 oiterator++; o//TODO:获取界面上的条目,并设置状态为开始上传 ovar perDom = fileuploader.uploadItems[file.guid]; o/*样式设置代码省略*/ o//新建XMLHttpRequest上传File文件,通过一个自执行的匿名函数将perDom传给异步请求,留作请求完成使用 o(function(perDom){ ovar req = new Request({ ourl: '/member/img-item/ajax-upload', odataType: 'json', omethod: 'post', osuccess: function(data){ o//检查数据的状态,并处理返回的数据 oif(data.status){ ofileuploader.addImages([data]); o//TODO:设置状态为成功 o/**样式设置代码省略**/ o}else{ o//TODO:设置状态为失败 o/**样式设置代码省略**/ o} o//游标减1表示上传完成 oiterator--; o//检查是否全部上传完毕 oif(allFiles.length == 0){ ofileuploader.close(); o} o//如果游标变为0则重新调用upload方法上传剩余的内容 oif(iterator == 0){ oupload(); o} o}, oprogress: function(e){ o//上传过程中计算上传的进度 ovar percent = parseInt(100 * e.loaded / e.total); operDom.progressBar.style.width = percent + '%'; o} o}); o//设置请求头信息,包括文件的名称大小类型唯一标识等等 oreq.setRequestHeader("DKUPLOADER_NAME", file.name); oreq.setRequestHeader("DKUPLOADER_SIZE", file.size); oreq.setRequestHeader("DKUPLOADER_TYPE", file.type); oreq.setRequestHeader("DKUPLOADER_GUID", file.guid); o//上传文件 oreq.send(file); o})(perDom) o} };
使用HTML5上传图片的内容到这里就结束了.怎么样很简单是不是.下面就继续说一下传统的方法上传的实现.
普通的基于iframe的无刷新文件上传系统已经是老生常谈的问题了,即将Form的target指向iframe,在执行submit的时候,页面不会刷新,只是iframe刷新.只要页面返回的内容中执行javascript调用父窗口的相关对象来更新状态即可.
当然本身这种方法是无法实现获取文件上传进度的,但是在php环境中,通过Alternative PHP Cache(APC)模块的扩展带来的小惊喜,可以获取文件上传的进度.前提是你需要独立安装这个扩展,而且需要你通过脚本定时查询后台来获取上传进度.这么做一是进度不够精确,另外增加服务器负担,除非是文件体积较大,否则实在是没有太大的必要这么做.至于其他的后台语言我没有深入研究,如果有哪位愿意分享还请多多指教.
这里实现选择多个文件是通过将<input type="file"/>
注册onchange
事件,待其选择文件后将其移动到另外一个隐藏容器中并将其缓存起来.而在原来上传按钮的位置重新创建一个新的input对象.这在点击选择文件按钮时会一直有上传选择窗口弹出,来实现伪装的多文件上传.
是实际上传的时候,<input type="file"/>
移动的策略跟第一种情况基本类似,只不过上传文件的方法由XMLHttpRequest改为Form的Submit方法.下面继续已代码说明:
var upload = function(){ o//获取所有缓存的input[type='file']对象 ovar allFiles = fileuploader.cache.files; o//如果数目为零则跳出 oif(allFiles.length <= 0){ fileuploader.close(); return; } //迭代游标 var iterator = 0; var uploadForm = fileuploader.dom.uploadForm; var uploadItems = fileuploader.uploadItems; //先清空form对象内部的内容 uploadForm.innerHTML = ''; //限定一次上传最多5个文件 while(allFiles.length > 0 && iterator < 5){ ovar file = allFiles.shift(); oiterator++; ovar perDom = uploadItems[file.guid]; o//修改状态为正在上传 operDom.status.className = 'message'; operDom.status.innerHTML = "正在上传"; operDom.thumb.innerHTML = '<img src="http://www.91meitu.net/resource/images/ajax_loader_s.gif" />'; o//将input[type='file']对象移动到待上传的表单内部 ouploadForm.appendChild(file); o} o//开始上传 ouploadForm.submit(); }
当然利用iframe跟使用HTML5上传还是有些区别的,因为使用Form提交的内容,通过javascript是无法直接获取上传的状态的,所以要被动等待iframe的内容返回后,通过调用方法来实现完成上传后的下一步操作.
我这里的图片上传控件是一个静态的对象,名字叫fileuploader,所以在iframe中调用的时候可以通过调用fileupload.complete方法来实现图片上传完成后的下一步操作.页面返回的内容是:
<script>window.parent.fileuploader.complete(" . json_encode($result) . ")</script>
而complete方法的具体内容如下:
var complete = function(){ ovar filesInfo = []; ofor(var i = 0, len = data.length; i < len; i++){ ovar imgData = data[i]; ovar perDom = fileuploader.uploadItems[imgData.guid]; oif(imgData.status){ ofilesInfo.push(imgData); o//TODO:设置状态为成功 o/**样式设置代码省略**/ o}else{ o//TODO:设置状态为失败 o/**样式设置代码省略**/ o} o} ofileuploader.addImages(filesInfo); o//继续上传剩余的文件 othis.iframeupload(); }
写到这基本上整个上传控件就写完了,当然还有一些open(),close()方法,一些自定义事件什么的都可以继续丰富和完善.抛砖引玉,欢迎不吝指教!
使用方法,在页面载入完毕后执行fileuploader.open();
文件中使用了我自己写的一个小工具包,打包成zip文件,欢迎大家下载源代码.
点击下载:fileuploader源代码
参考资料:
-
o
- Using files from web applications
- Using the DOM File API in chrome code
- File-Mozilla Developer Network
- File API-W3C
- XMLHttpRequest Level 2
o
o
o
o
转载请注明原文出处《渐进增强的无刷新多图片上传控件(iFrame+HTML5)》 如无特别声明,所有文章均遵守创作共用 署名-非商业-禁止演绎 3.0协议。
HTML5 Canvas和EaselJS入门(译)
HTML5中最受开发者期待的一项新特性莫过于Canvas(画布)元素了。Canvas元素提供了一个可以动态渲染图形和位图的位图画布。它非常类似于Flash中的Bitmap和BitmapData两个类。
但是,要使用Canvas还是有点难度的,特别是如果你还想管理,重绘或者运动图形或图片。与Flash播放器不同的是Canvas没有显示队列或显示个别项目这种概念,它提供一个用于绘图的画布,画什么以及什么时候画都取决于开发者。
Grant Skinner放出了一个名为EaselJS的JavaScript库,视图提供一个类似于Flash的DisplayList API用于简化Canvas的开发工作。虽然这个库目前还在内测阶段,但是却在早期就诶的就支持全部特性。如果你对Canvas感兴趣,那么这将是一个非常好的起点。
在这篇文章中,我将展示如何使用EaselJS来实现Canvas的动画效果。
下面是一个库中主要类的列表:
-
o
- DisplayObject:所有EaselJS中显示元素的抽象基类。包含所有显示元素的公用属性(例如:x,y,角度,x比例,y比例,透明度,阴影等等)。
- Stage:用以包含所有Canvas元素的容器根对象
- Container:可以包含一组对象的容器对象,可以让你把多个对象作为一个组来操作。
- Text:在显示列表的上下文中渲染文本
- Bitmap:按照显示的属性绘制一幅图,一个视频或者画布到画布上
- BitmapSequence:显示运动的或者动态的精灵板()并且提供管理回放和队列的APIs
- Graphics:提供一个简单却又强的绘制适量图形的API
- Shape:在显示列表上下文中通过Graphics Object渲染适量图
o
o
o
o
o
o
o
现在,在我们开始之前,让我们先看一下你在哪能够用到Canvas对象。Canvas是HTML5标准中的一部分,已经被大多数现代浏览器的最新版本所支持,包括:
Safari
Google Chrome
Opera
FireFox
(IE9业已支持 译者注)
但是,还有一个问题,并且这是个大问题。IE并没有支持Canvas对象(虽然下一个版本会支持)。根据NetMarketShare的数据,IE6,7,8占据了57%的浏览器市场,是用户最多的一部分。有个叫ExplorerCanvas的项目试图使IE支持Canvas,但是EaselJS为测试与它的兼容性。当你考虑用Canvas的时候请牢记这点。
现在我们有了一个是哦那个Canvas的好主意,先让我们看一个简单点例子。在示例中,我们将使用EaselJS动态的画一个圆并且移动它穿过画布。这个示例将会展示如何按照类库,介绍一下使用类库的一些基本概念,并且展示如何运动一个图形。
下面是例子
现在让我们看一下代码:
- <!DOCTYPE html>
- <html lang="en">
-
- <head>
- o<meta charset="utf-8" />
-
- o<meta name="author" content="Mike Chambers" />
- o<meta name="keywords" content="" />
- o<meta name="description" content="" />
- o<meta name="copyright" content="Mike Chambers" />
- o<meta name="robots" content="index,follow" />
-
-
- o<style>
- o#stageCanvas
- o{
- obackground-color:#333333;
- o}
- o</style>
-
- o<!-- 导入Easel库,下载地址 http://easeljs.com/
- o-->
-
- o<script>
-
- o//检查Canvas在当前浏览器是否支持
- o//http://diveintohtml5.org/detect.html#canvas
- oif(!(!!document.createElement("canvas").getContext))
- o{
- ovar wrapper = document.getElementById("canvasWrapper");
- owrapper.innerHTML = "Your browser does not appear to support " +
- o"the HTML5 Canvas element";
- oreturn;
- o}
-
- o//EaselJS Stage实例包含Canvas元素
- ovar stage;
-
- o//EaselJS Shape示例我们将做成动画
- ovar circle;
-
- o//圆的半径
- ovar CIRCLE_RADIUS = 10;
-
- o//x坐标,当圆离开屏幕的时候
- ovar circleXReset;
-
- o//EaselJS Rectangle(矩形)实例用于存储Canvas的边界值
- ovar bounds = new Rectangle();
-
- o//初始化函数
- ofunction init()
- o{
-
- o//通常这里我们会做一些Canvas的嗅探工作.
- o//浏览http://www.modernizr.com/有个用于HTML5嗅探非常有用的库
- o//获取Canvas对象的引用
- ovar canvas = document.getElementById("stageCanvas");
-
- o//复制画布绑定到边界实例
- o//注意,如果我们改变了画布的大小,我们需要同时改动这些边界
- obounds.w = canvas.width;
- obounds.h = canvas.height;
-
- o//pass the canvas element to the EaselJS Stage instance
- o//The Stage class abstracts away the Canvas element and
- o//is the root level display container for display elements.
- ostage = new Stage(canvas);
-
- o//创建一个EaselJS图形元素用来创建画圆的命令
- ovar g = new Graphics();
-
- o//1px的画笔
- og.setStrokeStyle(1);
-
- o//设置画笔颜色, 使用EaselJS
- o//Graphics.getRGB静态方法.
- o//创建了一个透明度为.7的白色
- og.beginStroke(Graphics.getRGB(255,255,255,.7));
-
- o//画这个圆
- og.drawCircle(0,0, CIRCLE_RADIUS);
-
- o//注意过圆现在并未真正的被画出来
- o//图形实例只是具有画圆的命令
- o//它在stage需要渲染的时候才被画出来
- o//通常在我们调用stage.tick()的时候
-
- o//创建一个新的图形实例. 这是一个可以添加到stage中并可以被渲染的显示对象
- o//Pass in the Graphics instance that we created, and that
- o//we want the Shape to draw.
- ocircle = new Shape(g);
-
- o//初始化x坐标,并初始化
- ocircle.x = circleXReset = -CIRCLE_RADIUS;
-
- o//设置y坐标
- ocircle.y = canvas.height / 2;
-
- o//将圆加入到舞台
- ostage.addChild(circle);
-
- o//让stage开始渲染
- ostage.tick();
-
- o//添加Tick类的订阅.这会每隔一段时间就调用tick方法
- o//(就像Flash中的ENTER_FRAME)
- oTick.addListener(this);
- o}
-
- o//每隔一定时间被Tick调用的函数
- ofunction tick()
- o{
- o//检查图像是否超出了stage的右边界
- oif(circle.x > bounds.w)
- o{
- o//如果有,则重置
- ocircle.x = circleXReset;
- o}
-
- o//将圆的x坐标移动10像素
- ocircle.x += 10;
-
- o//重新渲染stage
- ostage.tick();
- o}
- o</script>
-
- </head>
- <body onload="init()">
- o<div width="400" height="300" id="canvasWrapper">
- o<canvas width="400" height="300" id="stageCanvas"></canvas>
- o</div>
- </body>
- </html>
你可以点击这里下载本示例代码。
你可以看到,代码是相当的简单,并且它的结构也非常类似使用Flash中的DisplayList API。
有一些非常重要的地方需要指出。
EaselJS Stage示例包含Canvas元素,并且处理所有的内容什么时候如何渲染。只有当你调用stage.tick()的时候stage才渲染,并且为了效率方面的考虑,你仅需要在有内容发生更改或者需要重绘画布的时候再调用这个方法。
Tick类用于处理时间管理。当任何一个观察者对象被通知的时候它将调用一个tick方法。这与ActionScript中的ENTER_FRAME事件类似。
如果你改变了画布的大小,它的内容会被清空。然而,如果你使用EaselJS,唯一你需要做的就是在改变画布大小后调用stage.tick()方法,然后画布会重新渲染。
由于IE缺乏对Canvas的支持,你探测浏览器是否支持Canvas的工作变得非常重要,你最好给用户一个可以接受的回落。上面的示例代码中有简单的示范,同样你也可以使用Modernizr JavaScript Library这个库,这个库提供了检查浏览器对HTML5特性支持的API。
最后,当前版本是一个早期版本,因此APIs有可能发生改变。另外,有些你期望能用的内容可能尚未支持。例如,当前还没有能够获取一个显示对象高度或宽带的方法(你可能自己已经发现了)。然而不管怎么样,这个库还是非常健壮的,并且已经应用到一下产品级的项目中了。
下面是一些可能对你开始通过EaselJS使用Canvas有用的资源:
-
o
- EaselJS Homepage
- EaselJS API Docs
- Modernizr JavaScript Library (for detecting support for HTML5 features).
- Canvas Element Draft Specification
- Canvas Element (Wikipedia)
- Let’s call it a draw(ing surface) Good introduction to the low level Canvas API.
- HTML5 Browser Support Matrix
- HTML5 and CSS3 Readiness
- HTML5 Support in your Browser
o
o
o
o
o
o
o
o
转载请注明原文出处《HTML5 Canvas和EaselJS入门(译)》 如无特别声明,所有文章均遵守创作共用 署名-非商业-禁止演绎 3.0协议。