excel不经过后台实现解析和预览(vue)

数据流读取和数据解析方面通过xlsx组件

安装命令 npm install xlsx -S

它先将上传的excel变成流,然后再根据流进行下一步处理。这个流可以交给其他组件处理比如我用的预览组件是用了其他组件(@vue-office/excel)就是把这个流交给其它组件就实现预览了,

@vue-office/exce 预览组件 地址如下

复制代码
#docx文档预览组件
npm install @vue-office/docx vue-demi@0.14.6

#excel文档预览组件
npm install @vue-office/excel vue-demi@0.14.6

#pdf文档预览组件
npm install @vue-office/pdf vue-demi@0.14.6

如果是vue2.6版本或以下还需要额外安装 @vue/composition-api

复制代码
npm install @vue/composition-api
html 复制代码
<el-upload                
	class="upload-demo"                
	ref="upload"                
	action=""                
	:auto-upload="false"                
	:file-list="fileList"                
	:on-change="handleChange"                
	multiple                
	:show-file-list="false"                
>              

     <el-button type="text">点击上传{{ bankDialogIsShow }}</el-button>                         
</el-upload>
javascript 复制代码
// 上一个html 上传后调用这个,这个方法处理后会调用弹窗,把必要的参数传到弹窗页面去处理显示操作等内容		
handleChange(file,fileList){        
				this.fileList = [fileList[fileList.length - 1]]; // 只能上传一个Excel,重复上传会覆盖之前的        
				this.file = file.raw;        
				let reader = new FileReader()        
				let _this = this        
				reader.readAsArrayBuffer(this.file)        
				const that = this
				reader.onload = function () {      
					
					that.bankDialogIsShow = true     
					let buffer = reader.result            
					let bytes = new Uint8Array(buffer)            
					let length = bytes.byteLength            
					let binary = ''            
					for (let i = 0; i < length; i++) {                
						binary += String.fromCharCode(bytes[i])            
					}            
					let XLSX = require('xlsx')            
					let wb = XLSX.read(binary, {                
						type: 'binary'            
					})
					
					that.$refs.bankDialog.open(XLSX,wb,buffer)


				
				
					//这个里面的this,不是当前dom,上面有函数
				}
			},
javascript 复制代码
<template>
  <div>
    <el-dialog title="提示" :visible.sync="dialogVisible" :fullscreen="true" :before-close="handleClose">

      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="submist">确 定</el-button>
      </span>

    excel预览部分
       <div style="width: 100vw; height: 600px;">
        <vue-office-pdf
        :key="componentKey"
        v-if="officeV"
          :options="options"
          :src="pdfUrl"
          @rendered="renderedHandler"
          @error="errorHandler"
        />
      </div>
     
     操作部分
      <el-tabs type="border-card" v-model="activeName" v-if="isTableShow" @tab-click="handleClick"> 
        <el-tab-pane :label="name" v-for=" (name, key, index) in SheetNames" :key="key">

          <el-table style="width: 92vw;height: 200px; " :data="excelDataAllObj[name]" stripe>


            <el-table-column label="序号" width="50" align="center">

              <template slot-scope="scope">
                <template v-if="scope.$index == 0">

                </template>
                <template v-else>

                  {{ scope.row['id'] }}
                </template>
              </template>

            </el-table-column>



            <el-table-column label="帐号" width="150" align="center">

              <template slot-scope="scope">
                <template v-if="scope.$index == 0">
                  <el-select v-model="selColumn[name]['帐号']" placeholder="请选择">
                    <el-option v-for="item in optionsObj[name]" :key="item.value" :label="optionsObj[name][item]"
                      :value="optionsObj[name][item]">
                    </el-option>
                  </el-select>
                </template>
                <template v-else>

                  {{ scope.row[selColumn[name]['帐号']] }}
                </template>
              </template>

            </el-table-column>
            。。。。其他字段
            
          </el-table>
        </el-tab-pane>
      </el-tabs>



    </el-dialog>
  </div>
</template>




<script>
import { excelBankData } from "@/api/tab-bank";
import matchMap from "@/assets/matchMap.json"
import VueOfficePdf from "@vue-office/excel";
import '@vue-office/excel/lib/index.css'
import {
  Message
} from "element-ui";
export default {
  props: {
    // dialogVisible: {
    // 	type: Boolean,
    // 	default: false
    // }, //是否显示
    id: {
      type: String,
      default: ''
    }, //传递的id
  },
  data() {
    return {
      componentKey:0,
       // 预览组件的配置对象,设置xls: true才能预览展示xls类型,否则显示空白
      options:{
                xls: true,
//过滤器1
                beforeTransformData: (workbookData) => {
                  console.log('beforeTransformData ',workbookData)
                  return workbookData
                }, //底层通过exceljs获取excel文件内容,通过该钩子函数,可以对获取的excel文件内容进行修改,比如某个单元格的数据显示不正确,可以在此自行修改每个单元格的value值。
//过滤器2,我使用了这个 作用是只展示下面修改部分tab选择那个sheet,正常预览是导入有几个sheet就展示几个,这里有个问题是 arr.push(workbookData[this.activeName]) 改变赋值后 预览页面是不刷新的 需要handleClick(tab, event) {this.componentKey += 1;  }变换预览组件:ref,让它以为是新东西强制更新ui                
transformData: (workbookData) => {
                  console.log('transformData ',workbookData)
                  const arr = []
                  arr.push(workbookData[this.activeName])
                  return arr
                },
      },
      officeV:true,
      pdfUrl:'',
      matchMap:matchMap,
      testA: '',
      activeName: 0,
      isTableShow: false,
      dialogVisible: false,
      outTableData: [{}],
      outRelExcelMap: {},
      selColumn: {},
      outCnEnRel: {
        '帐号': 'account'
      },
      excelDataAll: [],
      excelDataAllObj: {},
      optionsObj: {},
      SheetNames: [],
      excelDatas: [],
      htmlExcel:''
    }
  },
  computed: {
    excelData() {

    }
  },
  methods: {
    handleClick(tab, event) {
        console.log(tab, event);
        // this.officeV = false
        // this.$nextTick(function(){
        //   this.officeV = true
        // })
       
        this.componentKey += 1;

      },
    findKeyByValue(obj, value) {
      const result = Object.entries(obj).find(([key, val]) => val === value);
      return result ? result[0] : null;
    },
//用于联想提示自动选择下拉框的
    findMatchKeyInJSON(excelColName){
      
      for(let subKey in matchMap){
     //   console.log(subKey,' matchMap ')
        if (matchMap.hasOwnProperty(subKey)) {
          const oneJSON = matchMap[subKey]
          
          const matchKey = oneJSON.find(e=> e==excelColName )
          if(matchKey){
            return subKey
          }
        }
      }
      return undefined
    },
    async submist() {
      //SheetNames
      //excelDataAllObj
      const tdata = this.excelDataAllObj
      const outCnEnRelTemp = this.outCnEnRel

      let outData = []
      for (let j = 0; j < this.SheetNames.length; j++) {
        const name = this.SheetNames[j]
        for (let i = 0; i < tdata[name].length; i++) {
          const excelOne = tdata[name][i]
          let outOne = {}
          for (let key in excelOne) {
            if (excelOne.hasOwnProperty(key)) {
              const outKeyCN = this.findKeyByValue(this.selColumn[name], key)
              if (outKeyCN) {
                const enKey = outCnEnRelTemp[outKeyCN]
                outOne[enKey] = excelOne[key]
              }
            }
          }
          outData.push(outOne)
        }
      }
      const respose = await excelBankData(outData)
      const { code, msg, data } = respose
      Message({
        message: data,
        type: msg,
      })



    },
    close() {
      this.optionsObj = {}
      this.excelDataAll = {}

    },
    getTableVal(keyName) {
      const t = scope.row[selColumn[keyName]]
      if (t) {
        return '笑话'
      }
      return "?"
    },
    handleClose(done) {
      this.$confirm('确认关闭?')
        .then(_ => {
          done();
        })
        .catch(_ => { });
    },
    open(XLSX, wb,buffer) {
      this.pdfUrl =  buffer
    //  console.log('弹窗参数 ' + JSON.stringify(wb))
      this.dialogVisible = true
      this.SheetNames = wb.SheetNames
      this.excelDatas = wb.Sheets
      for (let i = 0; i < wb.SheetNames.length; i++) {
        const sheetName = wb.SheetNames[i]

        this.$set(this.selColumn, sheetName, {})
        this.$set(this.optionsObj, sheetName, {})

        let excelData = {}
        excelData = XLSX.utils.sheet_to_json(wb.Sheets[sheetName])
        this.htmlExcel = XLSX.utils.sheet_to_json(wb.Sheets[sheetName])
        //  console.log('数据 '+i,wb.SheetNames[i],JSON.stringify(excelData))

        let outData = []
        let selOptions = []
        for (let i = 0; i < excelData.length; i++) {

          const obj = excelData[i]
          obj['id'] = i + ''
          let recordOne = {}
          outData.push(recordOne)
          let selOption = {}
          for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
              //  console.log(key, obj[key]);

              if (key) {
                const wantColName = this.findMatchKeyInJSON(key)
                if(wantColName){
                  this.$set(this.selColumn[sheetName], wantColName, key)
                }
              //  console.log('wantColName ',wantColName,' key ',key)

                this.optionsObj[sheetName][key] = key
              
              }
            }
          }
          //    
          // this.excelDataAll = [...excelData]
          // 固化i变量,防止地址内容变动影响对象键值对对应关系 huangjingnan 240825
          this.excelDataAllObj[sheetName] = excelData
      //    console.log(sheetName,' 弹窗中展示 excel上传数据 ', JSON.stringify(this.excelDataAllObj))
        }
      }
      this.isTableShow = true
    },
    renderedHandler() {
      console.log("渲染完成");
    },
    errorHandler() {
      console.log("渲染失败");
    }
  },
  components: {
    VueOfficePdf,
  }
};
</script>
<style scoped lang="scss">
/* 自定义滚动条样式 */
.el-table--scrollable-x .el-table__body-wrapper::-webkit-scrollbar {
  width: 10px;
  /* 设置滚动条的宽度 */
  height: 100px;
  /* 设置滚动条的高度 */
}

/* 自定义滚动条滑块样式 */
.el-table--scrollable-x .el-table__body-wrapper::-webkit-scrollbar-thumb {
  border-radius: 5px;
  /* 设置滑块的圆角 */
  background-color: rgba(144, 147, 153, 0.3);
  /* 设置滑块的背景颜色 */
}

/* 自定义滚动条轨道样式 */
.el-table--scrollable-x .el-table__body-wrapper::-webkit-scrollbar-track {
  background-color: #f0f2f5;
  /* 设置轨道的背景颜色 */
}
 
:deep .x-spreadsheet-bottombar{
  display: none;
}
</style>
相关推荐
轻口味1 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王2 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发2 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀2 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪3 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef4 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6415 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻5 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云5 小时前
npm淘宝镜像
前端·npm·node.js