Scenario: The project needs to upload local files (pictures, videos, etc.)
html provided input Tags can upload files < input type="file" /> //This will generate a button on the page, click to upload the file //But it is generally not used in this way, because the native button is not beautiful
Add hideen attribute to the input tag, then the input tag will be hidden
<input type="file" hidden ref="file" @change="onFileChange" />
The change event is triggered when a local file is selected and confirmed, but it does not trigger every time. If the two selected files are the same, it will not trigger the second time. The solution is explained below.
There is such a scene, click to change the avatar, then you can trigger the hidden input box by clicking the button to change the avatar
//Click on the avatar onChangePhoto() { //Because the input box has been hidden, the click event of the original input is triggered by clicking on other boxes this.$refs.file.click(); },
When the local file is selected and press OK, the input change event will be triggered
//When does the @change event trigger? For example on the pc side: it is triggered after selecting a computer file and clicking OK onFileChange() { /* this.$refs.file.files[0] What is obtained is a complex object, which contains the size of the picture, the type of the picture, the current time console.log(1111, this.$refs.file.files[0]); */ /* Entering window.URL.createObjectURL will get a url path in http format */ this.img = window.URL.createObjectURL(this.$refs.file.files[0]); //Show popup this.userPhotoShow = true; //When the same file is selected for the second time, the @change function will not be triggered, we can make the value of this.$refs.file equal to empty this.$refs.file.value = ""; },
Prior to Gecko 1.9.2, through the input element, only one file could be selected at a time, which meant that the FileList object on the files property of the input element could contain only one file anyway. As of Gecko 1.9.2, if an input element has the multiple attribute, it can be used to select multiple files. When multiple files are selected, an array of fileList is returned
<!DOCTYPE HTML> <html> <head> </head> <body> <!-- multiple Properties allow user to select multiple files --> <input id="myfiles" multiple type="file"> </body> <script> var pullfiles=function(){ // love the query selector var fileInput = document.querySelector("#myfiles"); var files = fileInput.files; // Get the number of selected files var fl = files.length; var i = 0; while ( i < fl) { // localize file var in the loop var file = files[i]; alert(file.name); i++; } } // Set the change event handler document.querySelector("#myfiles").onchange=pullfiles; </script> </html>
Image upload example
Since uploading pictures will definitely involve picture cropping, you need to use the third-party library cropperjs, please refer to the specific usage method official documentation
first
npm install cropperjs
Set up photo boxes
img { display: block; /* This rule is very important, please don't ignore this */ max-width: 100%; }
Introduce corpper and its style in the corresponding component
import "cropperjs/dist/cropper.css"; import Cropper from "cropperjs";
Avatar cropping
Set the style of the crop box in the mounted function
mounted() { //Get the dom element node, const image = this.$refs.img; //cropper is the data in data initialized to null, newcropper returns the cropper object, a complex object this.cropper = new Cropper(image, { viewMode: 1, //Try mode, the clipping frame cannot exceed the picture dragMode: "move", //Move mode, move can move pictures aspectRatio: 1, //The ratio of the fixed cropping frame, usually a square, choose 1/1, abbreviated 1 autoCropArea: 1, //The size of the custom crop area, it should be a number between 0 and 1. Define the auto crop area size (percentage) cropBoxMovable: false, //Enable this option to move the crop box by dragging. cropBoxResizable: false, //Enables resizable crop box size background: false, //Do not enable the default background }); },
save update
After the cropping is completed, send the request and send the image to the server
If Content-Type is required to be application/json , data is a normal object {}
If Content-Type is required to be multipart/form-data , then data pass FormData Object
Looking at all data interfaces, you will find that most of them require Content-Type requirements to be application/json
Generally, only the data interface related to file upload requires Content-Type to be multipart/form-data
This time pass a FormData object
For server-based cropping, use: getData method, which gets the cropped area parameters. Requires back-end interface cooperation
If it is pure client-side image cropping, use: getCroppedCanvas method, which gets the cropped image object (similar to the file object obtained by the URL.createObjectURL method).
methods: { confirm() { // This time pass a FormData object //Pure client-side cropped file, use getCroppedCanvas() to get the cropped file object this.cropper.getCroppedCanvas().toBlob((blob) => { const formData = new FormData(); //Add a new property value to FormData. If the property value corresponding to FormData exists, it will not overwrite the original value, but add a new value. If the property does not exist, add a new property value. formData.append("photo", blob); this.updataPhoto(formData); }); }, async updataPhoto(formData) { this.$toast.loading({ duration: 0, // keep showing toast forbidClick: true, message: "Loading", }); try { const { data } = await updataUserPhoto(formData); //close popup this.$emit("close"); //success tips this.$toast.success("Successfully modified"); //update view this.$emit("updataPhoto", data.data.photo); } catch (error) { console.log(error); this.$toast.faile("Identity expired,Please try logging in again"); } }, },