jszip+codemirror+ FileSaver实现文件的解压、下载、读取以及文件内容展示

1,050 阅读1分钟

需求描述

读取zip文件生成目录树,并提供zip的下载,解压之后的单个文件的下载,复制,以及展示。

引入相关依赖

// css
// element
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
// codemirror
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.3/codemirror.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.3/theme/idea.css">

// element
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
// codemirror 
<script src="https://cdn.bootcdn.net/ajax/libs/codemirror/2.36.0/clike.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.3/codemirror.js"></script>
// jszip 
<script src="https://cdn.bootcdn.net/ajax/libs/jszip/3.5.0/jszip.js"></script>
// FileSaver 
<script src="https://cdn.bootcdn.net/ajax/libs/FileSaver.js/2014-11-29/FileSaver.js"></script>

zip解压

// 创建目录树
async createTreeData() {
    let newZip = new JSZip();
    // this.zipData 为zip的blob文件流
    const { files } = await newZip.loadAsync(this.zipData).catch(() => {
        throw Error(`Could not load the ZIP project.`)
    })
    this.newZipFiles = files
    this.findRoot({ files })
},
// 查找目录树 并生成目录树 目前是只生成二级目录 后面的目录都采用实时获取
findRoot(zip) {
    let that = this
    this.filesTree = []
    const dirKeys = Object.keys(zip.files)
    const  root = Array.from(new Set(dirKeys.map(v => v.split('/')[0])))[0]
    this.filesTree.push({
        isFolder: true,
        path: root,
        label: root,
        children: []
    })
    const zipFileKeys = dirKeys.sort((a, b) => a.split('/').length - b.split('/').length)
    zipFileKeys.map((key, index) => {
        const dirKeys = key.split('/')
        let prevPath = dirKeys[0] + '/' + dirKeys[1]
        const isExistDir = that.filesTree[0].children.filter(v => v.label === dirKeys[1])
        const children = {
            isFolder: dirKeys.length > 2,
            path: prevPath,
            label: dirKeys[1]
        }
        dirKeys.length > 2 && (children.children = [{label: null}])
        if (isExistDir.length === 0) {
            that.filesTree[0].children.push(children)
        } else {
            that.filesTree[0].children.concat(children)
        }
    })
    // 过滤出二级目录中可以展示的文件
    const defaultData = this.filesTree[0].children.filter(v => !v.isFolder)[0]
    if (defaultData) {
        this.currentFile = this.filesTree[0]
        this.defaultExpandedKeys = [this.filesTree[0].label, defaultData.label]
        // 获取默认展示的文件内容
        this.getFilesDetails(defaultData)
    }
}

获取zip压缩包解压之后的文件内容并交给codeMirror展示

// data为当前选中的目录树节点参数
getFilesDetails(data) {
  this.currentFile = data
  let that = this
  if (!data.isFolder) {
      // 这里的path是当前zip文件的绝对路径
      this.newZipFiles[data.path].async('string').then(content => {
          that.fileDetails = content
          if (that.editor) {
              that.editor.setValue(content)
          } else {
          	  // 声明codemirror实例 并将文件内容设置给codeMirror
              that.editor = CodeMirror.fromTextArea(this.$refs.textarea, {
                  mode: 'text/x-java',
                  lineNumbers: true,
                  lint: true,
                  lineWrapping: true,
                  tabSize: 2,
                  cursorHeight: 0.9,
                  // 替换主题这里需修改名称
                  theme: 'idea',
                  readOnly: true
              })
              this.editor.setSize('auto', '650px')
              that.editor.setValue(content)
          }
      })
  }
},

下载单个文件

//  newZipFiles 是zip文件解压之后得到的files;this.currentFile.path是当前选中的目录节点的文件绝对路径
this.newZipFiles[this.currentFile.path].async("blob").then(content => {
	  // content为文件blob文件流;this.currentFile.label为zip解压之后的文件名带格式后缀 
      saveAs(content, this.currentFile.label);
  })

复制文件

// 复制文件
copyFileContent() {
    if (this.currentFile.path) {
        this.newZipFiles[this.currentFile.path].async('string').then(content => {
            this.copy(content)
        })
    } else {
        this.errorNotify('提示','请点击选中需要复制的文件')
    }
},
copy (data) {
    let str = ''
    let save = function (e) {
        e.clipboardData.setData('text/plain', data)
        str = e.clipboardData.getData('Text')
        e.preventDefault() // 阻止默认行为
    }
    document.addEventListener('copy', save)
    document.execCommand('copy') // 使文档处于可编辑状态,否则无效
    document.removeEventListener('copy', save) // 移除复制时间避免影响正常的复制
    this.$message.success("复制成功")
    return str
},