博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
发布框前端体验优化
阅读量:6036 次
发布时间:2019-06-20

本文共 5692 字,大约阅读时间需要 18 分钟。

通过前端代码,利用File API对图文发布操作进行优化,提高用户体验。

图片描述

发布框是web应用的一种常见图文发布功能,在微博、评论、论坛、博客或内容管理系统等产品中经常使用。做好发布框的交互设计,能提高用户的编辑效率,提高用户体验,给产品增加锦上添花的效果。

需求背景:

在实际的项目中,遇到了以下需求,用户(运营人员)可以通过发布框发布话题相关内容,产品经理期望在此发布框上实现以下功能:

1、用户可以拖动文件,当文件进入浏览器时提示用户拖动文件到发布框;
2、当拖动的文件(例如.exe)不符合要求时,给予拒绝提示,不能上传;
3、当拖动文件(批量)为图片或文档时,解析图片和文字,预览(或上传),其余类型的文件拒绝;

图片描述

4、发布框支持图片复制、和QQ、PrintScreen键等工具的截图后粘贴(或ctrl+v)。

图片描述

技术点:

  1. 拖放功能(drag & drop)
  2. File API功能
  3. 复制粘贴事件

drag & drop

拖放是 HTML5 中常见的功能。即:把抓取的对象拖放到其他位置(想想一下两个元素换位)。与他相关就是两个动作——拖和放。所以,它涉及到两个元素。一个是被拖的元素,称为拖放源;另一个是要放的目标,称为拖放目标。所涉及到的事件就是两类:drag(源)和drop(目标)。

与它相关的两个事件(按触发的先后顺序,参照物是鼠标指针而非文件边缘):

拖拽源:

  1. dragstart:按下鼠标时触发
  2. drag:按下鼠标持续时触发 (执行多次)
  3. dragend:鼠标放开时触发

投放目标:

  1. dragenter:拖动目标且鼠标进入投放区时触发
  2. dragover:拖动目标且鼠标移动在投放区时触发(每隔 350 毫秒会触发一次)
  3. dragleave:拖动对象且离开投放区时触发
  4. drop:拖动对象且在投放区放开鼠标时触发(需要在dragover上设置禁止默认事件,才会有触发,奇怪的设定)

兼容性

这里我们主要用到了投放目标的drop事件,它的兼容性如下图所示:

图片描述

主要代码:

    

 遇到问题

dragenter(dragleave)的事件触发类似于mouseover(mouseout),当在子节点内外的拖动时,会触发子节点的drage事件并向上冒泡,引起多次触发当前节点的drag事件。举例来说,我们只在document上绑定dragenter事件,但是任何进出页面子标签的拖动,都会再次触发document的dragenter事件。可以通过是否包含和relatedTarget来解决。

图片描述

两种方向的拖动都会触发目标节点的dragenter事件,这不是我们想要的结果!

//判断两个a中是否包含bfunction contains(a,b){    return a.contains ? a != b && a.contains(b) :!!(a.compareDocumentPosition(b) & 16);}NodeB.addEventListener("dragenter", (e) => {    event.preventDefault();    let related = e.relatedTarget || e.fromElement;    if ((related != NodeB) && !NodeB.contains(related)) {        //do something    }}, false);NodeB.addEventListener("dragleave", (e) => {    e.preventDefault();    let related = e.relatedTarget || e.toElement;    if ((related != NodeB) && !NodeB.contains(related)) {        //do something    }}, false);

event对象有一个属性叫relatedTarget,这个属性就是用来判断enter和leave事件目标节点的相关节点的属性。简单的来说就是当触发enter事件时,relatedTarget属性代表的就是鼠标刚刚离开的那个节点,当触发leave事件时它代表的是鼠标移向的那个对象。由于IE不支持这个属性,不过它有代替的属性,分别是 fromElement和toElement, node.contains()返回的是一个布尔值,来表示传入的节点是否为该节点的后代节点。利用这两个特性,就可以解决这个问题。

DataTransfer对象

任何拖动事件,event参数中都会一个DataTransfer属性,它有一些常用属性和方法:

1、DataTransfer.effectAllowed和dropEffect,用来设置拖和放的鼠标指针类型,用处不大,具体效果可点击此处查看
2、DataTransfer.files,拖拽的本地文件列表。如果拖动操作不涉及拖动文件,则此属性为空列表。
3、DataTransfer.items,只读,提供DataTransferItemList对象,该对象是所有拖动数据的列表,包含DataTransfer.files。

读取文件:

// 图片校验  checkFile(file){    const isJPG = /jpg|jpeg|png/.test(file.type.toLowerCase());    const isFile = /jpg|jpeg|png/.test(file.name.toLowerCase());    if (!isJPG || !isFile) {    console.log('只可以上传jpg、png的图片。')    }    const isLt2M = file.size / 1024 / 1024 < 2;    if (!isLt2M) {    console.log('图片尺寸不允许超过2MB!')    }    return isJPG && isFile && isLt2M;  }let content:string, pic:[]textareaDropfn(e){    e.preventDefault();    let fileList = e.dataTransfer.files;    let contentText:string;    for (let i = 0; i < fileList.length; i++) {      const el = fileList[i];      if(el.type == 'text/plain' || el.type == 'text/html'){        // 文本文件        let reader = new FileReader();        let that = this;        reader.onload = (function(file) {          return function(e) {            that.weiboContent += this.result;          };        })(el);        //读取文本内容        reader.readAsText(el, "gbk");      } else if(this.checkFile(el)) {//读取图片        this.pic.push(el);      }    }    return false;  }

 文件操作:

DataTransfer.files对象包含了我们拖动的File对象,是个数组对象,包含以下属性:

  • name:文件名,该属性只读。
  • size:文件大小,单位为字节,该属性只读。
  • type:文件的 MIME 类型,如果分辨不出类型,则为空字符串,该属性只读。
  • lastModified:文件的上次修改时间,格式为时间戳。
  • lastModifiedDate:文件的上次修改时间,格式为 Date 对象实例

我们需要name、type、size属性来校验格式和大小是否满足要求。HTML5给我们提供了FileReader API 用于读取文件,即把文件内容读入内存。它的参数是 File 对象或 Blob 对象。

什么是File

在前端开发中,最常见的file就是表单上传的文件,它是一个file对象,而FileList对象则是这些file对象的集合列表,代表所选择的所有文件。file对象继承于Blob对象,该对象表示二进制原始数据,提供slice方法(可以用来文件分片),可以访问到字节内部的原始数据块。总之,file对象包含与FlieList对象,而file对象继承于Blob对象!他们的关系如下图:

图片描述

对于不同类型的文件,FileReader 提供不同的方法读取文件。

readAsText(Blob|File, opt_encoding):返回文本字符串。默认情况下,文本编码格式是 UTF-8,可以通过可选的格式参数,指定其他编码格式的文本。用此方法我们可以读取文件内容。

readAsDataURL(Blob|File):返回一个基于 Base64 编码的 data-uri 对象。用此方法我们可以做图片预览。

图片本地预览

我们知道,img的src属性或background的url属性,可以通过被赋值为图片网络地址或base64的方式显示图片。在文件上传中,我们一般会先将本地文件上传到服务器,上传成功后,由后台返回图片的网络地址再在前端显示。通过FileReader的readAsDataURL方法,我们可以不经过后台,直接将本地图片显示在页面上。这样做可以减少前后端频繁的交互过程,减少服务器端无用的图片资源,代码如下:

let input  = document.getElementById("file");input.onchange = function(){    let file = this.files[0];        if(!!file){            let reader = new FileReader();            // 图片文件转换为base64            reader.readAsDataURL(file);            reader.onload = function(){                // 显示图片                document.getElementById("file_img").src = this.result;        }    }}

还有,URL对象也提供了一个把File类型的文件,转化为url(数据URL)的方法。

传入一个 File 对象或者 Blob 对象,能生成一个链接:

let objecturl =  window.URL.createObjectURL(file|blob);

 这个 URL 可以放置于任何通常可以放置 URL 的地方,也可用此方法做图片预览。

复制粘贴事件

在发布框里支持粘贴图片,可省去用户截图保存、再删除的麻烦。copy、cut、paste这三个事件是一个类型的事件。我们期望获得剪贴板(clipboard)里面的图片,可以用给页面中的元素绑定paste事件的方法,当用户鼠标在该元素上或者该元素处于focus状态,右键粘贴或者ctrl+v的操作都会触发。

粘贴图片我们需要解决下面几个问题
1、监听用户的粘贴操作
2、获取到剪切板上的数据
3、将获取到的数据渲染到网页中

myTextarea.addEventListener("paste", function (e){   let items = e.clipboardData && e.clipboardData.items || [];});

 clipboardData对象是一个DataTransfer类型的对象,DataTransfer 是拖动产生的一个对象,但实际上粘贴事件也是它。items的DataTransferItem有两个属性kind和type,我们可以通过循环取出粘贴板上的数据,然后通过kind来判断是文件(file)还是字符串(string),如果kind是file,可以用getAsFile方法获取到文件。type属性则包含的是具体体的数据类型即MIME-Type。

textareaPaste(e){    let cbd = e.clipboardData;    for(let i = 0; i < cbd.items.length; i++) {      let item = cbd.items[i];      if(item.kind == "file"){        var blob = item.getAsFile();        if (blob.size === 0) {          return;        }        this.postImg(blob);      }    }  }

获取到file文件之后,就可以进行一些列操作了。

 小结

结合拖放事件API,DataTransfer对象和文件读取对象FileList等方面的知识,可以实现拖拽上传图文并预览效果。其实它们能实现的功能远不止这些,比如拖动排序、大文件分片断点上传,或者结合后台处理Word文档等操作。由于技术的发展,这些桌面上的功能,都可以在前端实现,我们需要有一个探索的心。

作者:TNFE 大鹏哥

转载地址:http://pilhx.baihongyu.com/

你可能感兴趣的文章
产品无间道——如何毁掉对手产品
查看>>
VS2010编译过程中遇到的一个问题
查看>>
SO_REUSEADDR例解
查看>>
VC连接MySQL
查看>>
android sensor 之手掌接近或远离
查看>>
关于DB2对其sql语句进行长度限制的设置语句
查看>>
JS压缩工具Closure Compiler 和 YUICompressor的对比
查看>>
免费建站系统上线后反响不错
查看>>
初涉OSGi
查看>>
ShareX 屏幕截图分享好工具
查看>>
unity中使用protobuffer作为网络通讯封包协议的实现和流程
查看>>
oracle 不走索引
查看>>
自动化运维工具Ansible详细部署
查看>>
vagrant打包要注意虚拟机的名称
查看>>
如何将PC上的Word文档分享到朋友圈
查看>>
【批处理】goto 用法举例
查看>>
PO BO VO DTO POJO DAO概念及其作用(附转换图)
查看>>
重定向跳转与请求转发跳转的区别
查看>>
有限状态机时代终结的10大理由
查看>>
solr 3.5安装 及分词器配置
查看>>