前端本地图片上传总结

前言: 对于ant-Design或者element-UI这样的组件库,都帮助我们封装了 Upload 组件来帮助我们更好地实现文件上传的功能。这两家组件库都有action参数来帮助我们实现文件的自动上传,但是后端如果并没有提供action上传的地址,只能通过表单统一进行发送的时候我们又应该在怎么办呢?

ant-Design / element-ui 实现本地文件上传


这里仅讨论在antd和element-ui中,当我们并没有action上传地址,后端仅提供一个表单提交接口来完成所有表单项的提交任务的情况。

两种组件库都可以通过组件库自带的beforeUpload方法来获取上传的文件和阻止默认上传行为。对于element-ui可以设置auto-upload="false"来取消默认的上传行为。
以下代码通过onChange事件来获取上传的文件。

// ant-design
const Uploader = () => {
    const [fileList, updateFileList] = useState([]);
    const props = {
        fileList,
        beforeUpload: file => {
            return false;
        },
        onChange: info => {
            console.log(info.fileList);
            // 当 beforeUpload return false时 file.status 为空
            updateFileList(info.fileList.filter(file => !!file.status));
        },
    };
    return (
        <Upload {...props}>
            <Button icon={<UploadOutlined />}>点击上传</Button>
        </Upload>
    );
};

// element-ui
// action如果没有最好写个空值,要不然控制台会报错。这里用before-upload方法也可以
<el-upload
    action=""
    :auto-upload="false"
    :on-change="handleChange"
>
    <el-button size="small" type="primary">选取文件</el-button>
</el-upload>

<script>
export default {
    data() {
        return {
            fileList: []
        };
    },
    methods: {
        handleChange(file, fileList) {
            this.fileList = [...fileList];
        }
    }
}
</script>

HTML + JS 实现本地文件上传


当项目中没有组件库或者组件库的样式并不满足我们的要求时,此时可以通过<input /> 标签进行文件上传。

使用 <input />

  1. type属性,设置为file,使用户可以进行文件操作。

  2. accept属性,通过接收设定文件的MIME类型来指定规定的文件格式。

  3. multiple="multiple",可以设置是否可选多个文件。

<input type="file" name="myfile" />

修改样式


由于input自身的样式大多数不符合我们实际开发中的页面样式,因此我们可以隐藏input标签,通过另一个元素来调整页面上传组件的样式。
示例代码:

<div class="upload-btn" onclick="handleUpload()">点击上传</div>
<input type="file" style="display: none;" onchange="handleChange(this)">

<script>
    let fileInput = document.getElementsByTagName('input')[0];

    function handleUpload() {
        fileInput.click();
    }

    function handleChange(target) {
        console.log(target.files[0])
    }
</script>

如果在使用react或者vue这类前端框架的时候,可以给input标签设置ref去控制input的点击效果。

// react
const Upload = () => {
    const [fileList, updateFileList] = useState([]);
    const ref = useRef(null);

    const handleChange = (e) => {
        console.log(e.target.files);
        updateFileList(e.target.files);
    }
    const handleClick = () => {
        const input = ref.current as HTMLInputElement;
        if (input) {
            input.click();
        }
    }

    return (
        <div onClick={handleClick}>
            <input ref={ref} type="file" style={{display: 'none'}} onChange={handleChange} />
            点击上传
        </div>
    );
}
<!-- vue -->
<div @click="clickUpload">点击上传</div>
<input
    ref="fileInput"
    type="file"
    @change="handleChange"
    style="display: none"
>

<script>
export default {
    data() {
        return {
            fileList: []
        };
    },
    methods: {
        handleChange(e) {
            console.log(e.target.files[0]);
            this.fileList = [...e.target.files[0]];
        },
        clickUpload() {
            this.$refs.fileInput.click();
        }
    }
}
</script>

数据提交


当完成了页面相关数据的采集之后,需要将获取到的数据传递给后端以结束这一系列操作。由于普通的json参数并不能满足传输File文件对象的需求,因此这里使用FormData,通过生成表单数据传递给后端。

let formData = new FormData();
formData.append('file', fileList); // fileList为组件中获取到的File对象
axios.xxx('url', formData); // 发送请求
posted @ 2020-10-28 17:25  程乘成城橙诚  阅读(136)  评论(0)    收藏  举报