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>
相关推荐
i801314 分钟前
基于IntraWeb的数据表格的多选实现
前端
new Vue()1 小时前
vue.js 原生js app端实现图片旋转、放大、缩小、拖拽
前端·javascript·vue.js
麒麟而非淇淋1 小时前
Vue 技术进阶 day2 数据监视的原理、其他内置指令、自定义指令、生命周期、组件化、VueComponent构造函数
前端·javascript·vue.js
曹天骄1 小时前
使用 React useEffect 实现条件判断的最佳实践
前端·react.js·前端框架
想做一只快乐的修狗1 小时前
【React】react hooks的使用规则
前端·react.js·前端框架
BHDDGT1 小时前
react-问卷星项目(2)
前端·react.js·前端框架
Teln_小凯1 小时前
nodejs - puppeteer 无头浏览器截图 JAVA后端调用
java·前端·python
理想青年宁兴星1 小时前
vue中异步批量删除列表数据
前端·javascript·vue.js
可别是个可爱鬼1 小时前
黑马智数Day3
前端·javascript·html
xcLeigh2 小时前
HTML5实现唐朝服饰网站模板源码
前端·html·html5