H5文件与拖放API

文件API

FileList对象与file对象

FileList对象表示用户选择的文件列表。在HTML4中,file控件内只允许放置一个文件, 但是到了H5中,通过添加multiple属性,file控件内允许一次放置多个文件。控件内的每一个用户选择的文件都是一个file对象,而FileList对象则为这些file对象的列表,代表用户选择的所有文件。file对象有两个属性,name属性表示文件名, 不包括路径,lastModifiedDate属性表示文件的最后修改日期。

<script language=javascript>
function ShowFileName(){
    var file;
    //document.getElementById("file").files返回FileList文件列表对象
    for(var i=0;i<document.getElementById("file").files.length;i++){
       //file对象为用户选择的单个文件
        file = document.getElementById("file").files[i];
        //此处您可以针对FileList文件列表中每个文件进行多种处理,本例中只弹出文件名
        alert(file.name);
    }
}
</script>
选择文件:
<input type="file" id="file" multiple size="80"/>
<input type="button" onclick="ShowFileName();" value="文件上传"/>  

Blob对象

Blob表示二进制原始数据,它提供一个slice方法,可以通过该方法访问到字节内部的原始数据块。事实上,上面提到的file对象也继承了这个Blob对象.
Blob对象有两个属性,size属性表示一个Blob对象的字节长度。type属性表示Blob的MIME类型,如果是未知类型,则返回一个空字符串。

function ShowFileType(){
    var file;
    //得到用户选择的第一个文件 
    file = document.getElementById("file").files[0];
    var size=document.getElementById("size");
    //显示文件字节长度
    size.innerHTML=file.size;
    var type=document.getElementById("type");
    //显示文件类型
    type.innerHTML=file.type;
}
</script>
选择文件:
<input type="file" id="file" />
<input type="button" value="显示文件信息" onclick="ShowFileType();"/><br/>
文件字节长度:<span id="size"></span><br/>
文件类型:<span id="type"></span>

对于图像类型的文件,Blob对象的type属性都是以image/开头的,后跟图像类型,利用此特性我们可以在JS中判断用户选择的文件是否为图像文件,如果在批量上传时,只允许上传图像文件,可以利用该属性,如果用户选择的多个文件中有不是图像的文件时,可以弹出错误提示信息,并停止后面的文件上传,或者跳过这个文件,不将该文件上传。

function FileUpload(){
    var file;
    for(var i=0;i<document.getElementById("file").files.length;i++){
        file = document.getElementById("file").files[i];
        if(!/image\/\w+/.test(file.type)){
            alert(file.name+"不是图像文件!");
            break;            
        }
        else{
            //此处可加入文件上传的代码
            alert(file.name+"文件已上传");
        }
    }
}
</script>
选择文件:
<input type="file" id="file" multiple/>
<input type="button" value="文件上传" onclick="FileUpload();"/>

另外,H5中已经对file控件添加了accept属性,企图让file控件只能接受某种类型的文件,但是目前各主流浏览器对其的支持都只限于在打开文件选择窗口时,默认选择图像文件而己,如果选择其他类型文件,file控件也能正常接受。

<input type="file" id="file" accept="image/*" />

FileReader接口

FileReader接口主要用来把文件读入内存,并且读取文件中的数据。FileReader接口提供 了一个异步API ,使用该API可以在浏览器主线程中异步访问文件系统,读取文件中的数据。

//检测浏览器是否支持FileReader接口
if(typeof FileReader=='undefined'){
    alert("浏览器不支持FileReader接口")
}else{
    var reader=new FileReader();
}
FileReader接口的方法

FileReader接口拥有4个方法,其中3个用以读取文件,另一个用来将读取过程中断。无论读取成功或失败,方住并不会返回读取结果,这一结果存储在result属性中。

FileReader接口的方法

readAsText方法第二个参数是文本的编码方式,默认值为UTF-8。readAsBinaryString这个方法将文件读取为二进制字符串,通常我们将它传送到后端,后端可以通过这段字符串存储文件。readAsDataURL方法将文件读取为一串Data URL字符串,该方法事实上是将小文件以一种特殊格式的URL地址形式直接读入页面。这里的小文件通常是指图像与html等格式的文件。

FileReader接口的事件

FileReader接口还包含了一套完整的事件模型,用于捕获读取文件时的状态。

FileReader接口的事件

FileReader接口的使用示例
<script language=javascript>
var result=document.getElementById("result");
var file=document.getElementById("file");
if (typeof FileReader == 'undefined' ){
   result.innerHTML = "<p>抱歉,你的浏览器不支持 FileReader</p>";
   file.setAttribute( 'disabled','disabled' );
}
//将文件以Data URL形式进行读入页面
function readAsDataURL(){
    //检查是否为图像文件
    var file = document.getElementById("file").files[0];
    if(!/image\/\w+/.test(file.type)){
        alert("请确保文件为图像类型");
        return false;
    }    
    var reader = new FileReader();
    //将文件以Data URL形式进行读入页面
    reader.readAsDataURL(file);
    reader.onload = function(e){
       var result=document.getElementById("result");
       //在页面上显示文件
       result.innerHTML = '![]('+this.result+')'
    }
}
//将文件以二进制形式进行读入页面
function readAsBinaryString(){
    var file = document.getElementById("file").files[0];
    var reader = new FileReader();
    //将文件以二进制形式进行读入页面
    reader.readAsBinaryString(file);
    reader.onload = function(f){
        var result=document.getElementById("result");
        //在页面上显示二进制数据
        result.innerHTML=this.result;
    }
}
//将文件以文本形式进行读入页面
function readAsText(){
    var file = document.getElementById("file").files[0];
    var reader = new FileReader();
    //将文件以文本形式进行读入页面
    reader.readAsText(file);
    reader.onload = function(f){
        var result=document.getElementById("result");
        //在页面上显示读入文本
        result.innerHTML=this.result;
    }
}
</script>
<p>
    <label>请选择一个文件:</label>
    <input type="file" id="file" />
    <input type="button" value="读取图像" onclick="readAsDataURL()"/>
    <input type="button" value="读取二进制数据" onclick="readAsBinaryString()"/>
    <input type="button" value="读取文本文件" onclick="readAsText()"/>
</p> 
<div name="result" id="result">
      <!-- 这里用来显示读取结果 -->
</div>

在这个示例中,选取不同类型的文件,然后点击不同的按钮,浏览器会读取这些文件的各种数据,然后显示在画面中。当然您也可以选择不显示 ,而是直接提交到后端,然后保存到文件中或输送到数据库中。代码中fileReader对象读取到的数据都保存在了result属性中。

<script language=javascript>
var result=document.getElementById("result");
var input=document.getElementById("input");
if(typeof FileReader=='undefined'){
    result.innerHTML = "<p class='warn'>抱歉,你的浏览器不支持 FileReader</p>";
    input.setAttribute( 'disabled','disabled' );
} 
function readFile(){
    var file = document.getElementById("file").files[0];
    var reader = new FileReader();
    reader.onload = function(e){
        result.innerHTML = '![]('+this.result+')'
        alert("load");
    }
    reader.onprogress = function(e){
        alert("progress");
    }
    reader.onabort = function(e){
        alert("abort");
    }
    reader.onerror = function(e){
        alert("error");
    }
    reader.onloadstart = function(e){
        alert("loadstart");
    }
    reader.onloadend = function(e){
        alert("loadend");
    }
    reader.readAsDataURL(file);
}
</script> 
<p>
<label>请选择一个图像文件:</label>
<input type="file" id="file" />
<input type="button" value="显示图像" onclick="readFile()" />
</p> 
<div name="result" id="result">
<!-- 这里用来显示读取结果 -->
</div>

在这个示例中,我们通过点击显示图像按钮在画面中读入一个图像文件,通过这个过程我们可以了解按顺序触发了哪些事件,并用提示信息的形式报出这些事件的名字。我们需要编写的代码主要都是在onprogress事件中,譬如可以用H5中的新增元素progress来显示大文件的读取完成百分比。

拖放

拖放步骤

1.将想要拖放的对象元素的draggable属性设为true,这样才能将该元素进行拖放。另外,img元素与a元素(必须指定href)默认允许拖放。
2.编写与拖放有关的事件处理代码。

拖放的相关事件

示例:

<title>拖放示例</title>
<script type="text/javascript">
function init() {
    var source = document.getElementById("dragme");
    var dest = document.getElementById("text");
    // (1) 拖放开始
    source.addEventListener("dragstart", function(ev) {
        // 向dataTransfer对象追加数据
        var dt = ev.dataTransfer;
        dt.effectAllowed = 'all';    
       //(2) 拖动元素为dt.setData("text/plain", this.id); 
        dt.setData("text/plain", "你好"); 
    }, false);
    // (3) dragend:拖放结束
    dest.addEventListener("dragend", function(ev) {
        //不执行默认处理(拒绝被拖放)
        ev.preventDefault();
    }, false);
    // (4) drop:被拖放
    dest.addEventListener("drop", function(ev) {
        // 从DataTransfer对象那里取得数据
        var dt = ev.dataTransfer;
        var text = dt.getData("text/plain");
        dest.textContent += text;
        //(5) 不执行默认处理(拒绝被拖放)
        ev.preventDefault();
        //停止事件传播
        ev.stopPropagation();
    }, false);
}
//(6) 设置页面属性,不执行默认处理(拒绝被拖放)
document.ondragover = function(e){e.preventDefault();};
document.ondrop = function(e){e.preventDefault();};
</script>

<body onload="init()">
<h1>简单拖放示例</h1>
<!-- (7) 把draggable属性设为true -->
<div id="dragme" draggable="true" style="width: 200px; border: 1px solid gray;">
  请拖放
</div>
<div id="text" style="width: 200px; height: 200px; border: 1px solid gray;"></div>
</body>

代码解释:

  • 开始拖动(dragstart)时,把要拖动的数据存入DataTransfer对象(setData()方法)。DataTransfer对象专门用来存放拖放时要携带的数据,它可以被设置为拖动事件对象的dataTransfer属性。setData方法中的第一个参数为携带数据的数据种类的字符串,第二个参数为要携带的数据。第一个参数中表示数据种类的字符串里只能填入类似text/plaintext/html的表示MIME类型的文字,不能填入其它文字。
  • 如果把dt.setData("text/plain","你好");改为dt.setData("text/plain",this.id);,因为把被拖动元素的id当成了参数,所以携带的数据就是被拖动元素中的数据了,因为浏览器在使用getData方法读取数据时会自动读取该元素中的数据。
  • 针对拖放的目标元素,必须在dragenddragover事件内调用事件对象.preventDefault()方法。因为默认情况下,拖放的目标元素是不允许接收元素的,为了把元素拖放到其中,必须把默认处理关闭掉。
  • 目标元素接受到被拖放的元素后,执行getData()方能从DataTransfer那里获得数据。getData()方法的参数为setData()方法中指定的数据种类。
  • 要实现拖放过程,必须在目标元素的drop事件中关闭默认处理(拒绝被拖放),还必须设定整个页面为不执行默认处理(拒绝被拖放),否则目标元素不能接受被拖放的元素。
  • 要使元素可以被拖放,首先必须把该元素的draggable属性设为true。另外,为了让这个示例在所有支持拖放API的浏览器中都能正常运行,需要指定-webkit-user-drag:element这种Webkit特有的属性。
  • 因为这个示例中的数据种类使用了text/plain这个MIME类型,也可以从其他使用同样MIME类型的应用程序中把该类型的数据拖动到目标元素中。

支持拖动处理的MIME的类型为:

  • text/plain:文本文字
  • text/html:HTML文字
  • text/xml:XML文字
  • text/uri-list:URL列表,每个URL为一行

DataTransfer对象的属性与万法

如果DataTransfer对象的属性和方能使用得好,可以实现定制拖放图标,让它只支持特定拖放(如拷贝/移动) 等,甚至可以实现更复杂的拖放操作。

属性/方法 描述
dropEffect属性 表示拖放操作的视觉效果,允许对其进行值的设定。该效果必须在用effectAllowed属性指定的允许的视觉效果的范围内,允许指定的值为none、copy、link、move
effectAllowed属性 用来指定当前元素能被拖放时所允许的视觉效果。可以指定的值为none、copy、copyLink、copyMove、link、linkMove、move、all、unintialize
types属性 存入数据的种类,字符串的伪数组
void clearDaata(DOMString format)方法 消除DataTransfer对象中存放的数据。如果省略参数format,则消除全部数据
void setData(DOMString format、DOMString data) 向DataTransfer对象内存入数据
DOMString getData(DOMString format) 从DataTransfer对象中读数据
void setDragImage(Element image,long x,long y) 用img元素来设置拖放图标(部分浏览器可用canvas等其他元素)

setData方法在拖放开始时向dataTransfer对象中存入数据,它用types属性来指定数据的MIME类型。getData方法在拖动结束时读取dataTransfer对象中的数据。clearData方法可以用来清除DataTransfer对象内的数据。

设定拖放时的视觉效果

dropEffect属性与effectAllowed属性结合起来可以设定拖放时的视觉效果。effectAllowed属性表示当一个元素被拖动时所允许的视觉效果,一般在ondragstart事件中设定,允许设定的值为none、copy、copyLink、copyMove、link、linkMove、move、all、unintializedropEffect属性表示实际拖放时的视觉效果, 一般在ondragover事件中指定,允许设定的值为none、copy、link、movedropEffect属性所表示的实际视觉数果必须在effectAllowed属性所表示的允许的视觉效果范围内。规则如所示。

  • 如果effectAllowed属性设定为none,则不允许拖放元素
  • 如果dropEffect属性设定为none,则不允许被拖放到目标元素中
  • 如果effectAllowed属性设定为all或不设定,则dropEffect属性允许被设定为任何值,并且按指定的视觉效果进行显示
  • 如果effectAllowed属性设定为具体效果(不为none、all) ,dropEffect属性也设定了具体视觉效果,则两个具体效果值必须完全相等,否则不允许将被拖放元素拖放到目标元素中
source.addEventListener( "dragstart" , function(ev){
    var dt = ev.dataTransfer;
    //设定effectAllowed属性 
    dt.effectAllowed ='copy'; 
    dt.setData("text/plain","你好") ;
}, false);
dest.addEventListener( "dragover" , function (ev){
    var dt = ev.dataTransfer;
    //设定dropEffect属性
    dt.dropEffect ='copy'; 
    ev.preventDefault();
}, false);

自定义拖放图标

H5中允许自定义拖放图标——指的是在用鼠标拖动元素的过程中,位于鼠标指针下部的小图标。
DataTransfer对象有一个setDragImage方法,该方法有三个参数,第一个参数image设定为拖放图标的图标元素,第二个参数x为拖放图标离鼠标指针的x轴方向的位移量,第三个参数y为拖放图标离鼠标指针的y轴方向的位移量。

//创建图标元素
var dragIcon = document.createElement('img');
//设定图标来源
dragIcon.src = 'http://twivatar.orq/twitter/mini'; 
source.addEventListener("dragstart", function(ev) {
var dt = ev.dataTransfer;
//设定自定义图标 
dt.setDragImage(dragIcon, -10, -10); 
dt.setData("text/plain","aaa");
}, false);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容