Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ImageUploader使用renderItem自定义渲染时,通过value绑定fileList,上传1个文件之后列表展示两个选项 #6044

Closed
pgdm opened this issue Mar 17, 2023 · 13 comments

Comments

@pgdm
Copy link

pgdm commented Mar 17, 2023

Version of antd-mobile

5.28.1

Description

image

const [fileList, setFileList] = useState([]);

const isVideoType = (fileName = '') => {
    if (['.mp4', '.aov', '.mov'].includes(fileName.slice(-4).toLowerCase())) {
        return true;
    }
    return false;
};

const onFileUpload = async (file) => {
    const formData = new FormData();
    formData.append('uploadfile', file);
    const thumbnailUrl = URL.createObjectURL(file);
    const attachments = [...fileList, { extra: file.name, key: thumbnailUrl, url: thumbnailUrl }];
    setFileList(attachments);
    return {
        extra: file.name,
        key: thumbnailUrl,
        url: thumbnailUrl,
    };
};

// 移除图片
const onFileDelete = (file) => {
    const attachments = fileList.filter((item) => item.url !== file.url);
    setFileList(attachments);
};

 const renderItem = (originNode, file, fileLists) => {
    if (isVideoType(file.extra)) {
        return (
            <div className="video-content" key={file.key}>
                <span
                    className="video-content-delete"
                    onClick={(e) => {
                        Toast.show({
                            content: '删除',
                        });
                        onFileDelete(file);
                    }}
                >
                    <CloseOutline className="video-content-delete-icon" />
                </span>
                <video
                    src={file.url}
                    width={75}
                    height={75}
                    preload="none"
                    onClick={(e) => {
                        e.stopPropagation();
                        Toast.show({
                            content: '暂不支持预览该格式视频',
                        });
                    }}
                />
            </div>
        );
    } else {
        return originNode;
    }
};

return  <ImageUploader
    value={fileList}
    style={{ '--cell-size': '75px' }}
    maxCount={4}
    multiple={false}
    accept="image/jpeg,image/jpg,image/png,video/mp4,video/avi,video/mov"
    beforeUpload={beforeUpload}
    upload={onFileUpload}
    onDelete={onFileDelete}
    renderItem={renderItem}
</>


@pgdm
Copy link
Author

pgdm commented Mar 17, 2023

加上onChange属性,再改变fileList可完美解决,onFileUpload中不需要setFileList

@pgdm pgdm closed this as completed Mar 17, 2023
@xiaoming12138
Copy link

为什么按照你说的,还是会多一个空白的选项

@pgdm
Copy link
Author

pgdm commented Jul 4, 2023

为什么按照你说的,还是会多一个空白的选项

import React, { useState } from 'react';
import { Button, Form, ImageUploader, TextArea, Toast } from 'antd-mobile';
import { CloseOutline } from 'antd-mobile-icons';
import './index.less';

const IndexView = (props) => {
console.log('props', props);
const [form] = Form.useForm();
const { validateFields } = form;
const [loading, setLoading] = useState(false);
const [fileList, setFileList] = useState([]);

const onSubmit = () => {
    validateFields().then((values) => {
        console.log('values', values);
        setLoading(false);
    });
};
const isVideoType = (fileName = '') => {
    if (['.mp4', '.aov', '.mov'].includes(fileName.slice(-4).toLowerCase())) {
        return true;
    }
    return false;
};

const beforeUpload = (file) => {
    console.log('文件类型', file.type);
    const allowType = ['jpg', 'jpeg', 'png', 'mp4', 'avi', 'mov'];
    let fileType = '';
    let isAllowType = false;
    if (file.name) {
        const typeArr = file.name.split('.');
        fileType = typeArr[typeArr.length - 1].toLowerCase();
    }
    if (fileType && file.type && allowType.includes(fileType)) isAllowType = true;
    if (!isAllowType) {
        Toast.show({
            icon: 'fail',
            content: '文件格式不正确,请重新上传',
        });
        return null;
    }
    if (file.size > 1024 * 1000 * 20) {
        Toast.show({
            icon: 'fail',
            content: '图片/视频大小不能大于20M',
        });
        return null;
    }
    return file;
};

// 图片上传
const onFileUpload = async (file) => {
    const formData = new FormData();
    formData.append('uploadfile', file);
    const thumbnailUrl = URL.createObjectURL(file);
    const attachments = [...fileList, { extra: file.name, key: thumbnailUrl, url: thumbnailUrl }];
    console.log('onFileUpload --> attachments:', attachments);
    // setFileList(attachments);
    return {
        extra: file.name,
        key: thumbnailUrl,
        url: thumbnailUrl,
    };
};

// 移除图片
const onFileDelete = (file) => {
    const attachments = fileList.filter((item) => item.url !== file.url);
    setFileList(attachments);
};

const renderItem = (originNode, file) => {
    if (isVideoType(file.extra)) {
        return (
            <div className="video-content" key={file.key}>
                <span
                    className="video-content-delete"
                    onClick={(e) => {
                        Toast.show({
                            content: '删除',
                        });
                        console.log('删除', e, file);
                        onFileDelete(file);
                    }}
                >
                    <CloseOutline className="video-content-delete-icon" />
                </span>
                <video
                    src={file.url}
                    width={75}
                    height={75}
                    preload="none"
                    onClick={(e) => {
                        e.stopPropagation();
                        Toast.show({
                            content: '暂不支持预览该格式视频',
                        });
                    }}
                />
            </div>
        );
    } else {
        return originNode;
    }
};

console.log('文件-->', fileList);

return (
    <div>
        <Form form={form}>
            <Form.Item
                label="上传图片(必填)"
                name="attachments"
                rules={[{ required: true, message: '请上传图片' }]}
            >
                <ImageUploader
                    value={fileList}
                    style={{ '--cell-size': '75px' }}
                    maxCount={4}
                    multiple={false}
                    accept="image/jpeg,image/jpg,image/png,video/mp4,video/avi,video/mov"
                    beforeUpload={beforeUpload}
                    upload={onFileUpload}
                    onDelete={onFileDelete}
                    onChange={setFileList}
                    renderItem={renderItem}
                />
            </Form.Item>
        </Form>
        <div style={{ marginTop: 20, paddingLeft: 20, paddingRight: 20, paddingBottom: 100 }}>
            <Button
                style={{ '--background-color': '#976bff', '--text-color': '#fff' }}
                block
                shape="rounded"
                loading={loading}
                onClick={onSubmit}
            >
                提交
            </Button>
        </div>
    </div>
);

};

export default IndexView;
这是测试的最终版本,这种应该是不会的

@xiaoming12138
Copy link

很玄学,应该是upload的方法要返回一个对象,我之前返回的直接是url字符串

@tuao525
Copy link

tuao525 commented Apr 29, 2024

为什么我的每次上传都会显示两个,一个上传成功的,一个blob类型的临时图片

@pgdm
Copy link
Author

pgdm commented Apr 29, 2024

为什么我的每次上传都会显示两个,一个上传成功的,一个blob类型的临时图片
直接copy代码测试呢?

@tuao525
Copy link

tuao525 commented Apr 29, 2024

也是这样

@tuao525
Copy link

tuao525 commented Apr 29, 2024

我这边需要对图片进行处理,上传成功获得短链接,显示得用短链接获取长链接显示

@pgdm
Copy link
Author

pgdm commented Apr 29, 2024

你先用本地测试,不考虑接口,完全copy代码,出来就是一张

@tuao525
Copy link

tuao525 commented Apr 29, 2024

,完全copy代码,确实显示一张,但加上接口就有问题了

@tuao525
Copy link

tuao525 commented Apr 29, 2024

怎么能不显示那个临时图片呢

@pgdm
Copy link
Author

pgdm commented Apr 29, 2024

那就是你处理上传之后的逻辑有问题了

@tuao525
Copy link

tuao525 commented Apr 29, 2024

export const Upload = (props: any) => {
const { value = [], onChange } = props;

const onFileUpload = async (file: any) => {
const formData = new FormData();
formData.append('file', file || '');
try {
const res = await request(/upload, {
method: 'POST',
data: formData,
});
return {
url: res.data?.url,
};
} catch (error) {
// console.error(error);
}
};
const renderItem = (originNode: any, file: any, fileLists: any) => {
console.log('originNode', originNode)
return {
...originNode,
props: {
...originNode?.props,
url: ${location?.origin}/get?path=${file},
},
};
};

return (
<ImageUploader
{...props}
value={value}
upload={onFileUpload}
renderItem={renderItem}
onChange={(items) => {
onChange(items.map((item: any) => (item?.url ? item?.url : item)));
}}
/>
);
};,麻烦帮我看一下,我这样写,他还是会显示两个图片

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants