We have more or less used a wide variety of rich text editors, which have a very convenient function, copy a picture and then paste into the text box, this picture is uploaded, then this convenient function is how to achieve it?
Principle Analysis
extract operation: Copy => paste => upload
In this operation, we need to do is: Listen to paste events => get clipboard content => send request upload
For the convenience of understanding the following, you need to understand a few things first:
- We can only upload the page map (right button on the page picture, then copy) and screenshots (screenshot tool cut pictures, eg:qq screenshots), can not paste upload system pictures (from the desktop, hard copy), they are completely different places.
- Screenshot tool section of the diagram and right click on the page to copy the diagram is somewhat different, so the processing is not the same.
- Aware of the Paste event: When a paste (right paste/ctrl+v) operation is performed, the action triggers the Clipboard event named ' Paste ', which is triggered before the data in the Clipboard is inserted into the target element. If the target element (the location of the cursor) is an editable element (eg: a div with the Contenteditable property set). TextArea not. , the paste action inserts the data from the Clipboard into the target element in the most appropriate format, and if the target element is not editable, the data is not inserted, but the paste event is still triggered. The data is read-only during pasting. This section is translated into w3.org_the-paste-action.
- Unfortunately, after testing, it was found that Chrome (the latest version), Firefox (current edition), Ie11 's implementation of the Paste event is not entirely in accordance with the requirements of the consortium, and there are differences (the paste standard of the consortium is therefore only a draft phase).
Test code and screenshots are as follows:
Chrome:
<textarea ></textarea>
<div contenteditable style= "width:100px;height:100px; border:1px solid" >
</div>
<script>
document.addeventlistener (' Paste ', function (event) {
Console.log (Event)
})
</script>
- Event has clipboarddata attribute, and Clipboarddata has Item property, Clipboarddata.item Element (object) has type and kind attribute;
- No matter where the paste, can trigger the paste event;
- In the DIV (no special declaration, this article div refers to the contenteditable attribute of the div) paste screenshots, do not display pictures. IMG.SRC is a base64 encoded string;
- In the div paste the webpage picture, directly displays the picture, IMG.SRC is the picture address.
Firefox
- Event has clipboarddata attribute, Clipboarddata has no item attribute;
- Only in the textarea or editable div (only paste to trigger the paste event;
- In the div paste screenshot, directly display the picture, IMG.SRC for the base64 encoded string;
- Paste the page image in the Div, showing the same as chrome.
IE11: (no screenshots, can be tested, other browsers empathy < ( ̄▽ ̄)/, because lazy ... )
- Event has no clipboarddata attribute;
- Only paste in editable div to trigger the paste event;
- In the div paste screenshot, directly display the picture, IMG.SRC for the base64 encoded string;
- Paste the page image in the Div, showing the same as chrome.
Listening to the Paste event, and knowing the presentation, the next step is how to get the data:
Chrome has a specific approach, using Clipboarddata.items, Getasfile (), New FileReader () The API can get the Base64 encoded string of the picture in the Clipboard in the Paste callback function (whether it is a screenshot pasted or a copy of the page image to paste), Ie11,firefox has no such API, but there is still a way to get, Because the data has been shown in the IMG SRC, for screenshots pasted, directly take the SRC attribute value of img (base64), for Web pages pasted, the address to the background, and then down under the address down, the existence of their own servers, and finally return the new address to the front end of the show on the OK. To maintain consistency and ease of management, unify replaces the img src attribute in all situations (screenshots, Web pages) with its own stored address. So you can get the following core code (the comments are full Oh ~ ~):
HTML display:
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 Clipboar
Ddata = (Event.clipboarddata | | event.originalEvent.clipboardData);
if (clipboarddata.items) {//for chrome var items = clipboarddata.items, Len = Items.length,
BLOB = null;
Ischrome = true; Items.length is more interesting, the preliminary judgment is based on the MIME type, there are several types of mime, length is a few (to be verified)//If you paste plain text, then len=1, if you paste the page picture, len=2, Items[0].type = ' text/ Plain ', Items[1].type = ' image/* '//If Use screenshot tool to paste picture, len=1, Items[0].type = ' image/png '//If paste plain text +html,len=2, item
S[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 default behavior that does not allow clipboard content to appear in Div event.preventdefault (); In the items to find pasted image, according to the above analysis, need to loop for (var i = 0; i < len; i++) {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.target.result is the BASE64 encoded string of the picture var base64_str = Event.targ Et.result//Can write the upload logic here directly upload the Base64 encoded string (you can try to pass in a Blob object to see if the background program can parse) uploadimgfrompaste (Base64_str, ' past
E ', ischrome);
} reader.readasdataurl (BLOB); The reason for the else {//for Firefox settimeout (function () {//Set settimeout is to ensure that the picture is inserted into the DIV first,After going to get value 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 ') {//If it is a screenshot then SRC_STR is Base6
4 If it is copied other webpage picture so src_str is this picture in someone else server's address 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 (Xhr.status = =) {var data = Json.par
SE (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);
}
A simple backstage reception logic with Express.js:
Router.post ('/', upload.array (), function (req, res, next) {//1. Gets the SRC_STR string from the client => determines whether the Base64 or normal address => gets the picture type suffix ( Jpg/png etc)//=> if it is base64 replace "prefix" ("data:image\/png;base64," etc)//2.base64 convert to the ordinary address of the buffer object down//3. Write to Hard disk (
The following can be stored in the database)//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,/)) {//Processing screenshot src_str for 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 {///handling non-Chrome Web page picture Src_str for picture 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 the entire content of this article, I hope to help you learn.