【前端】之MEMFS实现简单的文件管理器

MEMFS实现简单的文件管理器

使用的是ffmpeg里的fs模块
fs的api可以参考emscripten的文档

上界面

在这里插入图片描述

上代码

<template>
  <div>
    fs文件系统
    <button @click="readDir">读取文件夹</button>
    <input @change="changFile" type="file" id="uploader" placeholder="文件">
    <button @click="saveFile">保存</button>
    <div class="path">
      <button @click="handleRefresh">刷新</button>
      <button @click="handleUpper">返回上一层</button>
      路径:<input v-model="path" placeholder="文件路径" @keyup.enter="handleRefresh"/>
      新建文件夹:<input v-model="newDir" placeholder="新建文件夹"/><button @click="handleMkdir">新建</button>
      新建文件:<input v-model="newFile" placeholder="新建文件"/><button @click="handleMkfile">新建</button>
      <button @click="handleUpload">上传文件</button>
    </div>
    <div class="file-list">
      <div class="file" :class="{active:file.name === active}" v-for="(file,index) in fileList" :key="'file' + index" @click="handleClick(file)" @dblclick="handleDbClick(file)">
        <div class="preview">
        </div>
        <div class="name">{
   
   { file.name }}</div>
        <div class="size">{
   
   { file.size }}</div>
        <div class="type">{
   
   { file.type === fileTypeEnum.FILE?'文件':'文件夹' }}</div>
        <div class="created-date">{
   
   { file.createDate }}</div>
        <div class="action">
          <span @click.stop="rename(file)">重命名</span>|
          <span @click.stop="remove(file)">删除</span>|
          <span v-if="file.type === fileTypeEnum.FILE" @click="download(file)">下载</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
// 本身项目用了ffmpeg,所以这里使用的是ffmpeg里的FS模块
import { createFFmpeg , fetchFile } from '@ffmpeg/ffmpeg'
import dayjs from 'dayjs'
import { onMounted , ref } from 'vue'
let fs = ''
const fileTypeEnum = {
  FILE:'file',
  DIR:'dir'
}
const path = ref('/')
const newDir = ref('')
const file = ref({})
const newFile = ref('')
const fileList = ref([])
const active = ref('')
onMounted(async () => {
  let ffmpeg = createFFmpeg( {
    log: true
  })
  await ffmpeg.load();
  fs = ffmpeg.FS
  console.log("fs",fs)
  handleRefresh()
})
let tmpFile = ''
const changFile = (file) => {
  console.log("选择文件",file.target.files)
  tmpFile = file.target.files[0]
}
const saveFile = async () => {
  console.log("保存文件",tmpFile)
  fs( 'writeFile' , tmpFile.name , await fetchFile(tmpFile) );
  const data = fs( 'readFile' , tmpFile.name );
  console.log("文件数据",data)
  handleRefresh()
}

const readDir = (path) => {
  const list=fs('readdir',path)
  console.log("文件列表",list)
  // fileList.value = list
  const showList = []
  list.forEach(file => {
    if(file !== '.' && file !== '..'  ){
      const item = {
        name:file,
        type:'',
        size:"",
        createDate:''
      }
      // 获取文件属性
      const info=fs('stat',path + file)
      console.log("info",info)
      item.createDate = dayjs(info.ctime).format('YYYY-MM-DD HH:mm:ss')
      item.size = info.size
      // 判断文件类型
      const isFile=fs('isFile',info.mode + '')
      item.type = isFile?fileTypeEnum.FILE:fileTypeEnum.DIR
      showList.push(item)
    }
  })
  fileList.value = showList
}

const handleRefresh = () => {
  console.log("刷新")
  if(path.value[path.value.length-1] !== '/') {
    path.value += '/'
  }
  readDir(path.value)
}
const handleUpper = () => {
  console.log("返回上一层")
  const pathArr = path.value.split('/')
  if(path.value === '/') {
    console.log("根目录")
    return
  }
  pathArr.splice(pathArr.length-2,1)
  console.log(pathArr.length,pathArr)
  path.value = pathArr.join('/')
  setTimeout(() => {
    handleRefresh()
  },100)
}
const handleMkdir = () => {
  console.log("新建文件夹",newDir.value)
  const data=fs('mkdir',path.value + newDir.value)
  console.log("结果",data)
  handleRefresh()
}
const handleMkfile = () => {
  console.log("新建文件")
  const data=fs('writeFile',path.value+newFile.value,'')
  console.log("结果",data)
  handleRefresh()
}
const handleUpload = () => {
  console.log("上传文件")
  let input = document.createElement('input');
  input.type = 'file';
  input.onchange = e => {
    tmpFile = e.target.files[0];
    console.log("添加的文件",tmpFile)
    saveFile()
    setTimeout(() => {
      handleRefresh()
    },100)
  }
  input.click();

}
const handleClick = (file) => {
  console.log("单机",file)
  active.value = file.name
}
const handleDbClick = (file) => {
  console.log("双击",file)
  if(file.type === fileTypeEnum.DIR) {
    active.value = ''
    path.value =  path.value + file.name + '/'
    setTimeout(() => {
      handleRefresh()
    },100)
  }
  if(file.type === fileTypeEnum.FILE) {
    const data = fs( 'readFile' ,path.value + file );
    console.log("文件数据",data)
  }
}
const download = (file) => {
  console.log("下载",file)
  const data = fs( 'readFile' ,path.value + file.name );
  const blob = new Blob([data])
  console.log("文件数据",data)
  saveAs(blob,file.name)
}
const rename = (file) => {
  console.log("重命名",file)
  const name=prompt("请输入新文件名 :",file.name);
  console.log("新文件名",name)
  const data = fs( 'rename' ,path.value + file.name,path.value + name );
  console.log("重命名",data)
  setTimeout(() => {
    handleRefresh()
  },100)

}

const remove = (file) => {
  console.log("删除",file)
  if(file.type === fileTypeEnum.DIR) {
    const data = fs( 'rmdir' ,path.value + file.name );
    console.log("删除",data)
  }
  if(file.type === fileTypeEnum.FILE) {
    const data = fs( 'unlink' ,path.value + file.name );
    console.log("删除",data)
  }
  setTimeout(() => {
    handleRefresh()
  },100)
}
function saveAs(blob, filename) {
  if (window.navigator.msSaveOrOpenBlob) {
    navigator.msSaveBlob(blob, filename)
  } else {
    const link = document.createElement('a')
    const body = document.querySelector('body')

    link.href = window.URL.createObjectURL(blob)
    console.log('创建的文件名', filename)
    link.download = filename
    link.style.display = 'none'
    body.appendChild(link)
    link.click()
    body.removeChild(link)
    window.URL.revokeObjectURL(link.href)
  }
}

</script>


<style lang="less" scoped>
.file-list{
  height: 500px;
  overflow: auto;
  .file{
    display: flex;
    &:hover{
      background: #eee;
      transition: 0.2s;
    }
    &.active{
      background: #ddd;
    }
    .preview{
      width: 50px;
      text-align: center;
    }
    .name{
      flex: 1;
    }
    .size{
      width: 120px;
    }
    .type{
      width: 80px;
    }
    .created-date{
      width: 150px;
    }
    .action{
      width: 200px;
      >span{
        cursor: pointer;
      }
    }
  }
}


</style>


猜你喜欢

转载自blog.csdn.net/sky529063865/article/details/128332093
今日推荐