zhh10 / Notes

前端中react、Vue、ES6、css3、webpack、模块化等思维导图
12 stars 1 forks source link

JS文件处理 #32

Open zhh10 opened 4 years ago

zhh10 commented 4 years ago
<input type="file" accept="image/*" multipie id="uploadInp"/>
<img src="" id="abbreImg"></img>

input标签

FileReader 文件读取类(异步操作)

let uploadInp = document.getElementById('uploadInp')
let abbreImg = document.getElementById('abbreImg')
uploadInp.onchange = function(){
    console.log(this.files) // 拿到一个FileList文件集合 【类数组集合】
    // 每一项就是一个文件
    let file = files[0] // 如果只上传一个文件
    if(file) return ;
    if(file.size > 1024){
        alert('上传的文件必须在1kb以内')
        return ;
    } 
    if(!/(jpg|jpeg|gif|png)/i.test(file)/){
        alert('必须上传png|jpg|gif图片!')
        return ;
    }
    // FileReader 文件读取类  (异步读取)
    let reader = new FileReader
    // 读取出一个base64的值 
    reader.readAsDataURL(file) 
    reader.onload = function(ev){
        // ev.target.result 
        abbreImg.src = ev.target.result
    }
    // 读取出一个Buffer的值
    // reader.readAsArrayBuffer(file)

}
let uploadBox = document.querySelector('.uploadBox'),
uploadInp = uploadBox.querySelector('.uploadInp'),
submit = uploadBox.querySelector('.submit'),
detail = uploadBox.quyerySeletor('.detail'),
detailText = uploadBox.querySelector('span'),

// axios post请求的封装
function postRequest(url,data,config){
    config = config || {};
    return axios.post(`http:....${url}`,data,config).then(res => return res.data)
}

// 文件读取
function fileReader(file){
    return new Promise((resolve,reject)=>{
        let reader = new FileReader() 
        reader.readAsDataURL(file)
        reader.onload = ev => {
            resolve(ev.target.result)
        }
    })
}
// 点击按钮调出窗口
submit.onclick = function(){
    let self = this 
    if(self.className.includes('disable')) return ;
    uploadInp.click()
}

// 选取图片后
uploadInp.onchange = function(){
    let self = this,
    file = self.files[0];
    if(!file) return ;
    detailText.innerText = file.name 
    detail.style.display = 'block'
    submit.className = 'submit disable'

    // 把选择的文件上传到服务器端
    // 1. 基于form-data
    let formData = new FormData() 
    formData.append('file',file)
    formData.append('filename',file.name)
    let res = await postRequest('/singal1',formData,{
        headers:{
            'Content-Type':"multipart/form-data",
            ""
        }
    })
    if(res.code === 0){
        // 成功了
        abbreImg.src = res.path
        detail.style.display = 'none'
        attre.style.display = 'block'
        submit.className = 'submit'
    }

    // 2. 把选择的文件base64传递给服务器
    let base64 = await fileReader(file);
    let data = {
        chunk:base64,
        filename:file.name,
    }
    let res = await postRequest('/signal2',Qs.stringify(data),{
        headers:{
            'Content-Type':"application/x-www-form-urlencoded"
        }
    })
    if(res.code === 0){
        // 成功了
        abbreImg.src = res.path
        detail.style.display = 'none'
        attre.style.display = 'block'
        submit.className = 'submit'
    }
}

客户端传给服务端格式:

  1. json
  2. form-data
  3. application/x-www.form-urlencoded (xxx=xxx&yyy=yyy就是通过这种格式)
  4. raw 文本格式(text)
  5. 二进制

文件上传进度条

// axios post请求的封装
function postRequest(url,data,config){
    config = config || {};
    return axios.post(`http:....${url}`,data,config).then(res => return res.data)
}

// 文件读取
function fileReader(file){
    return new Promise((resolve,reject)=>{
        let reader = new FileReader() 
        reader.readAsDataURL(file)
        reader.onload = ev => {
            resolve(ev.target.result)
        }
    })
}

//delay 延迟函数
function delay(interval){
    interval = interval || 500 
    return new Promise(resolve=>{
        setTimeout(()=>{
            resolve()
        },interval)
    })
}

let uploadBox = document.querySelector('.uploadBox')
let button = document.querySelector('.button')
let uploadInp = document.querySelector('#uploadInp')

button.onclick = function(){
    uploadInp.click()
}
uploadInp.onchange = async function(){
    let self = this 
    let files = Array.from(self.files)
    if(files.length === 0) return ;

    // 构建一个上传列表
    let uploadList = [] 
    files.forEach((file,index) => {
        uploadList[index] = {
            file,
            base64:null,
            card:null,
        }
    })

    // 搞定base64 && 动态创建Card
    let base64List = await Promise.all(files.map(file => fileReader(file)));
    let frag = document.createDocumentFragment();
    base64List.forEach((base64,index) => {
        let card = document.createElement('div')
        card.className = 'card'
        card.innerHTML = `
            <img src="${base64}"></img>
            <div class="progress">
                <div class="line"></div>
            </div>
            <div class="mark"></div>`
        frag.appendChild(card)
        // 完善上传列表
        uploadList[index].base64 = base64;
        uploadList[index].card = card
    })
    uploadBox.frag.appendChild(frag)

    await delay() 

    // 按照上传列表 批量上传图片 && 监听进度
    uploadList.forEach(async item => {
        let {file,
            base64,
            card} = item;
        let data = {
            chunk:encodeURIComponent(base64),
            filename:file.name,
        }
        let config = {
            haders:{
                "Content-Type":"application/x-www-form-urlencoded"
            },
            // 上传进度监测
            onUploadProgress(ev){
                // ev.loading 已经加载的
                // ev.total 总共的
                let radio = ev.loading / ev.total * 100 + '%'
                card.querySelector('.line').style.width = radio
            }
        }
        let res = await postRequest('/signal2',Qs.stringify(data),config)
        if(res.code === 0){
            // 上传成功
            await delay()
            let progress = card.querySelector('.progress')
            let mark = card.querySelector('.mark')
            card.remove(progress)
            card.remove(mark)
        }
    }) 

}

文件拖拽上传

必须加上contenteditable属性,设置成可编辑状态

<div class="upload" contenteditable></div>
let uploadBox = document.querySelector('.uploadBox')
uploadBox.ondrop = function(ev){
    ev.preventDefault() 
    // 获取拖拽放置到盒子中的文件
    let file = ev.dataTransfer.files[0] 
}