上传文件校验文件属性 + 必填的实现方案(Form包裹Upload组件)
Vue + iview 检验图片宽高+必填
<Form ref="formItem" :model="formItem" :rules="ruleValidate" :label-width="80">
<FormItem label="图片" prop="img">
<Upload
v-model="formItem.img"
:action="UPLOAD_IMG_URL"
accept="image/*"
:before-upload="beforeUpload"
:on-success="handleUploadSuccess"
:on-progress="handleProgress"
:on-error="handleUploadError"
:on-remove="handleUploadRemove"
:disabled="!canUpload || formItem.img ? true : false"
>
<Button icon="ios-cloud-upload-outline" ></Button>
</Upload>
</FormItem>
</Form>
<Button type="primary" @click="handleSubmit('formItem')">{{$t('ok')}}</Button>
data(){
return {
formItem: {
img: null,
},
canUpload: true, // 用于控制上传中时,Uplaod失效
ruleValidate: {
img: [
{ required: true, validator: this.validateUpload,trigger: 'blur' },
],
},
}
}
methods: {
// 准备上传
beforeUpload(file) {
const that =this;
return this.checkImageWH(file, 1000, 100,function(){
that.$Message.warning('图片格式要求为1000*100');
});
},
// 封装的一个校验文件宽高的函数
checkImageWH (file, width, height,fn) {
let self = this;
return new Promise(function (resolve, reject) {
let filereader = new FileReader();
filereader.onload = e => {
let src = e.target.result;
const image = new Image();
image.onload = function () {
if (width && this.width !== width || this.height !== height) {
fn()
reject();
} else {
resolve();
}
};
image.onerror = reject;
image.src = src;
};
filereader.readAsDataURL(file);
});
},
// 上传中
handleProgress(event,file){
this.canUpload = false;
},
// 上传失败
handleUploadError () {
this.$Message.error('上传失败');
this.canUpload = true;
},
// 上传成功
handleUploadSuccess (res) {
if (res.status_code != Constants.API_STATUS.OK) {
this.$Message.error(res.extra.details);
return;
}
this.formItem.img = res.data;
this.canUpload = true;
},
// 上传失败
handleUploadRemove () {
this.formItem.img = null;
},
// Form校验:文件必须上传
validateUpload = (rule, value, callback) => {
if (this.formItem.img === null) {
callback(new Error('请选择要上传的图片'));
} else {
callback();
}
};
// 点击确定
handleSubmit (name) {
this.$refs[name].validate((valid) => {
if (valid) {
// 验证成功
}
})
},
}
react + antd
<Form>
<Form.Item label="上传营业执照">
{this.props.form.getFieldDecorator('file', {
rules: [{ required: true, message: '必填' }, {validator: this.validFunction}],
})(
<Upload {...props}
accept=".pdf,.png,.jpg,.jpeg"
beforeUpload={this.beforeUploadfile}
onRemove={this.removeFile}
>
<Button disabled={this.state.file}>
上传(支持格式:pdf、png、jpg、jpeg)
<Icon type="plus" />
</Button>
</Upload>
)}
</Form.Item>
</Form>
<div className="setting-modal-footer" >
<Button type="primary" onClick={this.handleOk}>
完成
</Button>
</div>
class OrganizationModal extends Component {
state = {
file: null, //用于存储上传的文件,控制单文件上传
}
// 点击完成按钮,触发表单校验逻辑
handleOk = () => {
this.props.form.validateFields((err, value) => {
if (!err) {
// 校验成功后,做你想做的事
}
});
};
// 上传前的回调
beforeUploadfile = (file) => {
this.setState({ file });
};
// 移除文件的回调
removeFile = () => {
this.setState({file: null});
};
// 自定义表单校验函数
validFunction = (rule, value, callback) => {
// 此处需要注意:value.file会报错上次上传的文件,但是如果没有上传文件value.fileList为一个长度0的数组
if (value && !value.fileList.length) {
callback("必填");
return;
}
callback(); // 校验通过
}
}
- react+antd(改进) 发现上个方法有缺陷,
<Form.Item label="营业执照">
{getFieldDecorator('license', {
rules: [{ required: true, message: '必填' }],
})(
<Upload
{...props}
fileList={licenseFile}
listType="picture-card"
beforeUpload={this.beforeUpload}
onPreview={this.handlePreview}
onChange={this.licenseChange}
onRemove={this.removeFile}
accept=".png,.jpg,.jpeg">
<Input
placeholder='像素要求不小于800*800'
suffix={<Icon type="plus" style={{color: '#000000', opacity: 0.3}}/>}
disabled
/>
</Upload>
)}
</Form.Item>
// 触发校验
<Button className="next-step" onClick={this.handleNextStep}>下一步</Button>
// 提供图片预览
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}>
<img alt="example" style={{ width: '100%' }} src={previewImage} />
</Modal>
state = {
licenseFile: [], // 绑定Upload已经上传的文件列表(受控)
previewImage: '', // 预览图片地址
previewVisible: false, // 预览状态
};
// 移除回调
removeFile = () => {
// 只是改变了受控组件初始值
this.setState({
licenseFile: [],
});
// 重要:为了检验,一定要操作form属性
this.props.form.setFieldsValue({
license: [],
});
};
// 上传前回调
beforeUpload = (file) => {
// checkImageWH同上
return checkImageWH(file, 800, 800, function() {
message.warning('像素要求小于800*800');
this.removeFile(); // 记得清空~ 单文件上传,如果不符合条件,逻辑上应该没有已上传文件
}.bind(this));
};
// 上传文件改变时的状态
licenseChange = (info) => {
this.setState({
licenseFile: info.fileList.slice(-1)
});
if (info.file.status === 'done') {
message.success(`${info.file.name} 上传成功`);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} 上传失败`);
}
};
// 预览回调
handlePreview = async file => {
if (!file.url && !file.preview) {
file.preview = await this.getBase64(file.originFileObj);
}
this.setState({
previewImage: file.url || file.preview,
previewVisible: true,
});
};
getBase64 = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
};
// 关闭预览弹窗
handleCancel = () => this.setState({ previewVisible: false });
修改antd中Modal的样式
这个Modal的样式是有作用域的,所以官方文档中写明,可以给Modal指定className
。
- 踩坑: scss样式无论怎么修改都不生效,在浏览器中确可以生效
- 正确方式:
// 1. 给Modal指定className
<div className="container">
<Modal visible={true} className="myModal">
<div className="title">机构申请入驻</div>
</Modal>
</div>
在写scss时要注意,modal的className: myModal不能嵌套在container里面,一定要自己是最外层,可以理解为Modal是独立的样式作用范围。
// 2. 写scss
.container {
width: 100%;
height: 810px;
}
.myModal {
.title {
height: 24px;
font-family: PingFangSC;
font-size: 18px;
font-weight: 600;
line-height: 1.33;
color: #000000;
}
}
这样就可以生效啦~想怎么改怎么改
解决元素脱离文档流后事件无法触发
z-index: 1;
提高层级,马上就能点击到了