This article mainly introduces how to implement ctrl + v Pasting and upload images in js, which is compatible with chrome, firefox, ie11, interested friends can refer to the various rich text editors we have used more or less. One of them is very convenient. Copy an image and paste it into the text box, this image is uploaded. How can this convenient function be implemented?
Principle Analysis
Extraction operation: Copy => paste => upload
In this operation, we need to listen to the paste event => get the content in the clipboard => send a request for upload
To facilitate understanding of the following, we need to clarify the following points:
- We can only upload a webpage image (right-click the image on the webpage and copy it) and (tool-cut image, eg: qq ), images uploaded to the system cannot be pasted (copied from the desktop or hard disk). They are completely different.
- The tool screenshot graph is different from the one copied by right-clicking on the webpage, so the processing method is different.
- Note the paste event: When you paste (right-click paste/ctrl + v), this action triggers the clipboard event named 'paste, this event is triggered before the data in the clipboard is inserted into the target element. If the target element (where the cursor is located) is an editable element (eg: p with the contenteditable attribute set. Textarea does not exist .), The paste operation inserts the data in the clipboard into the target element in the most appropriate format. If the target element cannot be edited, the data is not inserted, but the paste event is still triggered. Data is read-only during the paste process. This section is translated into w3.org _ the-paste-action.
- Unfortunately, after testing, we found that chrome (the latest version), firefox (the latest version), and ie11 do not fully implement paste events according to w3c, there are also differences (w3c paste standards are only in the draft phase ).
The test code is as follows:
Chrome:
《script》 document.addEventListener('paste', function (event) { console.log(event) })《script》
- The event has the clipboardData attribute and the clipboardData has the item attribute. The elements (objects) in the clipboardData. item have the type and kind attributes;
- The paste event can be triggered wherever it is pasted;
- When p (no special declaration is made, p in this Article refers to p with the contenteditable Attribute Set), paste it in without displaying the image. Img. src is a base64 encoded string;
- Paste the webpage image in p to directly display the image. img. src is the image address.
Firefox:
- Event has the clipboardData attribute, while clipboardData does not have the item attribute;
- The paste event is triggered only when it is pasted in textarea or editable p;
- Paste in p to directly display the image. img. src is a base64 encoded string;
- Paste webpage images in p, which is the same as chrome.
Ie11: (no, you can test it on your own. The same applies to other browsers <( ̄)/, because it is lazy ...)
- The event does not have the clipboardData attribute;
- The paste event is triggered only when you paste the edited p file;
- Paste in p to directly display the image. img. src is a base64 encoded string;
- Paste webpage images in p, which is the same as chrome.
I listened to the paste event and learned the form. Next I learned how to get the data:
Chrome has a specific method, using clipboardData. APIS such as items, getAsFile (), and new FileReader () can obtain the base64 encoded string of the image in the clipboard in the paste callback function (whether pasted or copied or pasted by webpage images ), ie11 and firefox do not have such an api, but there is still a way to obtain it, because the data is already in the src of img. For the pasted data, the src attribute value (base64) of img is taken directly ), if the webpage is pasted, The address will be sent to the backend. Then, the address will be down based on the address, the server will exist, and the new address will be returned to the front-end for display. In order to maintain consistency and facilitate management, the src attribute of img in all situations (and webpages) should be replaced with the address stored by itself. Therefore, you can get the following core code (the comments are complete ~~) :
Html display:
Document
Front-end js processing logic:
Document. addEventListener ('paste ', function (event) {console. log (event) var isChrome = false; if (event. clipboardData | event. originalEvent) {// not for ie11 some chrome versions use event. originalEvent var clipboardData = (event. clipboardData | event. originalEvent. clipboardData); if (clipboardData. items) {// for chrome var items = clipboardData. items, len = items. length, blob = null; isChrome = true; // Items. length is interesting. The preliminary judgment is based on the mime type, that is, there are several mime types, and the length is a few (to be verified) // If the plain text is pasted, then len = 1, if you paste a webpage image, len = 2, items [0]. type = 'text/plain ', items [1]. type = 'image/* '// If you paste an image using a tool, len = 1, items [0]. type = 'image/png '// If you paste plain text + HTML, len = 2, items [0]. type = 'text/plain ', items [1]. type = 'text/html '// console. log ('len: '+ len); // console. log (items [0]); // console. log (items [1]); // console. log ('items [0] kind: ', items [0 ]. Kind); // console. log ('items [0] MIME type: ', items [0]. type); // console. log ('items [1] kind: ', items [1]. kind); // console. log ('items [1] MIME type: ', items [1]. type); // block the default action to prevent the clipboard content from displaying the event in p. preventDefault (); // find the pasted image in items. According to the above analysis, the loop for (var I = 0; I <len; I ++) is required) {if (items [I]. type. indexOf ("image ")! =-1) {// console. log (items [I]); // console. log (typeof (items [I]); // getAsFile () This method is only living standard firefox ie11 does not support blob = items [I]. getAsFile () ;}} if (blob! = Null) {var reader = new FileReader (); reader. onload = function (event) {// event.tar get. result is the Base64 encoded string var base64_str = event.tar get. result // you can write the upload logic here to directly upload the base64 encoded string (you can try to pass in the blob Object to see if the background program can parse it) uploadImgFromPaste (base64_str, 'paste ', isChrome);} reader. readAsDataURL (blob) ;}} else {// for firefox setTimeout (function () {// set setTimeout to ensure that the image is first inserted into p, then obtain the value var imgList = EN en. T. querySelectorAll ('# tar_box img'), len = imgList. length, src_str = '', I; for (I = 0; I <len; I ++) {if (imgList [I]. className! = 'My _ img ') {// If yes, src_str is base64. If it is a copied webpage image, src_str is the address of the image on another server. src_str = imgList [I]. src ;}} uploadImgFromPaste (src_str, 'paste ', isChrome) ;}, 1) ;}} else {// for ie11 setTimeout (function () {var imgList = document. querySelectorAll ('# tar_box img'), len = imgList. length, src_str = '', I; for (I = 0; I <len; I ++) {if (imgList [I]. className! = 'My _ img ') {src_str = imgList [I]. src ;}} uploadImgFromPaste (src_str, 'paste ', isChrome) ;}, 1) ;}}) function uploadImgFromPaste (file, type, isChrome) {var formData = new FormData (); formData. append ('image', file); formData. append ('submission-type', type); var xhr = new XMLHttpRequest (); xhr. open ('post', '/upload_image_by_paste'); xhr. onload = function () {if (xhr. readyState = 4) {if (x Hr. status = 200) {var data = JSON. parse (xhr. responseText), tarBox = document. getElementById ('tar _ box'); if (isChrome) {var img = document. createElement ('img '); img. className = 'my _ img '; img. src = data. store_path; tarBox. appendChild (img);} else {var imgList = document. querySelectorAll ('# tar_box img'), len = imgList. length, I; for (I = 0; I <len; I ++) {if (imgList [I]. className! = 'My _ img ') {imgList [I]. className = 'my _ img '; imgList [I]. src = data. store_path ;}}} else {console. log (xhr. statusText) ;};}; xhr. onerror = function (e) {console. log (xhr. statusText);} xhr. send (formData );}
Simple background receiving logic built with express. js:
Router. post ('/', upload. array (), function (req, res, next) {// 1. get the src_str string sent from the client ==> determine whether it is base64 or a common address ==> get the image type suffix (jpg/png etc) // => if it is base64, replace "prefix" ("data: image \/png; base64," etc) // 2. convert base64 to the normal address of the buffer object and then go down first // 3. write to the hard disk (you can save the address to the database later) // 4. returns the picture address var src_str = req. body. image, timestamp = new Date (). getTime (); if (src_str.match (/^ data: image \/png; base64, | ^ data: image \/jpg; base64, | ^ data: image \/jpg; base64, | ^ data: image \/bmp; base64,/) {// process src_str as a base64 string var pic_suffix = src_str.split (';', 1) [0]. split ('/', 2) [1], base64 = src_str.replace (/^ data: image \/png; base64, | ^ data: image \/jpg; base64, | ^ data: image \/jpg; base64, | ^ data: image \/bmp; base64,/, ''), buf = new Buffer (base64, 'base64 '), store_path = 'public/images/test _ '+ timestamp + '. '+ pic_suffix; fs. writeFile (store_path, buf, function (err) {if (err) {throw err;} else {res. json ({'store _ path': store_path}) ;}});} else {// process non-chrome webpage images src_str as the image address var temp_array = src_str.split ('. '), pic_suffix = temp_array [temp_array.length-1], store_path = 'public/images/test _' + timestamp + '. '+ pic_suffix, wstream = fs. createWriteStream (store_path); request (src_str ). pipe (wstream); wstream. on ('finish ', function (err) {if (err) {throw err;} else {res. json ({"store_path": store_path });}});}});
Node environment required: Install node => npm intall => node app. js)
The above is all the content of this article, hoping to help you learn.