Vue Common Object Data Update and file Object Data Update

Recently, in order to make a multi-image upload component, the requirement is to upload multiple files in turn, and display the upload progress bar.

After the implementation of the logic part, there is a problem when updating the progress bar view: the dynamic calculation of production progress attributes will not be automatically updated.

The original code was written as follows:

let files = this.filePicker.files;
if(!files.length) {
    return;
}

let arr = [];
for(let i = 0, len = files.length; i < len; i++) {
    let item = files[i];
    // The initial progress of each file is 0.
    item.progress = '0';

    arr.push(obj);
}

this.fileArr = arr;

The file object is added directly to record the upload progress, and initialized to 0. Then the update progress is calculated in real time when uploading. But strangely, this program doesn't automatically update in the view. It doesn't move. It's always zero. Also N in the way, Best thinking is puzzled.

 

Later, in a fit of anger, I made a little demo to see where the problem actually appeared. I removed all the code I didn't want to shut down. I just kept the core code and used the simplest data to simulate it. The code is as follows:

// Array simulation files, Object simulation file object
let files = [];
for(let i = 0, len = 5; i < len; i++) {
    let obj = {name: 'name_' + 1};

    files.push(obj);
}

let arr = [];
for(let i = 0, len = files.length; i < len; i++) {
    files[i].progress = '0';
    arr.push(files[i]);
}

Here we just change the file object into an array to simulate, and the file object into a common object simulation.

The magic is that it automatically updates.

Since the file is later stored in an array, the only difference is on the file object! So I'm going to save the properties of file objects with ordinary objects and try again.

let files = this.filePicker.files;
if(!files.length) {
    return;
}


let arr = [];
for(let i = 0, len = files.length; i < len; i++) {
    let item = files[i];
    let obj = {};

    obj.name = item.name;
    obj.size = item.size;

    obj.progress = '0';

    arr.push(obj);
}

In this way, the view can be automatically updated, and it is the difference between file object and ordinary object.

 

What is the difference between them? Look at their type first.

console.log('files type', Object.prototype.toString.call(files));
// files type [object FileList]
console.log('arr   type', Object.prototype.toString.call(arr));
// arr   type [object Array]

console.log('item type', Object.prototype.toString.call (files[0]));
// item type [object File]
console.log('obj  type', Object.prototype.toString.call (obj));
// obj  type [object Object]

The original file is a FileList type, and the file is a File type. Ordinary obj is an Object type.

The data update of Vue is realized by using the getter setter function of Object.defineProperty. By default, Vue does not set getter setter for File object, so it will not update automatically with File object.

The solution is to use ordinary objects to save the information needed in the file object and then to construct the view data. Or you can set the setter of the File object manually, or you can update it automatically. The code is as follows:

<div id="app">
    <input type="text" id='a'>
    <span id='b'></span>

    <input type="file" id='file'>
    <button type="button" id='button'>Click Change file attribute</button>
</div>

<script>
    // Ordinary Object Settings setter
    var obj = {};
    Object.defineProperty(obj, 'hello', {
        set: function(newVal) {
            document.getElementById('a').value = newVal;
            document.getElementById('b').innerHTML = newVal;
        }
    });

    document.addEventListener('keyup', function(e){
        obj.hello = e.target.value;
    });

    // File Object Settings setter
    var fileInput = document.getElementById('file');
    var file;
    fileInput.addEventListener('change', function(e){
        file = fileInput.files[0];

        Object.defineProperty(file, 'progress', {
            set: function(newVal) {
                // document.getElementById('a').value = newVal;
                document.getElementById('b').innerHTML = newVal;
            }
        });
    });

    document.getElementById('button').addEventListener('click', function(){
        file.progress = 'hello file';
    });

</script>

Keywords: Javascript Vue Attribute

Added by harmor on Sat, 06 Jul 2019 01:41:47 +0300