Experience Optimization for Front End of Publishing Box

  javascript

Through the front-end code, the File API is used to optimize the graphic publishing operation and improve the user experience.

图片描述
Publishing box is a common graphic publishing function of web applications, and is often used in products such as microblogs, reviews, forums, blogs or content management systems. Doing a good job in the interactive design of the publishing frame can improve the editing efficiency of users, improve the user experience, and add icing on the cake to the product.

Requirement background:

In actual projects, the following requirements are met. Users (operators) can publish topic-related content through the publishing box. The product manager expects to realize the following functions on this publishing box:
1. The user can drag the file and prompt the user to drag the file to the publishing box when the file enters the browser;
2. when the dragged file (e.g. exe) does not meet the requirements, a rejection prompt will be given and cannot be uploaded;
3. When dragging files (batch) into pictures or documents, analyze pictures and text, preview (or upload), and reject other types of files;

图片描述
4. The publishing box supports picture copying and pasting (or ctrl+v) after screenshots of QQ, PrintScreen and other tools.

图片描述

Technical points:

  1. Drag and drop function
  2. File API function
  3. Copy and paste event

drag & drop

Drag and drop is a common feature in HTML5. That is, drag and drop the captured object to another location (think about the transposition of the two elements). Related to him are two movements-dragging and releasing. Therefore, it involves two elements. One is the dragged element, called the drag-and-drop source. The other is the target to be put, called the drag-and-drop target. The events involved are of two types: drag (source) and drop (target).
Two events related to it (according to the sequence of triggering, the reference is the mouse pointer instead of the file edge):

Drag source:

  1. Dragstart: triggered when the mouse is pressed
  2. Drag: Triggered when the mouse is pressed continuously (executed multiple times)
  3. Dragend: Triggered when the mouse is released

Release target:

  1. Dragenter: Triggered when the target is dragged and the mouse enters the drop zone
  2. Dragover: Drag the target and the mouse movement will be triggered at the launch area (every 350 milliseconds)
  3. Dragleave: Triggered when dragging an object and leaving the drop zone
  4. Drop: Drag the object and trigger it when the mouse is released in the drop area (you need to set the default event of prohibition on dragover to trigger it, which is a strange setting)

Compatibility

Here we mainly use the drop event of the drop target, and its compatibility is shown in the following figure:
图片描述

Main code:

<textarea  rows="" cols="" id="myTextarea"></textarea>
<script type="text/javascript">
//<!  --
let myTextarea = document.getElementById('myTextarea');
document.addEventListener("dragenter", function(e) {
//When dragged items enter the page, they will be prompted by dotted lines.
e.preventDefault();
myTextarea.style.border = "#666 1px dashed";
}, false);
document.addEventListener("dragleave", function(e) {
//Drag the item off the page
e.preventDefault();
myTextarea.style.border = "none";
}, false);

myTextarea.addEventListener("dragover", function(e) {
//The dragged object moves
e.preventDefault();
}, false);

myTextarea.addEventListener('drop', function(e){
//Place the dragged object
e.preventDefault();
let upfile = e.dataTransfer.files;
console.log(upfile);
},false)
//-->
</script>

Encounter problems

The event trigger of dragenter(dragleave) is similar to mouseover(mouseout). When dragging inside drag outside the child node, it will trigger the DragEvent of the child node and bubble up, causing the DragEvent of the current node to be triggered several times. For example, we only bind the dragenter event to document, but any drag into or out of the subtab of the page will trigger the dragenter event of document again. Can be resolved by including and relatedTarget.

图片描述
Drag in both directions will trigger the dragenter event of the target node, which is not what we want!

//Judge whether two A's contain B or not
 function 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);

The event object has an attribute called relatedTarget, which is used to determine the attributes of the related nodes of the enter and leave event target nodes. Simply put, when the enter event is triggered, the relatedTarget property represents the node the mouse has just left, and when the leave event is triggered, it represents the object to which the mouse has moved. Because IE does not support this attribute, but it has substituted attributes, which are fromElement and toElement respectively.  node.contains () returns a Boolean value to indicate whether the passed-in node is a descendant node of the node. Using these two characteristics, this problem can be solved.

DataTransfer object

Any drag event will have a DataTransfer property in the event parameter, which has some common properties and methods:
1. DataTransfer.effectAllowed and dropEffect, which are used to set the type of mouse pointer to drag and drop, are not very useful. The specific effects can be viewed here.
2. DataTransfer.files, list of dragged local files. If the drag operation does not involve dragging a file, this property is an empty list.
3. DataTransfer.items, read-only, provides a DataTransferItemList object, which is a list of all dragged data and contains DataTransfer.files

Read file:

//picture check
checkFile(file){
const isJPG = /jpg|jpeg|png/.test(file.type.toLowerCase());
const isFile = /jpg|jpeg|png/.test(file.name.toLowerCase());
if (!  isJPG || !  isFile) {
Log ('only pictures of jpg and png can be uploaded.'  )
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!  isLt2M) {
Log ('picture size is not allowed to exceed 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'){
//Text file
let reader = new FileReader();
let that = this;
reader.onload = (function(file) {
return function(e) {
that.weiboContent += this.result;
};
})(el);
//Read Text Content
reader.readAsText(el, "gbk");
} else if(this.checkFile(el)) {
//Read Pictures
this.pic.push(el);
}
}
return false;
}

File operations:

The DataTransfer.Files object contains the file object we dragged. it is an array object and contains the following attributes:

  • Name: File name, which is read-only.
  • Size: file size, in bytes, this attribute is read-only.
  • Type: MIME type of the file. If the type cannot be distinguished, it is an empty string. This property is read-only.
  • LastModified: the last modified time of the file, in the form of a timestamp.
  • LastModifiedDate: the last modified time of the file, formatted as a Date object instance

We need the name, type and size attributes to check whether the format and size meet the requirements. HTML5 provides us with the FileReader API for reading files, that is, reading the contents of files into memory. Its parameters are File or Blob objects.

What is File

In front-end development, the most common file is the file uploaded by the form, which is a file object, while the FileList object is a collection list of these file objects, representing all the selected files. File object inherits from Blob object, which represents binary raw data, provides slice method (which can be used for file slicing) and can access raw data blocks inside bytes. In summary, the file object contains the FlieList object, while the file object inherits from the Blob object! Their relationship is as follows:
图片描述

FileReader provides different methods to read files for different types of files.

Readastxt (blob | file, opt _ encoding): returns a text string. By default, the text encoding format is UTF-8. You can specify text in other encoding formats through optional format parameters. In this way we can read the contents of the file.
ReadAsDataURL(Blob|File): Returns a Base64-encoded data-uri object. In this way we can preview the picture.

Picture local preview

We know that the src attribute of img or the url attribute of background can display the picture by being assigned to the picture network address or base64. In file upload, we usually upload the local file to the server first. After the upload is successful, the network address of the picture will be returned from the background and displayed at the front end. Through FileReader’s readAsDataURL method, we can directly display local pictures on the page without going through the background. This can reduce the frequent interaction between the front and back ends and reduce useless picture resources on the server end. The code is as follows:

let input  = document.getElementById("file");
 input.onchange = function(){
 let file = this.files[0];
 if(!  !  file){
 let reader = new FileReader();
 //Image file converted to base64
 reader.readAsDataURL(file);
 reader.onload = function(){
 //Show pictures
 document.getElementById("file_img").src = this.result;
 }
 }
 }

In addition, url object also provides a method to convert File type into URL (data URL).
Passing in a File object or Blob object can generate a link:

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

This URL can be placed anywhere where the URL can normally be placed, and this method can also be used for picture preview.

Copy and paste event

Sticking pictures in the release box can save users the trouble of saving and deleting screenshots. Copy, cut and paste are three types of events. We expect to get the picture in the clipboard. we can bind paste event to the element in the page. when the user mouse is over the element or the element is in focus state, right-click paste or ctrl+v operation will be triggered.
We need to solve the following problems when pasting pictures.
1. Monitor the user’s paste operation
2, acquiring data on the shearing plate
3, rendering the acquired data into a webpage

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

The clipboardData object is a DataTransfer type object, and DataTransfer is an object generated by dragging, but in fact the paste event is also it. The DataTransferItem of items has two attributes, kind and type. we can loop through the data on the sticker and then judge whether it is a file or a string by kind. if kind is a file, we can use the getAsFile method to get the file. The type attribute contains the data type of the concrete body, namely 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);
}
}
}

After getting the file file, you can do some column operations.

Summary

With the knowledge of drag-and-drop event API, DataTransfer object and FileList, etc., the effect of dragging and uploading pictures and texts and previewing can be realized. In fact, they can achieve more than these functions, such as drag sorting, large file fragment breakpoint upload, or combined with background processing Word documents and other operations. Due to the development of technology, these desktop functions can be implemented at the front end. We need to have a heart of exploration.

Author: TNFE Dapeng elder brother