Vue

by Trina Lu

HTML

<div id="app">
  <h1>
    File upload
  </h1>
  <file-input />
</div>

CSS

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

del {
  color: rgba(0, 0, 0, 0.3);
}

Vue

const FileInput = {
	template: `
  	<div class="file-input__wrapper">
      <input type="file" multiple @change="onFileInputChange" ref="fileInput" hidden>
      <button class="file-input__button" @click="triggerFileUpload">Upload file</button>
      <ul>
      	<li v-for="file in files" class="file-input__image">		
        	{{file.source.name}}
          <input v-model="file.alt" />
          <img v-if="file.image" :src="file.image" width="50" />
        </li>
      </ul>
  	</div>
  `,
  data() {
  	return {
    	files: []
    }
  },
  methods: {
  	triggerFileUpload() {
    	this.$refs.fileInput.click();
    },
  	onFileInputChange(e) {
      const nextFiles = Array.from(e.target.files).map(file => {
      	const data = {
        	source: file,
          image: '',
          alt: ''
        };
        
				 this.readFileImage(file)
          .then(image => data.image = image)
              
      	return data;
      });
      this.files = [...this.files, ...nextFiles];
    },
    readFileImage(file) {
    	return new Promise(resolve => {
      	const reader = new FileReader();
        reader.onload = function(e) {
        	resolve(e.target.result);
        };
        reader.readAsDataURL(file);
      });
    }
  }
}

const App = new Vue({
	el: '#app',
  components: {
  	FileInput
  }
})