前端上传预览文件以及下载,node后端存储文件以及返回前端文件流下载

上传文件
    
上传文件 multiple:接收多个文件上传

input自带的上传文件样式不好看,并且各个浏览器的默认样式不一致,我们需要修改

在外面添加一个盒子,然后将内部的 input 隐藏,修改外部盒子的样式就可以了,但是input隐藏后触发不了事件怎么办呢?这里我们可以使用模拟事件

img就是内部input元素,这样就可以触发选择文件的事件了。

 inputBox.addEventListener('click', function () {
            // 这里使用模拟事件
            let evt = document.createEvent('MouseEvents')
            // 初始化事件 三个参数分别为事件类型,是否冒泡,是否阻止默认事件 
            evt.initEvent('click', false, false)
            img.dispatchEvent(evt) //触发事件
        }, false)

接下来的功能是选择的文件预览

监听input选择的change事件,因为可能上传多个文件,这里循环处理,使用formdata上传文件,创建formdata实例,后面做判断,我这里只写了图片文件的预览,但是上传的话如果没有在input的属性中规定上传的文件类型,是什么文件都可以的。

在else中执行渲染操作,具体就是将图片转化为base64格式然后创建元素插入并渲染。

render.result就是拿到的base64字符串,这样的话文件的预览就实现了。

  img.addEventListener('change', function () {
            //this.files就是拿到的文件
            console.log(this.files)
            formdata = new FormData()
            for (var i = 0; i < this.files.length; i++) {
                if (this.files[i].type.includes('mp4')) {
                    formdata.append(`mp4${i}`, this.files[i]); //插入formdata
                    $span = $(`不支持该类型的预览`)
                    $(".imgbox").append($span);
                } else {
                    let render = new FileReader()// 创建读取文件类
                    render.readAsDataURL(this.files[i]);// 读取对应的文件
                    formdata.append(`img${i}`, this.files[i]); //插入formdata
                    render.onload = () => {
                        // 图片预览
                        $img = $(``)
                        $(".imgbox").append($img);
                    }
                }
            }
        })

上传

这里有两个实现,一个jquery还有一个axios,推荐使用axios,因为他将上传文件的操作独立出来了,可以更方便的实现进度条效果。

     $("#btn").click(function (e) {
            formdata.append('name', '1111')
            if (!$('#img')[0].value) {
                alert('上传的文件不能为空')
                return false
            }
            // axios实现
            axios({
                method: 'post',
                url: 'http://localhost:3000/users', //这里写node的接口
                data: formdata,
                headers: {
                     //这里必须要写请求头,不然node识别不了
                    'Content-Type': 'multipart/form-data'
                },
                onUploadProgress: function (progressEvent) {
                    console.log(progressEvent)
                    // 进度条
                    $(".speed").show()
                    let percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
                    $(".content").css("width", percentCompleted + "%")
                    if (percentCompleted == 100) {
                        setTimeout(() => {
                            $(".speed").hide()
                        }, 500)
                    }
                }
            }).then(res => {
                //成功后清空最上面声明的formdata
                formdata = new FormData()
            }).catch(err => {
                console.log(err)
            })
            // jquery实现
            // $.ajax({
            //     url: "http://localhost:3000/users/?age=1",
            //     type: "POST",
            //     data: formdata,
            //     processData: false, // 表示不需要对数据进行处理
            //     cache: false,// 不需要对数据进行缓存
            //     contentType: false,// 不需要设置请求头
            //     xhr: function () {
            //         var xhr = new XMLHttpRequest();
            //         //使用XMLHttpRequest.upload监听上传过程,注册progress事件,打印回调函数中的event事件
            //         xhr.upload.addEventListener('progress', function (e) {
            //             //loaded代表上传了多少total代表总数为多少
            //             var progressRate = (e.loaded / e.total) * 100 + '%';
            //             //进度条
            //             $('.speed').css('display', 'block');
            //             $('.content').css('width', progressRate);
            //             if (progressRate == '100%') {
            //                 setTimeout(() => {
            //                     $('.speed').css('display', 'none');
            //                 }, 500)
            //             }
            //         })
            //         return xhr
            //     },
            //     success: (res) => {
            //         // 清空上一次的文件(也就是新创建一个)
            //         formdata = new FormData()
            //         $('#img')[0].value = ''
            //         $(".imgbox").empty()
            //     },
            //     error: (err) => {
            //         console.log(err)
            //     }
            // })
        })

nodejs部分,这里主要是基于express,首先起服务就不说了

解决跨域,在App.js中添加,注意添加的位置

app.all('*', function (req, res, next) { //处理跨域
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", ' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
});

       node路由

这里我们需要安装一个模块formidable,使用yarn add formidable -s安装,npm安装也可以,推荐使用yarn,他会锁定当前项目依赖的版本,这样别人在下载依赖的时候就不会出现依赖版本问题。

下面可以实现基本的功能,也可以自己做判断分辨文件的类型啊,存储在不同的文件夹等等

// 解析带文件上传的表单需要
const formidable = require("formidable")

router.post('/', function (req, res, next) {
  console.log(req.body)
  var form = new formidable.IncomingForm()
  // console.log(path.resolve(__dirname, '../'))
  //path.resolve(__dirname, '../')代表当前目录的上一级__dirname表示当前的根目录
  form.uploadDir = `${path.resolve(__dirname, '../')}/public/images` // 上传目录
  form.keepExtensions = true //上传文件保持原来的扩展名
  form.parse(req, function (err, fields, files) {
    console.log(files) //上传的文件参数
    console.log(fields) //上传的除了文件以外的参数
    if (err) {
      res.send(err)
    }
    let response = {
      msg: `成功上传至${form.uploadDir}`
    }
    res.send(response)
  })
});

从服务端下载文件

服务端部分,这里我们读取文件后直接返回文件的blob编码,我们在前端响应的时候将相应类型设置为buffer就可以接收到了,我这里还判断了前端需要下载什么类型的文件,目前是有视频和图片。

router.get('/download', async function (req, res, next) {
  let { type } = req.query
  let video = []
  let images = []
  let file = ''
  const filesName = fs.readdirSync(path.resolve(__dirname, '../public/images'))
  function filelist() {//读取文件列表
    filesName.forEach(item => {
      if (item.includes('mp4')) {
        video.push(item)
      } else {
        images.push(item)
      }
    })
  }
  filelist()
  function read(url) { //读取文件
    filelist()
    return new Promise((resolve, rejects) => {
      //fs读取文件如果不添加第二个参数data是buffer类型的数据,如果添加的话就是字符串
      fs.readFile(`${path.resolve(__dirname, '../')}/public/images/${url}`, function (err, data) {
        resolve(data)
        rejects(err)
      })
    })
  }
  if (type === 'mp4') {
    if (video.length === 0) {
      res.send({
        msg: '视频不存在',
      })
    } else {
      file = video[0]
      let data = await read(file)
        //如果要前端下载的话这个响应头必须设置
      res.setHeader('Content-Type', 'application/octet-stream')
      res.send(data)
    }
  } else {
    if (images.length === 0) {
      res.send({
        msg: '图片不存在',
      })
    } else {
      file = images[0]
      let data = await read(file)
 //如果要前端下载的话这个响应头必须设置
      res.setHeader('Content-Type', 'application/octet-stream')
      res.send(data)
    }
  }
});

前端

  function download(type) {
            axios.get(`http://localhost:3000/users/download?type=${type}`, {
                responseType: 'blob',
                // responseType: 'arraybuffer' //这两种格式都可以,都是二进制流,但是如果使用这个,就不能判断type值了
            }).then(res => {
                console.log(res)
                if (res.data.type.includes('application/json')) {
                    // blob转json
                    var reader = new FileReader();
                    reader.readAsText(res.data,'utf-8');
                    reader.onload = function (event) {
                        content = JSON.parse(reader.result);
                        alert(content.msg)
                    };
                } else {
                    let url = window.URL.createObjectURL(new Blob([res.data]))
                    let link = document.createElement('a')
                    link.style.display = 'none'
                    link.href = url
                    link.setAttribute('download', '资源.' + type)
                    document.body.appendChild(link)
                    link.click()
                    document.body.removeChild(link) //下载完成移除元素
                    window.URL.revokeObjectURL(url) //释放掉blob对象
                }
            })
        }

你可能感兴趣的:(前端,javascript,node.js,html)