关于elementt的upload图片上传标签的解读,上传视频。上传大文件切片——生成一个哈希值,Message的消息提示。

发布于:2022-12-13 ⋅ 阅读:(574) ⋅ 点赞:(0)
<el-upload 
    action="https://jsonplaceholder.typicode.com/posts/"
    提交图片的服务器地址
    :on-preview="handlePreview" 
    :on-remove="handleRemove" 
    :before-remove="beforeRemove" 
    以上是三个事件
	 multiple
	 这个意思是上传多张
    :limit="3" 
    限制最多上传几张
    :on-exceed="handleExceed" 
    :file-list="fileList"
    两个事件
    >
    
    <el-button size="small" type="primary">点击上传</el-button>
    <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>

这里暂且用的到的有:

头像图片上传

这样写就是一次传一个。

<el-upload action="" :on-change="changeHandle">
	<el-button size="small" type="primary">点击上传头像</el-button>
	<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>

在这里插入图片描述

属性 说明 类型
on-change 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用 function(file, fileList)

这个函数里的参数一就是我上传的一个头像文件file对象

changeHandle(response) {
    console.log(response);
}

在这里插入图片描述
可以看出对象的类型Wie:File。那么如何将file上传到服务器呢,
把File对象传到服务器

得到对象:里面的row对象。
changeHandle(response) {
	console.log(response);
	const formData = new FormData()
	formData.append('file', response.raw)
},

++++++++++++++++分割线解读++++++++++++++++++

const formData = new FormData();
给forData这种Map类型添加一个属性file::file.row。
formData.append('file', response.raw);

然后直接将表单对象传输上去:

let ret = await uploadAvatar(formData);
uploadAvatar:封装好的ajax,服务器去解析。

上传视频

nodejs搭建服务器,然后设置一个公共资源路径,请求数据返回一个路径

// 设置静态资源目录
app.use(express.static('./public'))//目录下面有视频
app.post("/msg",(req,res)=>{
    console.log("我post被访问了");
    res.send({
        code:Date.now(),
        data:"http://localhost:4000/niu.mp4"
    })
})

客户端
el-upload标签自带一个axaj。

<el-upload action="http://localhost:4000/msg" 
	:on-success="uploadSuccess"
	:show-file-list="false">
		<el-button size="small" type="primary">点击上传视频</el-button>
</el-upload>

在这里插入图片描述
:on-success事件:上传成功后返回其响应内容;

uploadSuccess(response){//参数就是一个响应体。
    console.log(response);
}

当选择一个视频上传完可以在控制台查看其返回响应,状态如何。
在这里插入图片描述
但是这种写法有好有坏。方便维护,不利于安全。

大文件上传——方案

那么遇到超大文件,或者比较大的文件的时候该怎么传:

<el-upload>有个on-change属性,上面就是说过,第一个参数就是传输的文件本身。

  • 对于文件较大的文件上传进行分片上传,把一个大文件,拆分成若干个小的文件,然后再上传。
  • 切成小的方案
      1. 指定大小,然后来切文件 大小固定,数量不定
      1. 指定数量,然后来切文件,数据固定,大小不定
  • 上传时,要有一个编号,这样在服务器端才能根据此编号完成文件的合并操作
  • 还需要根据文件的内容,生成一个根据内容来得到的一个唯一随机字符串,此字符串一定要和内容是关联,只要内容有变化,则随机字符串要有变化,如果内容没有变化,则字符串不变(hash字符串[hash值])
  • 如果你没有此hash值,这样有可能在上传过来中,如果有两个相同的文件,就会上传两次,不太好
  • 有hash值,在合并的时候,可以用此hash值,来当作合并后的文件名称

hash值_0.mp4
hash值_1.mp4
hash值_2.mp4
==> hash值.mp4 完整的文件

<el-upload action="http://localhost:4000/msg" 
:on-success="uploadSuccess"
:show-file-list="false"
:on-change="changeHandle">
	<el-button size="small" type="primary">点击上传视频</el-button>
</el-upload>

*******
methods:

得到切片的大小:
当前的索引值是多少:

changeHandle(file){
    if(!file) return
    console.log(file.raw.size);
    let partnum = 4;//切片数
    console.log(file.raw.size/partnum);//每一块的大小
    let currentIndex = 0;//当前的索引值是多少
}

生成一个哈希值

在线MD5生成https://www.sojson.com/md5/
在这里插入图片描述

安装一个插件包,给定内容生成一个哈希值(加密稳定)

安装
npm i -S spark-md5
导入
import SparkMd5 from "spark=md5" 
给定一个内容生成一个md5.

要把内容转成哈希值之前,先要把内容转为arrayBuffer对象。buffer二进制数据流。把得到的buffer数据流转为一个hash值。

const read = new FileReader();/* 一个类的实例对象 */
read.readAsArrayBuffer(file.raw);/* 将file.raw转为arraybuffer */
read.onload = evt=>console.log(evt.target.result);

封装成一个函数:(异步)

async changeHandle(file){
            if(!file) return
            console.log(file.raw.size);
            let partnum = 4;//切片数
            console.log(file.raw.size/partnum);//每一块的大小
            let currentIndex = 0;//当前的索引值是多少
            let result = await this.binary(file.raw,"arraybuffer");//生成arraybuffer数据流
            console.log(result);
        },
binary(fileobj,type='binary'){
    return new Promise((resolve,reject)=>{
        const read = new FileReader();
        if(type == 'binary'){
            read.readAsBinaryString(fileobj);//普通二进制数据流(照片啥的)
        }else{
            read.readAsArrayBuffer(fileobj);//arraybuffer类数据流(大文件,视频啥的)
        }
        read.onload = evt=>resolve(evt.target.result);//返回最终的生成结果
    })
},

在这里插入图片描述


把得到的buffer数据流计算出来一个hash值

根据文件内容得到一个hash字符串,当做切片的前缀。得到文件扩展名。

let spark = new SparkMd5.ArrayBuffer();
spark.append(result)//把buffer的结果以流的形式填充进去的
let hash = spark.end();//结束的话返回一个字符串
console.log("hash:",hash);
// 得到一个文件的拓展名
let extName = file.raw.name.split(".").pop();
console.log(extName);

在这里插入图片描述

切片存储:

// 存储切好的文件,数组
let partList = [];
for(let i=0;i<partnum;i++){
    let chunk = file.raw.slice(currentIndex,partSize);//文件切片
    partList.push({
        filename:`${hash}_${i}.${extName}`,
        chunk:chunk
    })
    currentIndex += partSize;
}
console.log(partList);

this.partList = partList;
this.hash = hash;

在这里插入图片描述

将生成的多个小文件,串行按序请求网络。

let requertList = [];//存储每一个异步请求方法
partList.forEach(({filename,chunk})=>{
    const requestFn = ()=>{
        return new Promise((resolve,reject)=>{
            setTimeout(() => {
                resolve(filename)
            }, 1000);
        })
    };
    requertList.push(requestFn);
})
/*串行执行方法,每一个每一个的执行*/
let index = 0;
const next =async ()=>{
    if(index>=requertList.length){
        console.log("传输完成");
        return;
    }
    let name = await requertList[index++]();
    console.log(name);
    next();
}
next();

通过表单对象,上传切片的文件。

partList.forEach(({filename,chunk})=>{
	const requestFn =async ()=>{
	const formData = new FormData();
		formData.append("filename",filename);
		formData.append("chunk",chunk);
		let msg = await post("http://10.9.46.247:4000/msg",formData);
		console.log("msg:",msg);
	};

	requertList.push(requestFn);
})

在这里插入图片描述


Message的消息提示

this.$message("上传失败");
this.$message.error("上传失败");
this.$message.success("上传成功");
<template>
    <el-container>
        <el-header>Header</el-header>
        <el-container>
            <el-aside width="200px">
                <Enmu />
            </el-aside>
            <el-container>
                <el-main>
                    <el-breadcrumb separator="/">
                        <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
                        <el-breadcrumb-item><a href="/">活动管理</a></el-breadcrumb-item>
                        <el-breadcrumb-item>活动列表</el-breadcrumb-item>
                        <el-breadcrumb-item>活动详情</el-breadcrumb-item>
                    </el-breadcrumb>
                    <el-input placeholder="请输入内容" clearable class="shuru">
                    </el-input>
                    <el-button type="primary">点击搜索</el-button>
                    <el-button type="success">添加信息</el-button>
                    <el-button type="danger">删除选中</el-button>
                    <el-divider></el-divider>


                    <el-form ref="form" :model="form" label-width="80px">
                        <el-form-item label="账号" prop="input">
                            <el-input v-model="form.input"  />
                        </el-form-item>

                        <el-form-item label="上传头像">
                            <el-upload action="" :on-change="changeHandle">
                                <el-button size="small" type="primary">点击上传头像</el-button>
                                <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
                            </el-upload>
                        </el-form-item>
                        <el-form-item label="上传视频">
                            <el-upload action="http://localhost:4000/msg" 
                            :on-success="uploadSuccess"
                            :show-file-list="false"
                            :on-change="changeHandle">
                                <el-button size="small" type="primary">点击上传视频</el-button>
                            </el-upload>
                            <el-divider></el-divider>
                            <video v-if="src" :src="src"  width="200px" height="300px"  controls poster="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp3.itc.cn%2Fq_70%2Fimages01%2F20210619%2Fa7afb11dcd09419a911da798e6aa8878.png&refer=http%3A%2F%2Fp3.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1666056532&t=3b092bbb7b19927dd0b2e1ee4e93463d"></video>
                        </el-form-item>
                        <el-button type="success" @click="submitForm('form')">点击上传</el-button>
                    </el-form>

                    <!-- <el-image style="width: 100px; height: 100px" :src="form.avatar"  fit="fill"></el-image> -->
                </el-main>
                <el-footer>Footer</el-footer>
            </el-container>
        </el-container>
    </el-container>

</template>

<script>
import Bn from "@/components/Btcm.vue"
import Enmu from "@/views/menu"
import SparkMd5 from 'spark-md5'
import {post} from "@/utils/http"
export default {
    name: "upload",
    components: {
        Bn, Enmu
    },
    data() {
        return {
            src:'',
            form: {
                input: '123'
            }
        };
    },
    methods: {
        // changeHandle(response) {
        //     // console.log(response);
        //     const formData = new FormData()
        //     formData.append('file', response.raw)
        // },
        submitForm(formName) {
            this.$refs[formName].validate((valid) => {
                if (valid) {
                    console.log(this.$refs[formName]);
                    console.log("aaaaa");
                    console.log(this.$refs[formName]._props.model.input);
                    // this.$refs[formName].resetFields()
                    // alert('submit!');
                } else {
                    console.log('error submit!!');
                    return false;
                }
            });
        },
        resetForm(formName) {
            
            this.$refs[formName].resetFields();
           
        },
        async changeHandle(file){
            if(!file) return
            console.log(file.raw.size);
            let partnum = 4;//切片数
            console.log(file.raw.size/partnum);//每一块的大小
            let partSize = file.raw.size/partnum;
            let currentIndex = 0;//当前的索引值是多少
            /* 获得一个哈希值 */

            // const read = new FileReader();/* 一个类的实例对象 */
            // read.readAsArrayBuffer(file.raw);/* 将file.raw转为arraybuffer */
            // read.onload = evt=>console.log(evt.target.result);/*异步过程,输出二进制数据流 */
            let result = await this.binary(file.raw,"arraybuffer");
            console.log(result);
            
            let spark = new SparkMd5.ArrayBuffer();
            spark.append(result)//把buffer的结果以流的形式填充进去的
            let hash = spark.end();//结束的话返回一个字符串
            console.log("hash:",hash);
            // 得到一个文件的拓展名
            let extName = file.raw.name.split(".").pop();
            console.log(extName);
            // 存储切好的文件,数组
            let partList = [];
            for(let i=0;i<partnum;i++){
                let chunk = file.raw.slice(currentIndex,partSize);//文件切片
                partList.push({
                    filename:`${hash}_${i}.${extName}`,
                    chunk:chunk
                })
                currentIndex += partSize;
            }
            console.log(partList);
            this.partList = partList;
            this.hash = hash;

            let requertList = [];

            partList.forEach(({filename,chunk})=>{
                const requestFn =async ()=>{
                    const formData = new FormData();
                    formData.append("filename",filename);
                    formData.append("chunk",chunk);
                    let msg = await post("http://10.9.46.247:4000/msg",formData);
                    console.log("msg:",msg);
                };
                requertList.push(requestFn);
            })
            let index = 0;
            const next =async ()=>{
                if(index>=requertList.length){
                    console.log("传输完成");
                    return;
                }
                let name = await requertList[index++]();
                console.log(name);
                next();
            }
            next();



        },
        binary(fileobj,type='binary'){
            return new Promise((resolve,reject)=>{
                const read = new FileReader();
                if(type == 'binary'){
                    read.readAsBinaryString(fileobj);//普通二进制数据流(照片啥的)
                }else{
                    read.readAsArrayBuffer(fileobj);//arraybuffer类数据流(大文件,视频啥的)
                }
                read.onload = evt=>resolve(evt.target.result);//返回最终的生成结果
            })
        },
        uploadSuccess(response){
            // console.log(response);
            this.src = response.data;
        },

        
    }

}
</script>
<style>

</style>
<style>
.el-header,
.el-footer {
    background-color: #B3C0D1;
    color: #333;
    text-align: center;
    line-height: 60px;
}

.el-aside {
    background-color: #D3DCE6;
    color: #333;
    text-align: center;
    line-height: 200px;
}

/* 
.el-main {
    background-color: #E9EEF3;
    color: #333;
    text-align: center;
    line-height: 160px;
} */

body>.el-container {
    margin-bottom: 40px;
}

.el-container.is-vertical {
    height: 730px;
}

.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
    line-height: 260px;
}

.el-container:nth-child(7) .el-aside {
    line-height: 320px;
}

.shuru {
    margin-top: 15px;
    width: 300px
}

.el-button {
    margin-left: 20px;
}
</style>

网站公告

今日签到

点亮在社区的每一天
去签到