<div id="app">
  <image-input v-model="imageData"/>
</div>

<script type="text/x-template" id="image-input">
  <div
    class="image-input"
    :style="{ 'background-image': `url(${imageData})` }"
    @click="chooseImage"
  >
    <span
      v-if="!imageData"
      class="placeholder"
    >
      Choose an Image
    </span>
    <input
      class="file-input"
      ref="fileInput"
      type="file"
      @input="onSelectFile"
    >
  </div>
</script>
.image-input
  display: block
  width: 200px
  height: 200px
  cursor: pointer
  background-size cover
  background-position center center

.placeholder
  background: #F0F0F0
  width: 100%
  height: 100%
  display: flex
  justify-content: center
  align-items: center
  color: #333
  font-size: 18px
  font-family Helvetica

.placeholder:hover
  background: #E0E0E0

.file-input
  display none
Vue.component('image-input', {
  template: '#image-input',
 
  data () {
    return {
      imageData: null
    }
  },

  methods: {
    chooseImage () {
      this.$refs.fileInput.click()
    },

    onSelectFile () {
      const input = this.$refs.fileInput
      const files = input.files
      if (files && files[0]) {
        const reader = new FileReader
        reader.onload = e => {
          this.imageData = e.target.result
        }
        reader.readAsDataURL(files[0])
        this.$emit('input', files[0])
      }
    }
  }
})

new Vue({
  el: '#app',
  data () {
    return {
      imageData: null
    }
  }
})

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js