应用简介:此文主要是描述如何在前端div中直接ctrl+v 粘贴图片,并上传到服务器,包括拖拽图片文件到div中
应用场景描述:用QQ或者其它切图软件截图,在指定的div中ctrl+v 粘贴并显示,点击上传按钮,图片上传到服务器。类似实现了此功能的网站有 知乎 强力建议博客园实现此功能,写博客时插入图片方便的多。
适用环境:本代码目前适用谷歌浏览器、火狐,其它浏览器需要稍微改良一下即可,问题不大。
开发环境:vs2015 mvc
不说废话了,开始吧:
1:首先创建HTML元素,我们要粘贴的图片就是显示在 id=pasteImg 的div里面,注意 需要设置div的 contenteditable="true" 属性才可以编辑哦。
<div id="pasteImg" style="400px;height:300px;border:dashed" contenteditable="true"></div> <button style="30px;height:20px;" id="btnGO">上传图片</button>
2:写js代码:绑定粘贴事件 上传图片服务器
window.onload = function () { function paste_img(e) { if (e.clipboardData && e.clipboardData.items) { var imageContent = e.clipboardData.getData('image/png'); ele = e.clipboardData.items for (var i = 0; i < ele.length; ++i) {
//粘贴图片 if (ele[i].kind == 'file' && ele[i].type.indexOf('image/') !== -1) { var blob = ele[i].getAsFile(); window.URL = window.URL || window.webkitURL; var blobUrl = window.URL.createObjectURL(blob); // 显示到div中,此时是显示的本地图片数据,并没有上传到服务器 var new_img = document.createElement('img'); new_img.setAttribute('src', blobUrl); new_img.setAttribute('blobdata', blob);
// 移动div光标到新元素后面 insertHtmlAtCaret(new_img);
// 直接上传,当然你也可以不在这上传,可以点击按钮在上传
uploadImg(blob); }
//粘贴文本 else if (ele[i].kind === "string" && ele[i].type.indexOf('text/plain') != -1) {
//粘贴文本回调函数
ele[i].getAsString(
function (str) { insertHtmlAtCaret(document.createTextNode(str));//插入文本到光标处 并移动光标到新位置 }) } else return; } } else { alert('不支持的浏览器'); } }
//绑定粘贴事件 document.getElementById('pasteImg').onpaste = function () { paste_img(event); return false; };
}
3:下面是insertHtmlAtCaret方法,主要实现在div移动光标的位置,用不上的直接跳过此步骤
//聊天内容框 插入文本或者其他元素后,移动置光标到最新处 function insertHtmlAtCaret(childElement) { var sel, range; if (window.getSelection) { // IE9 and non-IE sel = window.getSelection(); if (sel.getRangeAt && sel.rangeCount) { range = sel.getRangeAt(0); range.deleteContents(); var el = document.createElement("div"); el.appendChild(childElement); var frag = document.createDocumentFragment(), node, lastNode; while ((node = el.firstChild)) { lastNode = frag.appendChild(node); } range.insertNode(frag); if (lastNode) { range = range.cloneRange(); range.setStartAfter(lastNode); range.collapse(true); sel.removeAllRanges(); sel.addRange(range); } } } else if (document.selection && document.selection.type != "Control") { // IE < 9 //document.selection.createRange().pasteHTML(html); } }
4:采用XHR上传图片数据
var createStandardXHR = function () { try { return new window.XMLHttpRequest(); } catch (e) { return false; } }; var createActiveXHR = function () { try { return new window.ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { return false; } }; var xhr; function createXHR() { var temp = createStandardXHR() || createActiveXHR(); if (window.XDomainRequest === undefined) { return temp; } else { return new XDomainRequest(); } } //前端上传方法 function uploadImg(obj) { xhr = createXHR(); if (xhr) { xhr.onerror = err; xhr.ontimeout = timeo; xhr.onprogress = progres; xhr.onload = loadd; xhr.timeout = timeo; } else { alert("Failed to create"); } //发送的数据 var fd = new FormData(); fd.append("image", obj, "imgtest.png"); //使用ajax发送 xhr.open('POST', '/Home/uploadFun', true);//第二个参数是服务器处理action,各个语言提供方式不一样,我这是.net mvc 后台处理的,具体方法见步骤5 xhr.send(fd); } function err() { // alert("XDR onerror"); } function timeo() { // alert("XDR ontimeout"); } function loadd() { // alert("上传完成"); // alert("Got: " + xhr.responseText); } function progres() { //alert("XDR onprogress"); } function stopdata() { xhr.abort(); }
5:后台接收图片数据处理方法,本人采用 .net MVC后台,根据自己的语言不通采用对应的处理方式
public class HomeController : Controller { public ActionResult Index() { return View(); } [HttpPost] public ActionResult uploadFun() { if (Request.Files.Count > 0) { var file = Request.Files[0]; if (file != null && file.ContentLength > 0) { //验证文件格式 var extension = Path.GetExtension(file.FileName); //if (extension != ".xls" && extension != ".xlsx") //{ //}
//上传成功的图片URL var fileFullPath = Path.Combine(Request.MapPath("~/uploads"), DateTime.Now.ToString("yyyyMMddHHmmss") + Path.GetFileName(file.FileName)); file.SaveAs(fileFullPath); return Content("上传成功!url:"+fileFullPath , "text/plain");
}
}
returnnew JsonResult();
}
}
6:扩展一下,拖拽图片文件到div 直接发送
//以下是拖拽事件 document.addEventListener("dragenter", function (e) { e.stopPropagation(); e.preventDefault(); }, false); document.addEventListener("dragleave", function (e) { e.stopPropagation(); e.preventDefault(); }, false); document.addEventListener("dragover", function (e) { e.stopPropagation(); e.preventDefault(); }, false); document.addEventListener("drop", function (e) { e.stopPropagation(); e.preventDefault(); handleFiles(e.dataTransfer.files); }, false); //拖拽文件处理事件 handleFiles = function (files) { for (var i = 0; i < files.length; i++) { var file = files[i]; //如果拖住进来的是图片文件则显示 if (file.type.match(/image*/)) { $("#pasteImg").focus();
var blob =file;
window.URL = window.URL || window.webkitURL;
var blobUrl = window.URL.createObjectURL(blob); // 显示到div中,此时是显示的本地图片数据,并没有上传到服务器
var new_img = document.createElement('img');
new_img.setAttribute('src', blobUrl);
new_img.setAttribute('blobdata', blob);
// 移动div光标到新元素后面
insertHtmlAtCaret(new_img);
// 直接上传,当然你也可以不在这上传,可以点击按钮在上传
uploadImg(blob);
} else { continue; } } }
7:至此就实现了ctrl+v 粘贴图片并发送服务器,也具有拖拽图片文件 并发送服务器的功能
发散:可以做文件上传的东西
待解决:IE浏览器和火狐浏览器可以直接粘贴图片及文件,显示的是数据而不是blob格式而已
这是隔日再来写的,以下是火狐浏览器解决方法,已亲测,可行,只不过,火狐不要写粘贴事件,它已自带
document.getElementById('btnGO').onclick = function () { var img = $("#pasteImg").find('img').eq(0); var blob = dataURLtoBlob(img.attr('src')); //上传方法 uploadImg(blob); }; //**dataURL to blob** function dataURLtoBlob(dataurl) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); } //**blob to dataURL** function blobToDataURL(blob, callback) { var a = new FileReader(); a.onload = function (e) { callback(e.target.result); } a.readAsDataURL(blob); }