在vue中实现excel上传并显示数据

效果如下:

具体代码如下:

<template>

  <div class="app-container">

      <input

        ref="excel-upload-input"

        class="excel-upload-input"

        style="width: 300px;margin-left: 10px"

        type="file"

        accept=".xlsx, .xls"

        @change="handleClick"

      />

      <div class="drop" @drop="handleDrop" @dragover="handleDragover" @dragenter="handleDragover">

        批量导入:拖拽excel文件或者

        <el-button :loading="loading" style="margin-left:16px;" size="mini" type="primary" @click="handleUpload">

          浏览

        </el-button>

      </div>

    <el-table :data="excelData.results" border highlight-current-row style="width: 100%;margin-top:20px;">

      <el-table-column v-for="item of excelData.header" :key="item" :prop="item" :label="item"/>

    </el-table>

  </div>

</template>

<script>

import XLSX from 'xlsx'

export default {

  name: 'UploadExcel',

  data() {

    return {

      loading: false,

      excelData: {

        header: null,

        results: null

      }

    }

  },

  methods: {

    handleUpload() {

      this.$refs['excel-upload-input'].click()

    },

    handleClick(e) {

      const files = e.target.files

      const file = files[0]

      const before = this.beforeUpload(file)

      if (before) {

        this.upload(file)

      }

    },

    // 上传文件的条件验证

    beforeUpload(file) {

      if (!file) {

        return false

      }

      const isLt1M = file.size / 1024 / 1024 < 1

      if (isLt1M) {

        return true

      }

      this.$message({

        message: '请上传1M以内的文件',

        type: 'warning'

      })

      return false

    },

    // excel文件数据获取

    upload(file) {

      this.$refs['excel-upload-input'].value = null

      return new Promise((resolve, reject) => {

        const reader = new FileReader()

        reader.onload = e => {

          const data = e.target.result

          const workbook = XLSX.read(data, { type: 'array' })

          // 获取第一个sheet页名字

          const firstSheetName = workbook.SheetNames[0]

          // 获取指定名字的sheet页内容

          const worksheet = workbook.Sheets[firstSheetName]

          // 获取标头

          const header = this.getHeaderRow(worksheet)

          // 获取除标头外的数据

          const results = XLSX.utils.sheet_to_json(worksheet)

          // 标头和数据处理

          this.generateData({ header, results })

          resolve()

        }

        reader.readAsArrayBuffer(file)

      })

    },

    // 获取标头

    getHeaderRow(sheet) {

      const headers = []

      const range = XLSX.utils.decode_range(sheet['!ref'])

      let C

      const R = range.s.r

      /* start in the first row */

      for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */

        const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]

        /* find the cell in the first row */

        let hdr = 'UNKNOWN ' + C // <-- replace with your desired default

        if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)

        headers.push(hdr)

      }

      return headers

    },

    handleDrop(e) {

      e.stopPropagation()

      e.preventDefault()

      if (this.loading) return

      const files = e.dataTransfer.files

      if (files.length !== 1) {

        this.$message.error('仅支持上传一个文件!')

        return

      }

      const rawFile = files[0] // only use files[0]

      if (!this.isExcel(rawFile)) {

        this.$message.error('仅支持上传.xlsx, .xls, .csv格式的文件')

        return false

      }

      this.upload(rawFile)

      e.stopPropagation()

      e.preventDefault()

    },

    handleDragover(e) {

      e.stopPropagation()

      e.preventDefault()

      e.dataTransfer.dropEffect = 'copy'

    },

    // 标头和数据处理(可以在此方法中调用后端接口保存数据)

    generateData({ header, results }) {

      this.excelData.header = header

      this.excelData.results = results

    }

  }

}

</script>

<style scoped>

.excel-upload-input {

  display: none;

  z-index: -9999;

}

.drop {

  border: 2px dashed #bbb;

  width: 600px;

  height: 160px;

  line-height: 160px;

  margin: 0 auto;

  font-size: 24px;

  border-radius: 5px;

  text-align: center;

  color: #bbb;

  position: relative;

}

</style>