vue中上传excel并在线(json)编辑

上传excel文件,通过xlsx将文件转为json,json文件通过codemirror(vue2版本)在线编辑,编辑后的文件替换第一次上传的文件

20230314_160827.gif

安装组件

1.安装xlsx
"xlsx": "^0.18.5"
2.安装vue-codemirror
"codemirror": "^5.46.0"
"vue-codemirror": "^4.0.6"

步骤流程

1.上传excel文件
2.excel文件通过xlxs组件转为json
3.json文件在线展示并编辑
4.将编辑后的json文件在生成file上传替换

部分代码

1、文件上传,使用element-ui上传组件
<el-upload
        class="upload-demo"
          drag
          :action="actionUrl"
          :on-success="handleSuccess"
          :before-upload="beforeUpload"
          :on-remove="handleRemove"
          :limit="1"
          :file-list="fileList"
          :on-preview="handlePreview"
          accept=".xls, .xlsx"
        >
          <i class="el-icon-upload"></i>
          <div class="el-upload__text">
            <em>点击</em> 或将文件拖拽到这里上传
          </div>
        </el-upload>
2、点击预览
handlePreview(row) {
      this.codeMirrorVisible = true;
      this.$nextTick(() => {
        this.$refs.codeMirror.url = row.url;  // 文件url
        this.$refs.codeMirror.fileName = row.name; // 文件name
        this.$refs.codeMirror.init(); 
      })
    },
3、弹框显示(在线编辑json组件)
// appendToBody属性可不写,解决两个dialog弹框叠加,详情查看element-ui文档
// 引用方式不写了,就import xxx 的,懂得都懂,code-mirror组件代码在下面
<code-mirror v-if="codeMirrorVisible" ref="codeMirror" :appendToBody="true" @changeFile="changeFile" />
// @changeFile回调修改fileList,就是将上传文件替换下
changeFile(data) {
      this.fileList = [{
        name: data.name, // 文件name,自行修改
        url: `${window.SITE_CONFIG["downloadURL"]}/${data.id}` // 文件url,自行修改
      }]
    },
4、在线编辑弹框(组件code-mirror代码)
<template>
  <el-dialog
    :visible.sync="visible"
    title="在线编辑"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    :append-to-body="appendToBody"
    width="800px"
  >
    <commonEditor :value="value" language="javescript" @input="change"></commonEditor>
    <template slot="footer">
      <el-button size="small" @click="visible = false">取消</el-button>
      <el-button type="primary" size="small" @click="dataFormSubmitHandle()">确认</el-button>
    </template>
  </el-dialog>
</template>

<script>
import Cookies from "js-cookie";  // 可以删除
import commonEditor from "@/components/common-editor.vue";
import * as XLSX from "xlsx/xlsx.mjs";
export default {
  props: ["appendToBody"],
  components: { commonEditor },
  data() {
    return {
      actionUrl: `${window.SITE_CONFIG["uploadURL"]}?token=${Cookies.get(
        "token"
      )}`, // 修改成个人接收file文件地址
      visible: false,
      url: "",
      fileName: "",
      value: "",
      changeInput: ""
    };
  },
  methods: {
    init() {
      this.visible = true;
      // 将在线文件转为json
      // this.url 就是上面2中的this.$refs.codeMirror.url = row.url;  // 文件url
      this.$http.get(this.url, { responseType: "arraybuffer" }).then(res => {
        const data = new Uint8Array(res.data);
        let workbook = XLSX.read(data, { type: "array" });
        let firstSheetName = workbook.SheetNames[0];
        let worksheet = workbook.Sheets[firstSheetName];
        this.value = XLSX.utils.sheet_to_json(worksheet);
      });
    },
    change(value) {
      this.changeInput = value;
    },
    // 点击确认,将修改后的json,转为blob,再转为file,(也可以直接导出file)
    dataFormSubmitHandle() {
      const ws = XLSX.utils.json_to_sheet(JSON.parse(this.changeInput));
      const wb = XLSX.utils.book_new();
      XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
      // const file = XLSX.writeFile(wb, this.fileName); // 直接浏览器导出excel文件
      // 将文件转为file重新上传
      const wbout = XLSX.write(wb, {
        bookType: "xlsx",
        bookSST: true,
        type: "array"
      });
      const blob = new Blob([wbout], {
        type: "application/octet-stream;charset=utf-8"
      });
      const file = new File([blob], this.fileName, { type: "xls/xlsx" });
      const fileParams = new FormData();
      fileParams.append("file", file);
      this.$http
        .post(this.actionUrl, fileParams, {
          headers: {
            "Content-Type": "multipart/form-data"
          }
        })
        .then(({ data: res }) => {
          if (res.code != 0) {
            return this.$message.er;
          }
          this.$emit("changeFile", res.data); // 替换文件
          this.visible = false;
        });
    }
  }
};
</script>

<style>
</style>
5、vue-codemirror(组件commonEditor代码)
<template>
  <div class="json-editor">
    <textarea ref="textarea" />
  </div>
</template>

<script>
import CodeMirror from "codemirror";
import "codemirror/addon/lint/lint.css";
import "codemirror/lib/codemirror.css";
import "codemirror/theme/panda-syntax.css";
import "codemirror/mode/javascript/javascript";
import "codemirror/addon/lint/json-lint";
// 折叠代码
import "codemirror/addon/fold/foldgutter.css";
import "codemirror/addon/fold/foldcode.js";
import "codemirror/addon/fold/foldgutter.js";
import "codemirror/addon/fold/brace-fold.js";
import "codemirror/addon/fold/xml-fold.js";
import "codemirror/addon/fold/indent-fold.js";
import "codemirror/addon/fold/markdown-fold.js";
import "codemirror/addon/fold/comment-fold.js";

export default {
  props: ["value"],
  data() {
    return {
      jsonEditor: null
    };
  },
  watch: {
    value(value) {
      const editor_value = this.jsonEditor.getValue();
      if (value !== editor_value) {
        this.jsonEditor.setValue(JSON.stringify(this.value, null, 2));
      }
    }
  },
  mounted() {
    this.jsonEditor = CodeMirror.fromTextArea(this.$refs.textarea, {
      lineNumbers: true,
      mode: "application/json",
      gutters: [
        "CodeMirror-lint-markers",
        "CodeMirror-linenumbers",
        "CodeMirror-foldgutter"
      ],
      theme: "panda-syntax",
      lint: true,
      foldGutter: {
        rangeFinder: new CodeMirror.fold.combine(
          CodeMirror.fold.indent,
          CodeMirror.fold.comment
        )
      }
    });

    this.jsonEditor.setValue(JSON.stringify(this.value, null, 2));
    this.jsonEditor.on("change", cm => {
      this.$emit("changed", cm.getValue());
      this.$emit('input', cm.getValue())
    });
  }
};
</script>

<style lang="scss" scoped>
.json-editor {
  max-height: 500px;
  overflow: auto;
  position: relative;
  ::v-deep.CodeMirror {
    height: auto;
    min-height: 180px;
  }
  ::v-deep.CodeMirror-scroll {
    min-height: 180px;
  }
  ::v-deep.cm-s-rubyblue span.cm-string {
    color: #f08047;
  }
}
</style>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容